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-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 struct wined3d_vertex_declaration *declaration = This->stateBlock->state.vertex_declaration;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
211 data = (BYTE *)buffer;
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory(buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 wined3d_buffer_preload(buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
436 device->useDrawStridedSlow = FALSE;
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 struct wined3d_texture *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->texture_ops->texture_preload(texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 struct wined3d_stateblock *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->resource.width
595 || draw_rect->bottom < target->resource.height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->resource.width
601 || clear_rect->bottom < target->resource.height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
691 context_release(context);
692 WARN("Failed to apply clear state, skipping clear.\n");
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(¤t_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 struct wined3d_resource *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
875 FIXME("Leftover resource %p with type %s (%#x).\n",
876 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
880 if(This->contexts) ERR("Context array not freed!\n");
881 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
882 This->haveHardwareCursor = FALSE;
884 wined3d_decref(This->wined3d);
885 This->wined3d = NULL;
886 HeapFree(GetProcessHeap(), 0, This);
887 TRACE("Freed device %p\n", This);
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
894 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 struct wined3d_buffer *object;
900 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
902 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
905 ERR("Failed to allocate memory\n");
906 return E_OUTOFMEMORY;
909 FIXME("Ignoring access flags (pool)\n");
911 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
912 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
915 WARN("Failed to initialize buffer, hr %#x.\n", hr);
916 HeapFree(GetProcessHeap(), 0, object);
919 object->desc = *desc;
921 TRACE("Created buffer %p.\n", object);
928 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
929 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
932 struct wined3d_buffer *object;
935 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
936 iface, Size, Usage, Pool, parent, parent_ops, buffer);
938 if (Pool == WINED3DPOOL_SCRATCH)
940 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
941 * anyway, SCRATCH vertex buffers aren't usable anywhere
943 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
951 ERR("Out of memory\n");
953 return WINED3DERR_OUTOFVIDEOMEMORY;
956 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
957 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
960 WARN("Failed to initialize buffer, hr %#x.\n", hr);
961 HeapFree(GetProcessHeap(), 0, object);
965 TRACE("Created buffer %p.\n", object);
971 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
972 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
975 struct wined3d_buffer *object;
978 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
979 iface, Length, Usage, Pool, parent, parent_ops, buffer);
981 /* Allocate the storage for the device */
982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
985 ERR("Out of memory\n");
987 return WINED3DERR_OUTOFVIDEOMEMORY;
990 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
991 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
995 WARN("Failed to initialize buffer, hr %#x\n", hr);
996 HeapFree(GetProcessHeap(), 0, object);
1000 TRACE("Created buffer %p.\n", object);
1007 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1008 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1011 struct wined3d_stateblock *object;
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1017 ERR("Failed to allocate stateblock memory.\n");
1018 return E_OUTOFMEMORY;
1021 hr = stateblock_init(object, This, type);
1024 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1029 TRACE("Created stateblock %p.\n", object);
1030 *stateblock = object;
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1036 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1037 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1038 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 IWineD3DSurfaceImpl *object;
1044 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1045 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1046 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1047 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1048 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1050 if (Impl == SURFACE_OPENGL && !This->adapter)
1052 ERR("OpenGL surfaces are not available without OpenGL.\n");
1053 return WINED3DERR_NOTAVAILABLE;
1056 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1059 ERR("Failed to allocate surface memory.\n");
1060 return WINED3DERR_OUTOFVIDEOMEMORY;
1063 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1064 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1067 WARN("Failed to initialize surface, returning %#x.\n", hr);
1068 HeapFree(GetProcessHeap(), 0, object);
1072 TRACE("(%p) : Created surface %p\n", This, object);
1074 *surface = (IWineD3DSurface *)object;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1080 struct wined3d_resource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1082 struct wined3d_rendertarget_view *object;
1084 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1085 iface, resource, parent, rendertarget_view);
1087 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1090 ERR("Failed to allocate memory\n");
1091 return E_OUTOFMEMORY;
1094 wined3d_rendertarget_view_init(object, resource, parent);
1096 TRACE("Created render target view %p.\n", object);
1097 *rendertarget_view = (IWineD3DRendertargetView *)object;
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1103 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1104 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1107 struct wined3d_texture *object;
1110 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1111 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1112 Format, debug_d3dformat(Format), Pool, texture, parent);
1114 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1117 ERR("Out of memory\n");
1119 return WINED3DERR_OUTOFVIDEOMEMORY;
1122 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1125 WARN("Failed to initialize texture, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1133 TRACE("(%p) : Created texture %p\n", This, object);
1138 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1139 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1140 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1143 struct wined3d_texture *object;
1146 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1147 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1149 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1152 ERR("Out of memory\n");
1154 return WINED3DERR_OUTOFVIDEOMEMORY;
1157 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1160 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1161 HeapFree(GetProcessHeap(), 0, object);
1166 TRACE("(%p) : Created volume texture %p.\n", This, object);
1172 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1173 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1174 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DVolumeImpl *object;
1180 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1181 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1183 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1186 ERR("Out of memory\n");
1188 return WINED3DERR_OUTOFVIDEOMEMORY;
1191 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1194 WARN("Failed to initialize volume, returning %#x.\n", hr);
1195 HeapFree(GetProcessHeap(), 0, object);
1199 TRACE("(%p) : Created volume %p.\n", This, object);
1200 *ppVolume = (IWineD3DVolume *)object;
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1206 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1207 const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1210 struct wined3d_texture *object;
1213 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1216 ERR("Out of memory\n");
1218 return WINED3DERR_OUTOFVIDEOMEMORY;
1221 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1224 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1225 HeapFree(GetProcessHeap(), 0, object);
1230 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1236 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1237 WINED3DQUERYTYPE type, struct wined3d_query **query)
1239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1240 struct wined3d_query *object;
1243 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1245 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1248 ERR("Failed to allocate query memory.\n");
1249 return E_OUTOFMEMORY;
1252 hr = query_init(object, This, type);
1255 WARN("Failed to initialize query, hr %#x.\n", hr);
1256 HeapFree(GetProcessHeap(), 0, object);
1260 TRACE("Created query %p.\n", object);
1266 /* Do not call while under the GL lock. */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1268 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1269 void *parent, IWineD3DSwapChain **swapchain)
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1272 IWineD3DSwapChainImpl *object;
1275 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1276 iface, present_parameters, swapchain, parent, surface_type);
1278 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1281 ERR("Failed to allocate swapchain memory.\n");
1282 return E_OUTOFMEMORY;
1285 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1288 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1289 HeapFree(GetProcessHeap(), 0, object);
1293 TRACE("Created swapchain %p.\n", object);
1294 *swapchain = (IWineD3DSwapChain *)object;
1299 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1300 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 TRACE("(%p)\n", This);
1304 return This->NumberOfSwapChains;
1307 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1311 if (iSwapChain < This->NumberOfSwapChains)
1313 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1314 IWineD3DSwapChain_AddRef(*pSwapChain);
1315 TRACE("(%p) returning %p\n", This, *pSwapChain);
1318 TRACE("Swapchain out of range\n");
1320 return WINED3DERR_INVALIDCALL;
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1325 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1326 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 struct wined3d_vertex_declaration *object;
1332 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1333 iface, elements, element_count, parent, parent_ops, declaration);
1335 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1338 ERR("Failed to allocate vertex declaration memory.\n");
1339 return E_OUTOFMEMORY;
1342 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1345 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1346 HeapFree(GetProcessHeap(), 0, object);
1350 TRACE("Created vertex declaration %p.\n", object);
1351 *declaration = object;
1356 struct wined3d_fvf_convert_state
1358 const struct wined3d_gl_info *gl_info;
1359 WINED3DVERTEXELEMENT *elements;
1364 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1365 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1367 WINED3DVERTEXELEMENT *elements = state->elements;
1368 const struct wined3d_format *format;
1369 UINT offset = state->offset;
1370 UINT idx = state->idx;
1372 elements[idx].format = format_id;
1373 elements[idx].input_slot = 0;
1374 elements[idx].offset = offset;
1375 elements[idx].output_slot = 0;
1376 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1377 elements[idx].usage = usage;
1378 elements[idx].usage_idx = usage_idx;
1380 format = wined3d_get_format(state->gl_info, format_id);
1381 state->offset += format->component_count * format->component_size;
1385 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1386 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1388 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1389 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1390 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1391 BOOL has_blend_idx = has_blend &&
1392 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1393 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1394 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1395 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1396 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1397 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1398 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1400 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1401 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1402 struct wined3d_fvf_convert_state state;
1405 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1406 if (has_blend_idx) num_blends--;
1408 /* Compute declaration size */
1409 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1410 has_psize + has_diffuse + has_specular + num_textures;
1412 state.gl_info = gl_info;
1413 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1414 if (!state.elements) return ~0U;
1420 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1421 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1422 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1425 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1428 if (has_blend && (num_blends > 0))
1430 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1431 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 ERR("Unexpected amount of blend values: %u\n", num_blends);
1456 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1457 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1458 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1459 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1460 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1466 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1467 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1468 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1470 for (idx = 0; idx < num_textures; ++idx)
1472 switch ((texcoords >> (idx * 2)) & 0x03)
1474 case WINED3DFVF_TEXTUREFORMAT1:
1475 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1477 case WINED3DFVF_TEXTUREFORMAT2:
1478 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1480 case WINED3DFVF_TEXTUREFORMAT3:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1483 case WINED3DFVF_TEXTUREFORMAT4:
1484 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1489 *ppVertexElements = state.elements;
1493 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1494 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1495 struct wined3d_vertex_declaration **declaration)
1497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1498 WINED3DVERTEXELEMENT *elements;
1502 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1503 iface, fvf, parent, parent_ops, declaration);
1505 size = ConvertFvfToDeclaration(This, fvf, &elements);
1506 if (size == ~0U) return E_OUTOFMEMORY;
1508 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1509 HeapFree(GetProcessHeap(), 0, elements);
1513 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1514 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1515 void *parent, const struct wined3d_parent_ops *parent_ops,
1516 IWineD3DBaseShader **shader)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1519 IWineD3DBaseShaderImpl *object;
1522 if (This->vs_selected_mode == SHADER_NONE)
1523 return WINED3DERR_INVALIDCALL;
1525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1528 ERR("Failed to allocate shader memory.\n");
1529 return E_OUTOFMEMORY;
1532 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1535 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1536 HeapFree(GetProcessHeap(), 0, object);
1540 TRACE("Created vertex shader %p.\n", object);
1541 *shader = (IWineD3DBaseShader *)object;
1546 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1547 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1548 void *parent, const struct wined3d_parent_ops *parent_ops,
1549 IWineD3DBaseShader **shader)
1551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1552 IWineD3DBaseShaderImpl *object;
1555 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1558 ERR("Failed to allocate shader memory.\n");
1559 return E_OUTOFMEMORY;
1562 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1565 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1566 HeapFree(GetProcessHeap(), 0, object);
1570 TRACE("Created geometry shader %p.\n", object);
1571 *shader = (IWineD3DBaseShader *)object;
1576 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1577 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1578 void *parent, const struct wined3d_parent_ops *parent_ops,
1579 IWineD3DBaseShader **shader)
1581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1582 IWineD3DBaseShaderImpl *object;
1585 if (This->ps_selected_mode == SHADER_NONE)
1586 return WINED3DERR_INVALIDCALL;
1588 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1591 ERR("Failed to allocate shader memory.\n");
1592 return E_OUTOFMEMORY;
1595 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1598 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1599 HeapFree(GetProcessHeap(), 0, object);
1603 TRACE("Created pixel shader %p.\n", object);
1604 *shader = (IWineD3DBaseShader *)object;
1609 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1610 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1613 struct wined3d_palette *object;
1616 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1617 iface, flags, entries, palette, parent);
1619 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1622 ERR("Failed to allocate palette memory.\n");
1623 return E_OUTOFMEMORY;
1626 hr = wined3d_palette_init(object, This, flags, entries, parent);
1629 WARN("Failed to initialize palette, hr %#x.\n", hr);
1630 HeapFree(GetProcessHeap(), 0, object);
1634 TRACE("Created palette %p.\n", object);
1640 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1644 HDC dcb = NULL, dcs = NULL;
1645 WINEDDCOLORKEY colorkey;
1647 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1650 GetObjectA(hbm, sizeof(BITMAP), &bm);
1651 dcb = CreateCompatibleDC(NULL);
1653 SelectObject(dcb, hbm);
1657 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1658 * couldn't be loaded
1660 memset(&bm, 0, sizeof(bm));
1665 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1666 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1667 &wined3d_null_parent_ops, &This->logo_surface);
1670 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1675 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1676 if(FAILED(hr)) goto out;
1677 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1678 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1680 colorkey.dwColorSpaceLowValue = 0;
1681 colorkey.dwColorSpaceHighValue = 0;
1682 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1686 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1687 /* Fill the surface with a white color to show that wined3d is there */
1688 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1692 if (dcb) DeleteDC(dcb);
1693 if (hbm) DeleteObject(hbm);
1696 /* Context activation is done by the caller. */
1697 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1699 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1701 /* Under DirectX you can have texture stage operations even if no texture is
1702 bound, whereas opengl will only do texture operations when a valid texture is
1703 bound. We emulate this by creating dummy textures and binding them to each
1704 texture stage, but disable all stages by default. Hence if a stage is enabled
1705 then the default texture will kick in until replaced by a SetTexture call */
1708 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1710 /* The dummy texture does not have client storage backing */
1711 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1712 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1715 for (i = 0; i < gl_info->limits.textures; ++i)
1717 GLubyte white = 255;
1719 /* Make appropriate texture active */
1720 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1721 checkGLcall("glActiveTextureARB");
1723 /* Generate an opengl texture name */
1724 glGenTextures(1, &This->dummyTextureName[i]);
1725 checkGLcall("glGenTextures");
1726 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1728 /* Generate a dummy 2d texture (not using 1d because they cause many
1729 * DRI drivers fall back to sw) */
1730 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1731 checkGLcall("glBindTexture");
1733 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1734 checkGLcall("glTexImage2D");
1737 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1739 /* Reenable because if supported it is enabled by default */
1740 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1741 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1747 /* Context activation is done by the caller. */
1748 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1751 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1752 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1755 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1758 static LONG fullscreen_style(LONG style)
1760 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1761 style |= WS_POPUP | WS_SYSMENU;
1762 style &= ~(WS_CAPTION | WS_THICKFRAME);
1767 static LONG fullscreen_exstyle(LONG exstyle)
1769 /* Filter out window decorations. */
1770 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1775 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1777 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1778 BOOL filter_messages;
1779 LONG style, exstyle;
1781 TRACE("Setting up window %p for fullscreen mode.\n", window);
1783 if (device->style || device->exStyle)
1785 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1786 window, device->style, device->exStyle);
1789 device->style = GetWindowLongW(window, GWL_STYLE);
1790 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1792 style = fullscreen_style(device->style);
1793 exstyle = fullscreen_exstyle(device->exStyle);
1795 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1796 device->style, device->exStyle, style, exstyle);
1798 filter_messages = device->filter_messages;
1799 device->filter_messages = TRUE;
1801 SetWindowLongW(window, GWL_STYLE, style);
1802 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1803 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1805 device->filter_messages = filter_messages;
1808 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1810 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1811 BOOL filter_messages;
1812 LONG style, exstyle;
1814 if (!device->style && !device->exStyle) return;
1816 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1817 window, device->style, device->exStyle);
1819 style = GetWindowLongW(window, GWL_STYLE);
1820 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1822 filter_messages = device->filter_messages;
1823 device->filter_messages = TRUE;
1825 /* Only restore the style if the application didn't modify it during the
1826 * fullscreen phase. Some applications change it before calling Reset()
1827 * when switching between windowed and fullscreen modes (HL2), some
1828 * depend on the original style (Eve Online). */
1829 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1831 SetWindowLongW(window, GWL_STYLE, device->style);
1832 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1834 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1836 device->filter_messages = filter_messages;
1838 /* Delete the old values. */
1840 device->exStyle = 0;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1845 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1847 TRACE("iface %p, window %p.\n", iface, window);
1849 if (!wined3d_register_window(window, device))
1851 ERR("Failed to register window %p.\n", window);
1855 device->focus_window = window;
1856 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1861 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1863 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1865 TRACE("iface %p.\n", iface);
1867 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1868 device->focus_window = NULL;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1872 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1875 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1876 IWineD3DSwapChainImpl *swapchain = NULL;
1877 struct wined3d_context *context;
1882 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1884 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1885 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1887 TRACE("(%p) : Creating stateblock\n", This);
1888 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1891 WARN("Failed to create stateblock\n");
1894 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1895 This->updateStateBlock = This->stateBlock;
1896 wined3d_stateblock_incref(This->updateStateBlock);
1898 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1899 sizeof(*This->render_targets) * gl_info->limits.buffers);
1901 This->NumberOfPalettes = 1;
1902 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1903 if (!This->palettes || !This->render_targets)
1905 ERR("Out of memory!\n");
1909 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1910 if(!This->palettes[0]) {
1911 ERR("Out of memory!\n");
1915 for (i = 0; i < 256; ++i) {
1916 This->palettes[0][i].peRed = 0xFF;
1917 This->palettes[0][i].peGreen = 0xFF;
1918 This->palettes[0][i].peBlue = 0xFF;
1919 This->palettes[0][i].peFlags = 0xFF;
1921 This->currentPalette = 0;
1923 /* Initialize the texture unit mapping to a 1:1 mapping */
1924 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1926 if (state < gl_info->limits.fragment_samplers)
1928 This->texUnitMap[state] = state;
1929 This->rev_tex_unit_map[state] = state;
1931 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1932 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1936 /* Setup the implicit swapchain. This also initializes a context. */
1937 TRACE("Creating implicit swapchain\n");
1938 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1939 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1942 WARN("Failed to create implicit swapchain\n");
1946 This->NumberOfSwapChains = 1;
1947 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1948 if (!This->swapchains)
1950 ERR("Out of memory!\n");
1953 This->swapchains[0] = swapchain;
1955 if (swapchain->back_buffers && swapchain->back_buffers[0])
1957 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1958 This->render_targets[0] = swapchain->back_buffers[0];
1962 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1963 This->render_targets[0] = swapchain->front_buffer;
1965 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1967 /* Depth Stencil support */
1968 This->depth_stencil = This->auto_depth_stencil;
1969 if (This->depth_stencil)
1970 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1972 hr = This->shader_backend->shader_alloc_private(This);
1974 TRACE("Shader private data couldn't be allocated\n");
1977 hr = This->frag_pipe->alloc_private(This);
1979 TRACE("Fragment pipeline private data couldn't be allocated\n");
1982 hr = This->blitter->alloc_private(This);
1984 TRACE("Blitter private data couldn't be allocated\n");
1988 /* Set up some starting GL setup */
1990 /* Setup all the devices defaults */
1991 stateblock_init_default_state(This->stateBlock);
1993 context = context_acquire(This, swapchain->front_buffer);
1995 create_dummy_textures(This);
1999 /* Initialize the current view state */
2000 This->view_ident = 1;
2001 This->contexts[0]->last_was_rhw = 0;
2002 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2003 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2005 switch(wined3d_settings.offscreen_rendering_mode) {
2007 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2010 case ORM_BACKBUFFER:
2012 if (context_get_current()->aux_buffers > 0)
2014 TRACE("Using auxilliary buffer for offscreen rendering\n");
2015 This->offscreenBuffer = GL_AUX0;
2017 TRACE("Using back buffer for offscreen rendering\n");
2018 This->offscreenBuffer = GL_BACK;
2023 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2026 context_release(context);
2028 /* Clear the screen */
2029 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2030 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2033 This->d3d_initialized = TRUE;
2035 if(wined3d_settings.logo) {
2036 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2038 This->highest_dirty_ps_const = 0;
2039 This->highest_dirty_vs_const = 0;
2043 HeapFree(GetProcessHeap(), 0, This->render_targets);
2044 HeapFree(GetProcessHeap(), 0, This->swapchains);
2045 This->NumberOfSwapChains = 0;
2046 if(This->palettes) {
2047 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2048 HeapFree(GetProcessHeap(), 0, This->palettes);
2050 This->NumberOfPalettes = 0;
2052 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2054 if (This->stateBlock)
2056 wined3d_stateblock_decref(This->stateBlock);
2057 This->stateBlock = NULL;
2059 if (This->blit_priv) {
2060 This->blitter->free_private(This);
2062 if (This->fragment_priv) {
2063 This->frag_pipe->free_private(This);
2065 if (This->shader_priv) {
2066 This->shader_backend->shader_free_private(This);
2071 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2072 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 IWineD3DSwapChainImpl *swapchain = NULL;
2078 /* Setup the implicit swapchain */
2079 TRACE("Creating implicit swapchain\n");
2080 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2081 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 WARN("Failed to create implicit swapchain\n");
2088 This->NumberOfSwapChains = 1;
2089 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2090 if (!This->swapchains)
2092 ERR("Out of memory!\n");
2095 This->swapchains[0] = swapchain;
2099 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2103 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2105 TRACE("Unloading resource %p.\n", resource);
2107 resource->resource_ops->resource_unload(resource);
2112 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2113 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 const struct wined3d_gl_info *gl_info;
2117 struct IWineD3DSurfaceImpl *surface;
2118 struct wined3d_context *context;
2121 TRACE("(%p)\n", This);
2123 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2125 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2126 * it was created. Thus make sure a context is active for the glDelete* calls
2128 context = context_acquire(This, NULL);
2129 gl_info = context->gl_info;
2131 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2133 /* Unload resources */
2134 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2136 TRACE("Deleting high order patches\n");
2137 for(i = 0; i < PATCHMAP_SIZE; i++) {
2138 struct list *e1, *e2;
2139 struct WineD3DRectPatch *patch;
2140 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2141 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2142 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2146 /* Delete the mouse cursor texture */
2147 if(This->cursorTexture) {
2149 glDeleteTextures(1, &This->cursorTexture);
2151 This->cursorTexture = 0;
2154 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2155 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2157 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2158 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2161 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2162 * private data, it might contain opengl pointers
2164 if(This->depth_blt_texture) {
2166 glDeleteTextures(1, &This->depth_blt_texture);
2168 This->depth_blt_texture = 0;
2170 if (This->depth_blt_rb) {
2172 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2174 This->depth_blt_rb = 0;
2175 This->depth_blt_rb_w = 0;
2176 This->depth_blt_rb_h = 0;
2179 /* Release the update stateblock */
2180 if (wined3d_stateblock_decref(This->updateStateBlock))
2182 if (This->updateStateBlock != This->stateBlock)
2183 FIXME("Something's still holding the update stateblock.\n");
2185 This->updateStateBlock = NULL;
2188 struct wined3d_stateblock *stateblock = This->stateBlock;
2189 This->stateBlock = NULL;
2191 /* Release the stateblock */
2192 if (wined3d_stateblock_decref(stateblock))
2193 FIXME("Something's still holding the stateblock.\n");
2196 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2197 This->blitter->free_private(This);
2198 This->frag_pipe->free_private(This);
2199 This->shader_backend->shader_free_private(This);
2201 /* Release the buffers (with sanity checks)*/
2202 if (This->onscreen_depth_stencil)
2204 surface = This->onscreen_depth_stencil;
2205 This->onscreen_depth_stencil = NULL;
2206 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2209 if (This->depth_stencil)
2211 surface = This->depth_stencil;
2213 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2215 This->depth_stencil = NULL;
2216 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2217 && surface != This->auto_depth_stencil)
2219 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2223 if (This->auto_depth_stencil)
2225 surface = This->auto_depth_stencil;
2226 This->auto_depth_stencil = NULL;
2227 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2229 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2233 for (i = 1; i < gl_info->limits.buffers; ++i)
2235 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2238 surface = This->render_targets[0];
2239 TRACE("Setting rendertarget 0 to NULL\n");
2240 This->render_targets[0] = NULL;
2241 TRACE("Releasing the render target at %p\n", surface);
2242 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2244 context_release(context);
2246 for (i = 0; i < This->NumberOfSwapChains; ++i)
2248 TRACE("Releasing the implicit swapchain %u.\n", i);
2249 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2251 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2255 HeapFree(GetProcessHeap(), 0, This->swapchains);
2256 This->swapchains = NULL;
2257 This->NumberOfSwapChains = 0;
2259 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2260 HeapFree(GetProcessHeap(), 0, This->palettes);
2261 This->palettes = NULL;
2262 This->NumberOfPalettes = 0;
2264 HeapFree(GetProcessHeap(), 0, This->render_targets);
2265 This->render_targets = NULL;
2267 This->d3d_initialized = FALSE;
2272 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2276 for (i = 0; i < This->NumberOfSwapChains; ++i)
2278 TRACE("Releasing the implicit swapchain %u.\n", i);
2279 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2281 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2285 HeapFree(GetProcessHeap(), 0, This->swapchains);
2286 This->swapchains = NULL;
2287 This->NumberOfSwapChains = 0;
2291 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2292 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2293 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2295 * There is no way to deactivate thread safety once it is enabled.
2297 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 /*For now just store the flag(needed in case of ddraw) */
2301 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2305 const WINED3DDISPLAYMODE* pMode) {
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2312 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2314 /* Resize the screen even without a window:
2315 * The app could have unset it with SetCooperativeLevel, but not called
2316 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2317 * but we don't have any hwnd
2320 memset(&devmode, 0, sizeof(devmode));
2321 devmode.dmSize = sizeof(devmode);
2322 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2323 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2324 devmode.dmPelsWidth = pMode->Width;
2325 devmode.dmPelsHeight = pMode->Height;
2327 devmode.dmDisplayFrequency = pMode->RefreshRate;
2328 if (pMode->RefreshRate)
2329 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2331 /* Only change the mode if necessary */
2332 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2333 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2336 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2337 if (ret != DISP_CHANGE_SUCCESSFUL)
2339 if (devmode.dmDisplayFrequency)
2341 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2342 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2343 devmode.dmDisplayFrequency = 0;
2344 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2346 if(ret != DISP_CHANGE_SUCCESSFUL) {
2347 return WINED3DERR_NOTAVAILABLE;
2351 /* Store the new values */
2352 This->ddraw_width = pMode->Width;
2353 This->ddraw_height = pMode->Height;
2354 This->ddraw_format = pMode->Format;
2356 /* And finally clip mouse to our screen */
2357 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2358 ClipCursor(&clip_rc);
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2365 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2367 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2369 *wined3d = device->wined3d;
2370 wined3d_incref(*wined3d);
2372 TRACE("Returning %p.\n", *wined3d);
2377 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2381 (This->adapter->TextureRam/(1024*1024)),
2382 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2383 /* return simulated texture memory left */
2384 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2388 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2392 struct wined3d_buffer *prev_buffer;
2394 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2395 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2397 if (StreamNumber >= MAX_STREAMS) {
2398 WARN("Stream out of range %d\n", StreamNumber);
2399 return WINED3DERR_INVALIDCALL;
2400 } else if(OffsetInBytes & 0x3) {
2401 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2402 return WINED3DERR_INVALIDCALL;
2405 stream = &This->updateStateBlock->state.streams[StreamNumber];
2406 prev_buffer = stream->buffer;
2408 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2410 if (prev_buffer == buffer
2411 && stream->stride == Stride
2412 && stream->offset == OffsetInBytes)
2414 TRACE("Application is setting the old values over, nothing to do\n");
2418 stream->buffer = buffer;
2421 stream->stride = Stride;
2422 stream->offset = OffsetInBytes;
2425 /* Handle recording of state blocks */
2426 if (This->isRecordingState) {
2427 TRACE("Recording... not performing anything\n");
2429 wined3d_buffer_incref(buffer);
2431 wined3d_buffer_decref(prev_buffer);
2437 InterlockedIncrement(&buffer->bind_count);
2438 wined3d_buffer_incref(buffer);
2442 InterlockedDecrement(&prev_buffer->bind_count);
2443 wined3d_buffer_decref(prev_buffer);
2446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2452 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 struct wined3d_stream_state *stream;
2457 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2458 iface, StreamNumber, buffer, pOffset, pStride);
2460 if (StreamNumber >= MAX_STREAMS)
2462 WARN("Stream out of range %d\n", StreamNumber);
2463 return WINED3DERR_INVALIDCALL;
2466 stream = &This->stateBlock->state.streams[StreamNumber];
2467 *buffer = stream->buffer;
2468 *pStride = stream->stride;
2469 if (pOffset) *pOffset = stream->offset;
2472 wined3d_buffer_incref(*buffer);
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 struct wined3d_stream_state *stream;
2480 UINT old_flags, oldFreq;
2482 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2484 /* Verify input at least in d3d9 this is invalid. */
2485 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2487 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2488 return WINED3DERR_INVALIDCALL;
2490 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2492 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2493 return WINED3DERR_INVALIDCALL;
2497 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2498 return WINED3DERR_INVALIDCALL;
2501 stream = &This->updateStateBlock->state.streams[StreamNumber];
2502 old_flags = stream->flags;
2503 oldFreq = stream->frequency;
2505 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2506 stream->frequency = Divider & 0x7FFFFF;
2508 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2510 if (stream->frequency != oldFreq || stream->flags != old_flags)
2511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2516 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 struct wined3d_stream_state *stream;
2520 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2522 stream = &This->updateStateBlock->state.streams[StreamNumber];
2523 *Divider = stream->flags | stream->frequency;
2525 TRACE("Returning %#x.\n", *Divider);
2531 * Get / Set & Multiply Transform
2533 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 /* Most of this routine, comments included copied from ddraw tree initially: */
2537 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2539 /* Handle recording of state blocks */
2540 if (This->isRecordingState) {
2541 TRACE("Recording... not performing anything\n");
2542 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2543 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2548 * If the new matrix is the same as the current one,
2549 * we cut off any further processing. this seems to be a reasonable
2550 * optimization because as was noticed, some apps (warcraft3 for example)
2551 * tend towards setting the same matrix repeatedly for some reason.
2553 * From here on we assume that the new matrix is different, wherever it matters.
2555 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2557 TRACE("The app is setting the same matrix over again\n");
2562 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2566 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2567 where ViewMat = Camera space, WorldMat = world space.
2569 In OpenGL, camera and world space is combined into GL_MODELVIEW
2570 matrix. The Projection matrix stay projection matrix.
2573 /* Capture the times we can just ignore the change for now */
2574 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2575 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2576 /* Handled by the state manager */
2579 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2587 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2589 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2591 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2593 *matrix = device->stateBlock->state.transforms[state];
2598 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2599 const WINED3DMATRIX *mat = NULL;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2610 if (State <= HIGHEST_TRANSFORMSTATE)
2612 mat = &This->updateStateBlock->state.transforms[State];
2616 FIXME("Unhandled transform state!!\n");
2619 multiply_matrix(&temp, mat, pMatrix);
2621 /* Apply change via set transform - will reapply to eg. lights this way */
2622 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2628 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2629 you can reference any indexes you want as long as that number max are enabled at any
2630 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2631 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2632 but when recording, just build a chain pretty much of commands to be replayed. */
2634 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2636 struct wined3d_light_info *object = NULL;
2637 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2643 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2647 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2648 return WINED3DERR_INVALIDCALL;
2651 switch(pLight->Type) {
2652 case WINED3DLIGHT_POINT:
2653 case WINED3DLIGHT_SPOT:
2654 case WINED3DLIGHT_PARALLELPOINT:
2655 case WINED3DLIGHT_GLSPOT:
2656 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2659 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2661 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2666 case WINED3DLIGHT_DIRECTIONAL:
2667 /* Ignores attenuation */
2671 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2672 return WINED3DERR_INVALIDCALL;
2675 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2677 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2678 if(object->OriginalIndex == Index) break;
2683 TRACE("Adding new light\n");
2684 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2686 ERR("Out of memory error when allocating a light\n");
2687 return E_OUTOFMEMORY;
2689 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2690 object->glIndex = -1;
2691 object->OriginalIndex = Index;
2694 /* Initialize the object */
2695 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2696 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2697 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2698 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2699 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2700 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2701 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2703 /* Save away the information */
2704 object->OriginalParms = *pLight;
2706 switch (pLight->Type) {
2707 case WINED3DLIGHT_POINT:
2709 object->lightPosn[0] = pLight->Position.x;
2710 object->lightPosn[1] = pLight->Position.y;
2711 object->lightPosn[2] = pLight->Position.z;
2712 object->lightPosn[3] = 1.0f;
2713 object->cutoff = 180.0f;
2717 case WINED3DLIGHT_DIRECTIONAL:
2719 object->lightPosn[0] = -pLight->Direction.x;
2720 object->lightPosn[1] = -pLight->Direction.y;
2721 object->lightPosn[2] = -pLight->Direction.z;
2722 object->lightPosn[3] = 0.0f;
2723 object->exponent = 0.0f;
2724 object->cutoff = 180.0f;
2727 case WINED3DLIGHT_SPOT:
2729 object->lightPosn[0] = pLight->Position.x;
2730 object->lightPosn[1] = pLight->Position.y;
2731 object->lightPosn[2] = pLight->Position.z;
2732 object->lightPosn[3] = 1.0f;
2735 object->lightDirn[0] = pLight->Direction.x;
2736 object->lightDirn[1] = pLight->Direction.y;
2737 object->lightDirn[2] = pLight->Direction.z;
2738 object->lightDirn[3] = 1.0f;
2741 * opengl-ish and d3d-ish spot lights use too different models for the
2742 * light "intensity" as a function of the angle towards the main light direction,
2743 * so we only can approximate very roughly.
2744 * however spot lights are rather rarely used in games (if ever used at all).
2745 * furthermore if still used, probably nobody pays attention to such details.
2747 if (!pLight->Falloff)
2749 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2750 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2751 * will always be 1.0 for both of them, and we don't have to care for the
2752 * rest of the rather complex calculation
2754 object->exponent = 0.0f;
2756 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2757 if (rho < 0.0001f) rho = 0.0001f;
2758 object->exponent = -0.3f/logf(cosf(rho/2));
2760 if (object->exponent > 128.0f)
2762 object->exponent = 128.0f;
2764 object->cutoff = (float) (pLight->Phi*90/M_PI);
2770 FIXME("Unrecognized light type %d\n", pLight->Type);
2773 /* Update the live definitions if the light is currently assigned a glIndex */
2774 if (object->glIndex != -1 && !This->isRecordingState) {
2775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2780 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2782 struct wined3d_light_info *lightInfo = NULL;
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2786 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2788 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2790 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2791 if(lightInfo->OriginalIndex == Index) break;
2797 TRACE("Light information requested but light not defined\n");
2798 return WINED3DERR_INVALIDCALL;
2801 *pLight = lightInfo->OriginalParms;
2806 * Get / Set Light Enable
2807 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2811 struct wined3d_light_info *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2815 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2817 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2819 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2820 if(lightInfo->OriginalIndex == Index) break;
2823 TRACE("Found light: %p\n", lightInfo);
2825 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2828 TRACE("Light enabled requested but light not defined, so defining one!\n");
2829 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2831 /* Search for it again! Should be fairly quick as near head of list */
2832 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2834 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2835 if(lightInfo->OriginalIndex == Index) break;
2840 FIXME("Adding default lights has failed dismally\n");
2841 return WINED3DERR_INVALIDCALL;
2846 if(lightInfo->glIndex != -1) {
2847 if(!This->isRecordingState) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2851 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2852 lightInfo->glIndex = -1;
2854 TRACE("Light already disabled, nothing to do\n");
2856 lightInfo->enabled = FALSE;
2858 lightInfo->enabled = TRUE;
2859 if (lightInfo->glIndex != -1) {
2861 TRACE("Nothing to do as light was enabled\n");
2864 /* Find a free gl light */
2865 for (i = 0; i < This->maxConcurrentLights; ++i)
2867 if (!This->updateStateBlock->state.lights[i])
2869 This->updateStateBlock->state.lights[i] = lightInfo;
2870 lightInfo->glIndex = i;
2874 if(lightInfo->glIndex == -1) {
2875 /* Our tests show that Windows returns D3D_OK in this situation, even with
2876 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2877 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2878 * as well for those lights.
2880 * TODO: Test how this affects rendering
2882 WARN("Too many concurrently active lights\n");
2886 /* i == lightInfo->glIndex */
2887 if(!This->isRecordingState) {
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2896 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2898 struct wined3d_light_info *lightInfo = NULL;
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2902 TRACE("(%p) : for idx(%d)\n", This, Index);
2904 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2906 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2907 if(lightInfo->OriginalIndex == Index) break;
2913 TRACE("Light enabled state requested but light not defined\n");
2914 return WINED3DERR_INVALIDCALL;
2916 /* true is 128 according to SetLightEnable */
2917 *pEnable = lightInfo->enabled ? 128 : 0;
2922 * Get / Set Clip Planes
2924 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2928 /* Validate Index */
2929 if (Index >= This->adapter->gl_info.limits.clipplanes)
2931 TRACE("Application has requested clipplane this device doesn't support\n");
2932 return WINED3DERR_INVALIDCALL;
2935 This->updateStateBlock->changed.clipplane |= 1 << Index;
2937 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2938 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2939 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2940 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2942 TRACE("Application is setting old values over, nothing to do\n");
2946 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2947 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2948 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2949 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2951 /* Handle recording of state blocks */
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2962 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p) : for idx %d\n", This, Index);
2966 /* Validate Index */
2967 if (Index >= This->adapter->gl_info.limits.clipplanes)
2969 TRACE("Application has requested clipplane this device doesn't support\n");
2970 return WINED3DERR_INVALIDCALL;
2973 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2974 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2975 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2976 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2981 * Get / Set Clip Plane Status
2982 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2984 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 FIXME("(%p) : stub\n", This);
2989 return WINED3DERR_INVALIDCALL;
2991 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2992 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 FIXME("(%p) : stub\n", This);
3001 return WINED3DERR_INVALIDCALL;
3003 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3004 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3009 * Get / Set Material
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 This->updateStateBlock->changed.material = TRUE;
3015 This->updateStateBlock->state.material = *pMaterial;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 *pMaterial = This->updateStateBlock->state.material;
3030 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3031 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3032 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3033 pMaterial->Ambient.b, pMaterial->Ambient.a);
3034 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3035 pMaterial->Specular.b, pMaterial->Specular.a);
3036 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3037 pMaterial->Emissive.b, pMaterial->Emissive.a);
3038 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3047 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 struct wined3d_buffer *prev_buffer;
3052 TRACE("iface %p, buffer %p, format %s.\n",
3053 iface, buffer, debug_d3dformat(fmt));
3055 prev_buffer = This->updateStateBlock->state.index_buffer;
3057 This->updateStateBlock->changed.indices = TRUE;
3058 This->updateStateBlock->state.index_buffer = buffer;
3059 This->updateStateBlock->state.index_format = fmt;
3061 /* Handle recording of state blocks */
3062 if (This->isRecordingState) {
3063 TRACE("Recording... not performing anything\n");
3065 wined3d_buffer_incref(buffer);
3067 wined3d_buffer_decref(prev_buffer);
3071 if (prev_buffer != buffer)
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3076 InterlockedIncrement(&buffer->bind_count);
3077 wined3d_buffer_incref(buffer);
3081 InterlockedDecrement(&prev_buffer->bind_count);
3082 wined3d_buffer_decref(prev_buffer);
3089 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("iface %p, buffer %p.\n", iface, buffer);
3095 *buffer = This->stateBlock->state.index_buffer;
3098 wined3d_buffer_incref(*buffer);
3100 TRACE("Returning %p.\n", *buffer);
3105 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("(%p)->(%d)\n", This, BaseIndex);
3110 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3112 TRACE("Application is setting the old value over, nothing to do\n");
3116 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3122 /* The base vertex index affects the stream sources */
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p) : base_index %p\n", This, base_index);
3131 *base_index = This->stateBlock->state.base_vertex_index;
3133 TRACE("Returning %u\n", *base_index);
3139 * Get / Set Viewports
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 TRACE("(%p)\n", This);
3145 This->updateStateBlock->changed.viewport = TRUE;
3146 This->updateStateBlock->state.viewport = *pViewport;
3148 /* Handle recording of state blocks */
3149 if (This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3154 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3155 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3162 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 TRACE("(%p)\n", This);
3165 *pViewport = This->stateBlock->state.viewport;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3170 WINED3DRENDERSTATETYPE State, DWORD Value)
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 DWORD oldValue = This->stateBlock->state.render_states[State];
3175 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3177 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3178 This->updateStateBlock->state.render_states[State] = Value;
3180 /* Handle recording of state blocks */
3181 if (This->isRecordingState) {
3182 TRACE("Recording... not performing anything\n");
3186 /* Compared here and not before the assignment to allow proper stateblock recording */
3187 if(Value == oldValue) {
3188 TRACE("Application is setting the old value over, nothing to do\n");
3190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3196 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3197 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3203 *pValue = This->stateBlock->state.render_states[State];
3208 * Get / Set Sampler States
3209 * TODO: Verify against dx9 definitions
3212 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3216 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3217 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3219 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3220 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3223 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3225 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3226 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3229 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3230 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3231 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3233 /* Handle recording of state blocks */
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3239 if(oldValue == Value) {
3240 TRACE("Application is setting the old value over, nothing to do\n");
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3253 This, Sampler, debug_d3dsamplerstate(Type), Type);
3255 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3256 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3259 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3261 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3262 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3264 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3265 TRACE("(%p) : Returning %#x\n", This, *Value);
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 This->updateStateBlock->changed.scissorRect = TRUE;
3274 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3276 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3279 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3281 if(This->isRecordingState) {
3282 TRACE("Recording... not performing anything\n");
3286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 *pRect = This->updateStateBlock->state.scissor_rect;
3295 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3299 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3300 struct wined3d_vertex_declaration *pDecl)
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3303 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3305 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3308 wined3d_vertex_declaration_incref(pDecl);
3310 wined3d_vertex_declaration_decref(oldDecl);
3312 This->updateStateBlock->state.vertex_declaration = pDecl;
3313 This->updateStateBlock->changed.vertexDecl = TRUE;
3315 if (This->isRecordingState) {
3316 TRACE("Recording... not performing anything\n");
3318 } else if(pDecl == oldDecl) {
3319 /* Checked after the assignment to allow proper stateblock recording */
3320 TRACE("Application is setting the old declaration over, nothing to do\n");
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3328 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3329 struct wined3d_vertex_declaration **ppDecl)
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3335 *ppDecl = This->stateBlock->state.vertex_declaration;
3337 wined3d_vertex_declaration_incref(*ppDecl);
3342 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DBaseShader *shader)
3344 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3345 IWineD3DBaseShader *prev = (IWineD3DBaseShader *)device->updateStateBlock->state.vertex_shader;
3347 device->updateStateBlock->state.vertex_shader = (IWineD3DBaseShaderImpl *)shader;
3348 device->updateStateBlock->changed.vertexShader = TRUE;
3350 if (device->isRecordingState)
3353 wined3d_shader_incref(shader);
3355 wined3d_shader_decref(prev);
3356 TRACE("Recording... not performing anything.\n");
3359 else if(prev == shader)
3361 /* Checked here to allow proper stateblock recording */
3362 TRACE("App is setting the old shader over, nothing to do.\n");
3366 TRACE("(%p) : setting shader(%p)\n", device, shader);
3368 wined3d_shader_incref(shader);
3370 wined3d_shader_decref(prev);
3372 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
3377 static IWineD3DBaseShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3379 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3380 IWineD3DBaseShader *shader;
3382 TRACE("iface %p.\n", iface);
3384 shader = (IWineD3DBaseShader *)device->stateBlock->state.vertex_shader;
3386 wined3d_shader_incref(shader);
3388 TRACE("Returning %p.\n", shader);
3392 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3393 IWineD3DDevice *iface,
3395 CONST BOOL *srcData,
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3401 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3402 iface, srcData, start, count);
3404 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3406 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3407 for (i = 0; i < cnt; i++)
3408 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3410 for (i = start; i < cnt + start; ++i) {
3411 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3414 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3419 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3420 IWineD3DDevice *iface,
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 int cnt = min(count, MAX_CONST_B - start);
3428 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3429 iface, dstData, start, count);
3431 if (!dstData || cnt < 0)
3432 return WINED3DERR_INVALIDCALL;
3434 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3438 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3439 IWineD3DDevice *iface,
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3447 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3448 iface, srcData, start, count);
3450 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3452 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3453 for (i = 0; i < cnt; i++)
3454 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3455 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3457 for (i = start; i < cnt + start; ++i) {
3458 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3461 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3466 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3467 IWineD3DDevice *iface,
3472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3473 int cnt = min(count, MAX_CONST_I - start);
3475 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3476 iface, dstData, start, count);
3478 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3479 return WINED3DERR_INVALIDCALL;
3481 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3485 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3486 IWineD3DDevice *iface,
3488 CONST float *srcData,
3491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3495 iface, srcData, start, count);
3497 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3498 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3499 return WINED3DERR_INVALIDCALL;
3501 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3503 for (i = 0; i < count; i++)
3504 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3505 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3508 if (!This->isRecordingState)
3510 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3514 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3515 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3520 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3521 IWineD3DDevice *iface,
3526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3527 int cnt = min(count, This->d3d_vshader_constantF - start);
3529 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3530 iface, dstData, start, count);
3532 if (!dstData || cnt < 0)
3533 return WINED3DERR_INVALIDCALL;
3535 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3539 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3541 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3547 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3549 DWORD i = This->rev_tex_unit_map[unit];
3550 DWORD j = This->texUnitMap[stage];
3552 This->texUnitMap[stage] = unit;
3553 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3555 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3558 This->rev_tex_unit_map[unit] = stage;
3559 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3561 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3565 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3568 This->fixed_function_usage_map = 0;
3569 for (i = 0; i < MAX_TEXTURES; ++i)
3571 const struct wined3d_state *state = &This->stateBlock->state;
3572 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3573 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3574 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3575 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3576 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3577 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3578 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3579 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3581 if (color_op == WINED3DTOP_DISABLE) {
3582 /* Not used, and disable higher stages */
3586 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3587 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3588 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3589 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3590 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3591 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3592 This->fixed_function_usage_map |= (1 << i);
3595 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3596 This->fixed_function_usage_map |= (1 << (i + 1));
3601 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3603 unsigned int i, tex;
3606 device_update_fixed_function_usage_map(This);
3607 ffu_map = This->fixed_function_usage_map;
3609 if (This->max_ffp_textures == gl_info->limits.texture_stages
3610 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3612 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3614 if (!(ffu_map & 1)) continue;
3616 if (This->texUnitMap[i] != i) {
3617 device_map_stage(This, i, i);
3618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3619 markTextureStagesDirty(This, i);
3625 /* Now work out the mapping */
3627 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3629 if (!(ffu_map & 1)) continue;
3631 if (This->texUnitMap[i] != tex) {
3632 device_map_stage(This, i, tex);
3633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3634 markTextureStagesDirty(This, i);
3641 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3643 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3644 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3647 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3648 if (sampler_type[i] && This->texUnitMap[i] != i)
3650 device_map_stage(This, i, i);
3651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3652 if (i < gl_info->limits.texture_stages)
3654 markTextureStagesDirty(This, i);
3660 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3661 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3663 DWORD current_mapping = This->rev_tex_unit_map[unit];
3665 /* Not currently used */
3666 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3668 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3669 /* Used by a fragment sampler */
3671 if (!pshader_sampler_tokens) {
3672 /* No pixel shader, check fixed function */
3673 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3676 /* Pixel shader, check the shader's sampler map */
3677 return !pshader_sampler_tokens[current_mapping];
3680 /* Used by a vertex sampler */
3681 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3684 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3686 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3687 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3688 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3689 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3694 IWineD3DBaseShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3696 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3697 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3698 pshader_sampler_type = pshader->reg_maps.sampler_type;
3701 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3702 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3703 if (vshader_sampler_type[i])
3705 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3707 /* Already mapped somewhere */
3711 while (start >= 0) {
3712 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3714 device_map_stage(This, vsampler_idx, start);
3715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3727 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3729 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3730 const struct wined3d_state *state = &This->stateBlock->state;
3731 BOOL vs = use_vs(state);
3732 BOOL ps = use_ps(state);
3735 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3736 * that would be really messy and require shader recompilation
3737 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3738 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3740 if (ps) device_map_psamplers(This, gl_info);
3741 else device_map_fixed_function_samplers(This, gl_info);
3743 if (vs) device_map_vsamplers(This, ps, gl_info);
3746 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DBaseShader *shader)
3748 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3749 IWineD3DBaseShader *prev = (IWineD3DBaseShader *)device->updateStateBlock->state.pixel_shader;
3751 device->updateStateBlock->state.pixel_shader = (IWineD3DBaseShaderImpl *)shader;
3752 device->updateStateBlock->changed.pixelShader = TRUE;
3754 /* Handle recording of state blocks */
3755 if (device->isRecordingState)
3756 TRACE("Recording... not performing anything\n");
3758 if (device->isRecordingState)
3760 TRACE("Recording... not performing anything.\n");
3762 wined3d_shader_incref(shader);
3764 wined3d_shader_decref(prev);
3770 TRACE("App is setting the old pixel shader over, nothing to do.\n");
3775 wined3d_shader_incref(shader);
3777 wined3d_shader_decref(prev);
3779 TRACE("Setting shader %p.\n", shader);
3780 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3785 static IWineD3DBaseShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3787 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3788 IWineD3DBaseShader *shader;
3790 TRACE("iface %p.\n", iface);
3792 shader = device->stateBlock->state.pixel_shader;
3794 wined3d_shader_incref(shader);
3796 TRACE("Returning %p.\n", shader);
3800 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3801 IWineD3DDevice *iface,
3803 CONST BOOL *srcData,
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3807 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3809 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3810 iface, srcData, start, count);
3812 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3814 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3815 for (i = 0; i < cnt; i++)
3816 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3818 for (i = start; i < cnt + start; ++i) {
3819 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3822 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3827 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3828 IWineD3DDevice *iface,
3833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3834 int cnt = min(count, MAX_CONST_B - start);
3836 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3837 iface, dstData, start, count);
3839 if (!dstData || cnt < 0)
3840 return WINED3DERR_INVALIDCALL;
3842 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3846 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3847 IWineD3DDevice *iface,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3855 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3856 iface, srcData, start, count);
3858 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3860 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3861 for (i = 0; i < cnt; i++)
3862 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3863 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3865 for (i = start; i < cnt + start; ++i) {
3866 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3869 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3875 IWineD3DDevice *iface,
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 int cnt = min(count, MAX_CONST_I - start);
3883 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3884 iface, dstData, start, count);
3886 if (!dstData || cnt < 0)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3893 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3894 IWineD3DDevice *iface,
3896 CONST float *srcData,
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3903 iface, srcData, start, count);
3905 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3906 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3907 return WINED3DERR_INVALIDCALL;
3909 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3911 for (i = 0; i < count; i++)
3912 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3913 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3916 if (!This->isRecordingState)
3918 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3922 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3923 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3928 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3929 IWineD3DDevice *iface,
3934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3935 int cnt = min(count, This->d3d_pshader_constantF - start);
3937 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3938 iface, dstData, start, count);
3940 if (!dstData || cnt < 0)
3941 return WINED3DERR_INVALIDCALL;
3943 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3947 /* Context activation is done by the caller. */
3948 /* Do not call while under the GL lock. */
3949 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3950 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3951 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3954 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3955 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3958 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3962 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3964 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3967 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3969 ERR("Source has no position mask\n");
3970 return WINED3DERR_INVALIDCALL;
3973 if (!dest->resource.allocatedMemory)
3974 buffer_get_sysmem(dest, gl_info);
3976 /* Get a pointer into the destination vbo(create one if none exists) and
3977 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3979 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3981 dest->flags |= WINED3D_BUFFER_CREATEBO;
3982 wined3d_buffer_preload(dest);
3985 if (dest->buffer_object)
3987 unsigned char extrabytes = 0;
3988 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3989 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3990 * this may write 4 extra bytes beyond the area that should be written
3992 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3993 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3994 if(!dest_conv_addr) {
3995 ERR("Out of memory\n");
3996 /* Continue without storing converted vertices */
3998 dest_conv = dest_conv_addr;
4001 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
4003 static BOOL warned = FALSE;
4005 * The clipping code is not quite correct. Some things need
4006 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4007 * so disable clipping for now.
4008 * (The graphics in Half-Life are broken, and my processvertices
4009 * test crashes with IDirect3DDevice3)
4015 FIXME("Clipping is broken and disabled for now\n");
4017 } else doClip = FALSE;
4018 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4020 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4023 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4024 WINED3DTS_PROJECTION,
4026 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4027 WINED3DTS_WORLDMATRIX(0),
4030 TRACE("View mat:\n");
4031 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);
4032 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);
4033 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);
4034 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);
4036 TRACE("Proj mat:\n");
4037 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);
4038 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);
4039 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);
4040 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);
4042 TRACE("World mat:\n");
4043 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);
4044 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);
4045 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);
4046 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);
4048 /* Get the viewport */
4049 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4050 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4051 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4053 multiply_matrix(&mat,&view_mat,&world_mat);
4054 multiply_matrix(&mat,&proj_mat,&mat);
4056 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4058 for (i = 0; i < dwCount; i+= 1) {
4059 unsigned int tex_index;
4061 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4062 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4063 /* The position first */
4064 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4065 const float *p = (const float *)(element->data + i * element->stride);
4067 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4069 /* Multiplication with world, view and projection matrix */
4070 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);
4071 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);
4072 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);
4073 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);
4075 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4077 /* WARNING: The following things are taken from d3d7 and were not yet checked
4078 * against d3d8 or d3d9!
4081 /* Clipping conditions: From msdn
4083 * A vertex is clipped if it does not match the following requirements
4087 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4089 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4090 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4095 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4096 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4099 /* "Normal" viewport transformation (not clipped)
4100 * 1) The values are divided by rhw
4101 * 2) The y axis is negative, so multiply it with -1
4102 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4103 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4104 * 4) Multiply x with Width/2 and add Width/2
4105 * 5) The same for the height
4106 * 6) Add the viewpoint X and Y to the 2D coordinates and
4107 * The minimum Z value to z
4108 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4110 * Well, basically it's simply a linear transformation into viewport
4122 z *= vp.MaxZ - vp.MinZ;
4124 x += vp.Width / 2 + vp.X;
4125 y += vp.Height / 2 + vp.Y;
4130 /* That vertex got clipped
4131 * Contrary to OpenGL it is not dropped completely, it just
4132 * undergoes a different calculation.
4134 TRACE("Vertex got clipped\n");
4141 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4142 * outside of the main vertex buffer memory. That needs some more
4147 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4150 ( (float *) dest_ptr)[0] = x;
4151 ( (float *) dest_ptr)[1] = y;
4152 ( (float *) dest_ptr)[2] = z;
4153 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4155 dest_ptr += 3 * sizeof(float);
4157 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4158 dest_ptr += sizeof(float);
4163 ( (float *) dest_conv)[0] = x * w;
4164 ( (float *) dest_conv)[1] = y * w;
4165 ( (float *) dest_conv)[2] = z * w;
4166 ( (float *) dest_conv)[3] = w;
4168 dest_conv += 3 * sizeof(float);
4170 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4171 dest_conv += sizeof(float);
4175 if (DestFVF & WINED3DFVF_PSIZE) {
4176 dest_ptr += sizeof(DWORD);
4177 if(dest_conv) dest_conv += sizeof(DWORD);
4179 if (DestFVF & WINED3DFVF_NORMAL) {
4180 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4181 const float *normal = (const float *)(element->data + i * element->stride);
4182 /* AFAIK this should go into the lighting information */
4183 FIXME("Didn't expect the destination to have a normal\n");
4184 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4186 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4190 if (DestFVF & WINED3DFVF_DIFFUSE) {
4191 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4192 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4193 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4195 static BOOL warned = FALSE;
4198 ERR("No diffuse color in source, but destination has one\n");
4202 *( (DWORD *) dest_ptr) = 0xffffffff;
4203 dest_ptr += sizeof(DWORD);
4206 *( (DWORD *) dest_conv) = 0xffffffff;
4207 dest_conv += sizeof(DWORD);
4211 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4213 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4214 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4215 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4216 dest_conv += sizeof(DWORD);
4221 if (DestFVF & WINED3DFVF_SPECULAR)
4223 /* What's the color value in the feedback buffer? */
4224 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4225 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4226 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4228 static BOOL warned = FALSE;
4231 ERR("No specular color in source, but destination has one\n");
4235 *( (DWORD *) dest_ptr) = 0xFF000000;
4236 dest_ptr += sizeof(DWORD);
4239 *( (DWORD *) dest_conv) = 0xFF000000;
4240 dest_conv += sizeof(DWORD);
4244 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4246 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4247 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4248 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4249 dest_conv += sizeof(DWORD);
4254 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4255 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4256 const float *tex_coord = (const float *)(element->data + i * element->stride);
4257 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4259 ERR("No source texture, but destination requests one\n");
4260 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4261 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4264 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4266 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4276 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4277 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4278 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4279 dwCount * get_flexible_vertex_size(DestFVF),
4281 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4285 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4290 #undef copy_and_next
4292 /* Do not call while under the GL lock. */
4293 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4294 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4295 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4298 struct wined3d_stream_info stream_info;
4299 const struct wined3d_gl_info *gl_info;
4300 struct wined3d_context *context;
4301 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4304 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4307 ERR("Output vertex declaration not implemented yet\n");
4310 /* Need any context to write to the vbo. */
4311 context = context_acquire(This, NULL);
4312 gl_info = context->gl_info;
4314 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4315 * control the streamIsUP flag, thus restore it afterwards.
4317 This->stateBlock->state.user_stream = FALSE;
4318 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4319 This->stateBlock->state.user_stream = streamWasUP;
4321 if(vbo || SrcStartIndex) {
4323 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4324 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4326 * Also get the start index in, but only loop over all elements if there's something to add at all.
4328 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4330 struct wined3d_stream_info_element *e;
4332 if (!(stream_info.use_map & (1 << i))) continue;
4334 e = &stream_info.elements[i];
4335 if (e->buffer_object)
4337 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4338 e->buffer_object = 0;
4339 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4341 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4342 vb->buffer_object = 0;
4345 if (e->data) e->data += e->stride * SrcStartIndex;
4349 hr = process_vertices_strided(This, DestIndex, VertexCount,
4350 &stream_info, dst_buffer, flags, DestFVF);
4352 context_release(context);
4358 * Get / Set Texture Stage States
4359 * TODO: Verify against dx9 definitions
4361 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4364 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4367 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4369 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4371 WARN("Invalid Type %d passed.\n", Type);
4375 if (Stage >= gl_info->limits.texture_stages)
4377 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4378 Stage, gl_info->limits.texture_stages - 1);
4382 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4383 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4384 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4386 if (This->isRecordingState) {
4387 TRACE("Recording... not performing anything\n");
4391 /* Checked after the assignments to allow proper stateblock recording */
4392 if(oldValue == Value) {
4393 TRACE("App is setting the old value over, nothing to do\n");
4397 if (Stage > This->stateBlock->state.lowest_disabled_stage
4398 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4399 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4401 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4402 * Changes in other states are important on disabled stages too
4407 if(Type == WINED3DTSS_COLOROP) {
4410 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4411 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4412 * they have to be disabled
4414 * The current stage is dirtified below.
4416 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4418 TRACE("Additionally dirtifying stage %u\n", i);
4419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4421 This->stateBlock->state.lowest_disabled_stage = Stage;
4422 TRACE("New lowest disabled: %u\n", Stage);
4423 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4424 /* Previously disabled stage enabled. Stages above it may need enabling
4425 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4426 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4428 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4431 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4433 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4435 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4438 This->stateBlock->state.lowest_disabled_stage = i;
4439 TRACE("New lowest disabled: %u\n", i);
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4448 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 TRACE("iface %p, stage %u, state %s, value %p.\n",
4453 iface, Stage, debug_d3dtexturestate(Type), pValue);
4455 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4457 WARN("Invalid Type %d passed.\n", Type);
4461 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4462 TRACE("Returning %#x.\n", *pValue);
4467 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4468 DWORD stage, struct wined3d_texture *texture)
4470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4471 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4472 struct wined3d_texture *prev;
4474 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4476 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4477 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4479 /* Windows accepts overflowing this array... we do not. */
4480 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4482 WARN("Ignoring invalid stage %u.\n", stage);
4486 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4487 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4489 WARN("Rejecting attempt to set scratch texture.\n");
4490 return WINED3DERR_INVALIDCALL;
4493 This->updateStateBlock->changed.textures |= 1 << stage;
4495 prev = This->updateStateBlock->state.textures[stage];
4496 TRACE("Previous texture %p.\n", prev);
4498 if (texture == prev)
4500 TRACE("App is setting the same texture again, nothing to do.\n");
4504 TRACE("Setting new texture to %p.\n", texture);
4505 This->updateStateBlock->state.textures[stage] = texture;
4507 if (This->isRecordingState)
4509 TRACE("Recording... not performing anything\n");
4511 if (texture) wined3d_texture_incref(texture);
4512 if (prev) wined3d_texture_decref(prev);
4519 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4521 wined3d_texture_incref(texture);
4523 if (!prev || texture->target != prev->target)
4524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4526 if (!prev && stage < gl_info->limits.texture_stages)
4528 /* The source arguments for color and alpha ops have different
4529 * meanings when a NULL texture is bound, so the COLOROP and
4530 * ALPHAOP have to be dirtified. */
4531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4535 if (bind_count == 1)
4536 texture->sampler = stage;
4541 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4543 wined3d_texture_decref(prev);
4545 if (!texture && stage < gl_info->limits.texture_stages)
4547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4551 if (bind_count && prev->sampler == stage)
4555 /* Search for other stages the texture is bound to. Shouldn't
4556 * happen if applications bind textures to a single stage only. */
4557 TRACE("Searching for other stages the texture is bound to.\n");
4558 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4560 if (This->updateStateBlock->state.textures[i] == prev)
4562 TRACE("Texture is also bound to stage %u.\n", i);
4570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4575 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4576 DWORD stage, struct wined3d_texture **texture)
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4582 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4583 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4585 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4587 WARN("Current stage overflows textures array (stage %u).\n", stage);
4588 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4591 *texture = This->stateBlock->state.textures[stage];
4593 wined3d_texture_incref(*texture);
4595 TRACE("Returning %p.\n", *texture);
4603 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4604 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4606 IWineD3DSwapChain *swapchain;
4609 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4610 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4612 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4615 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4619 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4620 IWineD3DSwapChain_Release(swapchain);
4623 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4630 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4632 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4634 TRACE("iface %p, caps %p.\n", iface, caps);
4636 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4639 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 IWineD3DSwapChain *swapChain;
4644 if(iSwapChain > 0) {
4645 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4646 if (hr == WINED3D_OK) {
4647 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4648 IWineD3DSwapChain_Release(swapChain);
4650 FIXME("(%p) Error getting display mode\n", This);
4653 /* Don't read the real display mode,
4654 but return the stored mode instead. X11 can't change the color
4655 depth, and some apps are pretty angry if they SetDisplayMode from
4656 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4658 Also don't relay to the swapchain because with ddraw it's possible
4659 that there isn't a swapchain at all */
4660 pMode->Width = This->ddraw_width;
4661 pMode->Height = This->ddraw_height;
4662 pMode->Format = This->ddraw_format;
4663 pMode->RefreshRate = 0;
4671 * Stateblock related functions
4674 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4677 struct wined3d_stateblock *stateblock;
4680 TRACE("(%p)\n", This);
4682 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4684 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4685 if (FAILED(hr)) return hr;
4687 wined3d_stateblock_decref(This->updateStateBlock);
4688 This->updateStateBlock = stateblock;
4689 This->isRecordingState = TRUE;
4691 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4696 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4697 struct wined3d_stateblock **stateblock)
4699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4700 struct wined3d_stateblock *object = This->updateStateBlock;
4702 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4704 if (!This->isRecordingState) {
4705 WARN("(%p) not recording! returning error\n", This);
4707 return WINED3DERR_INVALIDCALL;
4710 stateblock_init_contained_states(object);
4712 *stateblock = object;
4713 This->isRecordingState = FALSE;
4714 This->updateStateBlock = This->stateBlock;
4715 wined3d_stateblock_incref(This->updateStateBlock);
4717 TRACE("Returning stateblock %p.\n", *stateblock);
4723 * Scene related functions
4725 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4726 /* At the moment we have no need for any functionality at the beginning
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 TRACE("(%p)\n", This);
4732 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4733 return WINED3DERR_INVALIDCALL;
4735 This->inScene = TRUE;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 struct wined3d_context *context;
4744 TRACE("(%p)\n", This);
4746 if(!This->inScene) {
4747 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4748 return WINED3DERR_INVALIDCALL;
4751 context = context_acquire(This, NULL);
4752 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4754 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4756 context_release(context);
4758 This->inScene = FALSE;
4762 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4763 const RECT *pSourceRect, const RECT *pDestRect,
4764 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4766 IWineD3DSwapChain *swapChain = NULL;
4768 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4770 TRACE("iface %p.\n", iface);
4772 for(i = 0 ; i < swapchains ; i ++) {
4774 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4775 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4776 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4777 IWineD3DSwapChain_Release(swapChain);
4783 /* Do not call while under the GL lock. */
4784 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4785 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4787 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4788 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4791 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4792 iface, rect_count, rects, flags, color, depth, stencil);
4794 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4796 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4799 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4800 /* TODO: What about depth stencil buffers without stencil bits? */
4801 return WINED3DERR_INVALIDCALL;
4803 else if (flags & WINED3DCLEAR_TARGET)
4805 if(ds->resource.width < device->render_targets[0]->resource.width ||
4806 ds->resource.height < device->render_targets[0]->resource.height)
4808 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4814 device_get_draw_rect(device, &draw_rect);
4816 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4817 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4824 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4825 WINED3DPRIMITIVETYPE primitive_type)
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4831 This->updateStateBlock->changed.primitive_type = TRUE;
4832 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4835 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4836 WINED3DPRIMITIVETYPE *primitive_type)
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4842 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4844 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4853 if (!This->stateBlock->state.vertex_declaration)
4855 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4856 return WINED3DERR_INVALIDCALL;
4859 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4860 if (This->stateBlock->state.user_stream)
4862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4863 This->stateBlock->state.user_stream = FALSE;
4866 if (This->stateBlock->state.load_base_vertex_index)
4868 This->stateBlock->state.load_base_vertex_index = 0;
4869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4871 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4872 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4876 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4879 struct wined3d_buffer *index_buffer;
4883 index_buffer = This->stateBlock->state.index_buffer;
4886 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4887 * without an index buffer set. (The first time at least...)
4888 * D3D8 simply dies, but I doubt it can do much harm to return
4889 * D3DERR_INVALIDCALL there as well. */
4890 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4891 return WINED3DERR_INVALIDCALL;
4894 if (!This->stateBlock->state.vertex_declaration)
4896 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4897 return WINED3DERR_INVALIDCALL;
4900 if (This->stateBlock->state.user_stream)
4902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4903 This->stateBlock->state.user_stream = FALSE;
4905 vbo = index_buffer->buffer_object;
4907 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4909 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4914 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4916 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4920 drawPrimitive(This, index_count, startIndex, idxStride,
4921 vbo ? NULL : index_buffer->resource.allocatedMemory);
4926 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4927 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4930 struct wined3d_stream_state *stream;
4931 struct wined3d_buffer *vb;
4933 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4934 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4936 if (!This->stateBlock->state.vertex_declaration)
4938 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4939 return WINED3DERR_INVALIDCALL;
4942 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4943 stream = &This->stateBlock->state.streams[0];
4944 vb = stream->buffer;
4945 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4947 wined3d_buffer_decref(vb);
4949 stream->stride = VertexStreamZeroStride;
4950 This->stateBlock->state.user_stream = TRUE;
4951 This->stateBlock->state.load_base_vertex_index = 0;
4953 /* TODO: Only mark dirty if drawing from a different UP address */
4954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4956 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4958 /* MSDN specifies stream zero settings must be set to NULL */
4959 stream->buffer = NULL;
4962 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4963 * the new stream sources or use UP drawing again
4968 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4969 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4970 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4974 struct wined3d_stream_state *stream;
4975 struct wined3d_buffer *vb, *ib;
4977 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4978 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4980 if (!This->stateBlock->state.vertex_declaration)
4982 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4983 return WINED3DERR_INVALIDCALL;
4986 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4992 stream = &This->stateBlock->state.streams[0];
4993 vb = stream->buffer;
4994 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4996 wined3d_buffer_decref(vb);
4998 stream->stride = VertexStreamZeroStride;
4999 This->stateBlock->state.user_stream = TRUE;
5001 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5002 This->stateBlock->state.base_vertex_index = 0;
5003 This->stateBlock->state.load_base_vertex_index = 0;
5004 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5008 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
5010 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5011 stream->buffer = NULL;
5013 ib = This->stateBlock->state.index_buffer;
5016 wined3d_buffer_decref(ib);
5017 This->stateBlock->state.index_buffer = NULL;
5019 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5020 * SetStreamSource to specify a vertex buffer
5026 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5027 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5031 /* Mark the state dirty until we have nicer tracking
5032 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5037 This->stateBlock->state.base_vertex_index = 0;
5038 This->up_strided = DrawPrimStrideData;
5039 drawPrimitive(This, vertex_count, 0, 0, NULL);
5040 This->up_strided = NULL;
5044 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5045 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5046 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5049 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5051 /* Mark the state dirty until we have nicer tracking
5052 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5057 This->stateBlock->state.user_stream = TRUE;
5058 This->stateBlock->state.base_vertex_index = 0;
5059 This->up_strided = DrawPrimStrideData;
5060 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5061 This->up_strided = NULL;
5065 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5066 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5067 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5069 WINED3DLOCKED_BOX src;
5070 WINED3DLOCKED_BOX dst;
5073 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5074 iface, pSourceVolume, pDestinationVolume);
5076 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5077 * dirtification to improve loading performance.
5079 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5080 if (FAILED(hr)) return hr;
5081 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5084 IWineD3DVolume_Unmap(pSourceVolume);
5088 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5090 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5092 IWineD3DVolume_Unmap(pSourceVolume);
5094 hr = IWineD3DVolume_Unmap(pSourceVolume);
5099 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5100 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5102 unsigned int level_count, i;
5103 WINED3DRESOURCETYPE type;
5106 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5108 /* Verify that the source and destination textures are non-NULL. */
5109 if (!src_texture || !dst_texture)
5111 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5112 return WINED3DERR_INVALIDCALL;
5115 if (src_texture == dst_texture)
5117 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5118 return WINED3DERR_INVALIDCALL;
5121 /* Verify that the source and destination textures are the same type. */
5122 type = wined3d_texture_get_type(src_texture);
5123 if (wined3d_texture_get_type(dst_texture) != type)
5125 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5126 return WINED3DERR_INVALIDCALL;
5129 /* Check that both textures have the identical numbers of levels. */
5130 level_count = wined3d_texture_get_level_count(src_texture);
5131 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5133 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5134 return WINED3DERR_INVALIDCALL;
5137 /* Make sure that the destination texture is loaded. */
5138 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5140 /* Update every surface level of the texture. */
5143 case WINED3DRTYPE_TEXTURE:
5145 IWineD3DSurface *src_surface;
5146 IWineD3DSurface *dst_surface;
5148 for (i = 0; i < level_count; ++i)
5150 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5152 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5154 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5157 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5164 case WINED3DRTYPE_CUBETEXTURE:
5166 IWineD3DSurface *src_surface;
5167 IWineD3DSurface *dst_surface;
5169 for (i = 0; i < level_count * 6; ++i)
5171 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5173 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5175 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5178 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5185 case WINED3DRTYPE_VOLUMETEXTURE:
5187 IWineD3DVolume *src_volume;
5188 IWineD3DVolume *dst_volume;
5190 for (i = 0; i < level_count; ++i)
5192 src_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
5193 dst_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
5194 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5197 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5205 FIXME("Unsupported texture type %#x.\n", type);
5206 return WINED3DERR_INVALIDCALL;
5212 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5213 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5215 IWineD3DSwapChain *swapchain;
5218 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5220 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5221 if (FAILED(hr)) return hr;
5223 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5224 IWineD3DSwapChain_Release(swapchain);
5229 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 const struct wined3d_state *state = &This->stateBlock->state;
5233 struct wined3d_texture *texture;
5236 TRACE("(%p) : %p\n", This, pNumPasses);
5238 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5240 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5242 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5243 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5245 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5247 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5248 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5251 texture = state->textures[i];
5252 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5254 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5256 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5259 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5261 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5264 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5265 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5267 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5272 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5273 state->render_states[WINED3DRS_STENCILENABLE])
5275 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5276 IWineD3DSurfaceImpl *target = This->render_targets[0];
5279 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5281 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5282 return WINED3DERR_CONFLICTINGRENDERSTATE;
5286 /* return a sensible default */
5289 TRACE("returning D3D_OK\n");
5293 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5297 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5299 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5300 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5301 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5303 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5308 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5312 PALETTEENTRY **palettes;
5314 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5316 if (PaletteNumber >= MAX_PALETTES) {
5317 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5318 return WINED3DERR_INVALIDCALL;
5321 if (PaletteNumber >= This->NumberOfPalettes) {
5322 NewSize = This->NumberOfPalettes;
5325 } while(PaletteNumber >= NewSize);
5326 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5328 ERR("Out of memory!\n");
5329 return E_OUTOFMEMORY;
5331 This->palettes = palettes;
5332 This->NumberOfPalettes = NewSize;
5335 if (!This->palettes[PaletteNumber]) {
5336 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5337 if (!This->palettes[PaletteNumber]) {
5338 ERR("Out of memory!\n");
5339 return E_OUTOFMEMORY;
5343 for (j = 0; j < 256; ++j) {
5344 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5345 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5346 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5347 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5349 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5350 TRACE("(%p) : returning\n", This);
5354 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5358 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5359 /* What happens in such situation isn't documented; Native seems to silently abort
5360 on such conditions. Return Invalid Call. */
5361 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5362 return WINED3DERR_INVALIDCALL;
5364 for (j = 0; j < 256; ++j) {
5365 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5366 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5367 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5368 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5370 TRACE("(%p) : returning\n", This);
5374 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5377 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5378 (tested with reference rasterizer). Return Invalid Call. */
5379 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5380 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5381 return WINED3DERR_INVALIDCALL;
5383 /*TODO: stateblocks */
5384 if (This->currentPalette != PaletteNumber) {
5385 This->currentPalette = PaletteNumber;
5386 dirtify_p8_texture_samplers(This);
5388 TRACE("(%p) : returning\n", This);
5392 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5397 WARN("(%p) : returning Invalid Call\n", This);
5398 return WINED3DERR_INVALIDCALL;
5400 /*TODO: stateblocks */
5401 *PaletteNumber = This->currentPalette;
5402 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5406 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5411 FIXME("(%p) : stub\n", This);
5415 This->softwareVertexProcessing = bSoftware;
5420 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5425 FIXME("(%p) : stub\n", This);
5428 return This->softwareVertexProcessing;
5431 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5432 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5434 IWineD3DSwapChain *swapchain;
5437 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5438 iface, swapchain_idx, raster_status);
5440 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5443 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5447 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5448 IWineD3DSwapChain_Release(swapchain);
5451 WARN("Failed to get raster status, hr %#x.\n", hr);
5458 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5461 if(nSegments != 0.0f) {
5464 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5471 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5476 FIXME("iface %p stub!\n", iface);
5482 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5483 IWineD3DSurface *src_surface, const RECT *src_rect,
5484 IWineD3DSurface *dst_surface, const POINT *dst_point)
5486 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5487 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5489 const struct wined3d_format *src_format;
5490 const struct wined3d_format *dst_format;
5491 const struct wined3d_gl_info *gl_info;
5492 struct wined3d_context *context;
5493 const unsigned char *data;
5494 UINT update_w, update_h;
5495 CONVERT_TYPES convert;
5499 struct wined3d_format format;
5501 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5502 iface, src_surface, wine_dbgstr_rect(src_rect),
5503 dst_surface, wine_dbgstr_point(dst_point));
5505 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5507 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5508 src_surface, dst_surface);
5509 return WINED3DERR_INVALIDCALL;
5512 src_format = src_impl->resource.format;
5513 dst_format = dst_impl->resource.format;
5515 if (src_format->id != dst_format->id)
5517 WARN("Source and destination surfaces should have the same format.\n");
5518 return WINED3DERR_INVALIDCALL;
5521 dst_x = dst_point ? dst_point->x : 0;
5522 dst_y = dst_point ? dst_point->y : 0;
5524 /* This call loads the OpenGL surface directly, instead of copying the
5525 * surface to the destination's sysmem copy. If surface conversion is
5526 * needed, use BltFast instead to copy in sysmem and use regular surface
5528 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5529 if (convert != NO_CONVERSION || format.convert)
5530 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5532 context = context_acquire(This, NULL);
5533 gl_info = context->gl_info;
5536 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5537 checkGLcall("glActiveTextureARB");
5540 /* Make sure the surface is loaded and up to date */
5541 surface_internal_preload(dst_impl, SRGB_RGB);
5542 surface_bind(dst_impl, gl_info, FALSE);
5544 src_w = src_impl->resource.width;
5545 src_h = src_impl->resource.height;
5546 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5547 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5549 data = src_impl->resource.allocatedMemory;
5550 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5554 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5556 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5557 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5558 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5562 data += (src_rect->top / src_format->block_height) * src_pitch;
5563 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5566 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5567 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5568 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5570 if (row_length == src_pitch)
5572 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5573 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5579 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5580 * can't use the unpack row length like below. */
5581 for (row = 0, y = dst_y; row < row_count; ++row)
5583 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5584 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5585 y += src_format->block_height;
5589 checkGLcall("glCompressedTexSubImage2DARB");
5595 data += src_rect->top * src_w * src_format->byte_count;
5596 data += src_rect->left * src_format->byte_count;
5599 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5600 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5601 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5603 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5604 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5605 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5606 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5607 checkGLcall("glTexSubImage2D");
5611 context_release(context);
5613 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5614 sampler = This->rev_tex_unit_map[0];
5615 if (sampler != WINED3D_UNMAPPED_STAGE)
5617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5623 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5625 struct WineD3DRectPatch *patch;
5626 GLenum old_primitive_type;
5630 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5632 if(!(Handle || pRectPatchInfo)) {
5633 /* TODO: Write a test for the return value, thus the FIXME */
5634 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5635 return WINED3DERR_INVALIDCALL;
5639 i = PATCHMAP_HASHFUNC(Handle);
5641 LIST_FOR_EACH(e, &This->patches[i]) {
5642 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5643 if(patch->Handle == Handle) {
5650 TRACE("Patch does not exist. Creating a new one\n");
5651 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5652 patch->Handle = Handle;
5653 list_add_head(&This->patches[i], &patch->entry);
5655 TRACE("Found existing patch %p\n", patch);
5658 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5659 * attributes we have to tesselate, read back, and draw. This needs a patch
5660 * management structure instance. Create one.
5662 * A possible improvement is to check if a vertex shader is used, and if not directly
5665 FIXME("Drawing an uncached patch. This is slow\n");
5666 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5669 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5670 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5671 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5674 TRACE("Tesselation density or patch info changed, retesselating\n");
5676 if(pRectPatchInfo) {
5677 patch->RectPatchInfo = *pRectPatchInfo;
5679 patch->numSegs[0] = pNumSegs[0];
5680 patch->numSegs[1] = pNumSegs[1];
5681 patch->numSegs[2] = pNumSegs[2];
5682 patch->numSegs[3] = pNumSegs[3];
5684 hr = tesselate_rectpatch(This, patch);
5686 WARN("Patch tesselation failed\n");
5688 /* Do not release the handle to store the params of the patch */
5690 HeapFree(GetProcessHeap(), 0, patch);
5696 This->currentPatch = patch;
5697 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5698 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5699 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5700 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5701 This->currentPatch = NULL;
5703 /* Destroy uncached patches */
5705 HeapFree(GetProcessHeap(), 0, patch->mem);
5706 HeapFree(GetProcessHeap(), 0, patch);
5711 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5712 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5714 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5715 iface, handle, segment_count, patch_info);
5720 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5723 struct WineD3DRectPatch *patch;
5725 TRACE("(%p) Handle(%d)\n", This, Handle);
5727 i = PATCHMAP_HASHFUNC(Handle);
5728 LIST_FOR_EACH(e, &This->patches[i]) {
5729 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5730 if(patch->Handle == Handle) {
5731 TRACE("Deleting patch %p\n", patch);
5732 list_remove(&patch->entry);
5733 HeapFree(GetProcessHeap(), 0, patch->mem);
5734 HeapFree(GetProcessHeap(), 0, patch);
5739 /* TODO: Write a test for the return value */
5740 FIXME("Attempt to destroy nonexistent patch\n");
5741 return WINED3DERR_INVALIDCALL;
5744 /* Do not call while under the GL lock. */
5745 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5746 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5748 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5750 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5751 iface, surface, wine_dbgstr_rect(rect),
5752 color->r, color->g, color->b, color->a);
5754 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5756 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5757 return WINED3DERR_INVALIDCALL;
5760 return surface_color_fill(s, rect, color);
5763 /* Do not call while under the GL lock. */
5764 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5765 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5767 struct wined3d_resource *resource;
5770 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5773 ERR("Failed to get resource, hr %#x\n", hr);
5777 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5779 FIXME("Only supported on surface resources\n");
5783 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5784 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5787 /* rendertarget and depth stencil functions */
5788 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5789 DWORD render_target_idx, IWineD3DSurface **render_target)
5791 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5793 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5794 iface, render_target_idx, render_target);
5796 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5798 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5799 return WINED3DERR_INVALIDCALL;
5802 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5803 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5805 TRACE("Returning render target %p.\n", *render_target);
5810 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5812 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5814 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5816 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5817 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5818 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5819 IWineD3DSurface_AddRef(*depth_stencil);
5824 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5825 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5827 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5828 IWineD3DSurfaceImpl *prev;
5830 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5831 iface, render_target_idx, render_target, set_viewport);
5833 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5835 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5836 return WINED3DERR_INVALIDCALL;
5839 prev = device->render_targets[render_target_idx];
5840 if (render_target == (IWineD3DSurface *)prev)
5842 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5846 /* Render target 0 can't be set to NULL. */
5847 if (!render_target && !render_target_idx)
5849 WARN("Trying to set render target 0 to NULL.\n");
5850 return WINED3DERR_INVALIDCALL;
5853 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5855 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5856 return WINED3DERR_INVALIDCALL;
5859 if (render_target) IWineD3DSurface_AddRef(render_target);
5860 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5861 /* Release after the assignment, to prevent device_resource_released()
5862 * from seeing the surface as still in use. */
5863 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5865 /* Render target 0 is special. */
5866 if (!render_target_idx && set_viewport)
5868 /* Set the viewport and scissor rectangles, if requested. Tests show
5869 * that stateblock recording is ignored, the change goes directly
5870 * into the primary stateblock. */
5871 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5872 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5873 device->stateBlock->state.viewport.X = 0;
5874 device->stateBlock->state.viewport.Y = 0;
5875 device->stateBlock->state.viewport.MaxZ = 1.0f;
5876 device->stateBlock->state.viewport.MinZ = 0.0f;
5877 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5879 device->stateBlock->state.scissor_rect.top = 0;
5880 device->stateBlock->state.scissor_rect.left = 0;
5881 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5882 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5883 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5889 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5892 IWineD3DSurfaceImpl *tmp;
5894 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5896 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5898 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5902 if (This->depth_stencil)
5904 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5905 || This->depth_stencil->flags & SFLAG_DISCARD)
5907 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5908 This->depth_stencil->resource.width,
5909 This->depth_stencil->resource.height);
5910 if (This->depth_stencil == This->onscreen_depth_stencil)
5912 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5913 This->onscreen_depth_stencil = NULL;
5918 tmp = This->depth_stencil;
5919 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5920 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5921 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5923 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5925 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5934 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5935 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5938 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5939 WINED3DLOCKED_RECT lockedRect;
5941 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5942 iface, XHotSpot, YHotSpot, cursor_image);
5944 /* some basic validation checks */
5945 if (This->cursorTexture)
5947 struct wined3d_context *context = context_acquire(This, NULL);
5949 glDeleteTextures(1, &This->cursorTexture);
5951 context_release(context);
5952 This->cursorTexture = 0;
5955 if (s->resource.width == 32 && s->resource.height == 32)
5956 This->haveHardwareCursor = TRUE;
5958 This->haveHardwareCursor = FALSE;
5962 WINED3DLOCKED_RECT rect;
5964 /* MSDN: Cursor must be A8R8G8B8 */
5965 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5967 WARN("surface %p has an invalid format.\n", cursor_image);
5968 return WINED3DERR_INVALIDCALL;
5971 /* MSDN: Cursor must be smaller than the display mode */
5972 if (s->resource.width > This->ddraw_width
5973 || s->resource.height > This->ddraw_height)
5975 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5976 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5977 return WINED3DERR_INVALIDCALL;
5980 if (!This->haveHardwareCursor) {
5981 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5983 /* Do not store the surface's pointer because the application may
5984 * release it after setting the cursor image. Windows doesn't
5985 * addref the set surface, so we can't do this either without
5986 * creating circular refcount dependencies. Copy out the gl texture
5989 This->cursorWidth = s->resource.width;
5990 This->cursorHeight = s->resource.height;
5991 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5993 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5994 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5995 struct wined3d_context *context;
5996 char *mem, *bits = rect.pBits;
5997 GLint intfmt = format->glInternal;
5998 GLint gl_format = format->glFormat;
5999 GLint type = format->glType;
6000 INT height = This->cursorHeight;
6001 INT width = This->cursorWidth;
6002 INT bpp = format->byte_count;
6006 /* Reformat the texture memory (pitch and width can be
6008 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6009 for(i = 0; i < height; i++)
6010 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6011 IWineD3DSurface_Unmap(cursor_image);
6013 context = context_acquire(This, NULL);
6017 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6019 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6020 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6023 /* Make sure that a proper texture unit is selected */
6024 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6025 checkGLcall("glActiveTextureARB");
6026 sampler = This->rev_tex_unit_map[0];
6027 if (sampler != WINED3D_UNMAPPED_STAGE)
6029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6031 /* Create a new cursor texture */
6032 glGenTextures(1, &This->cursorTexture);
6033 checkGLcall("glGenTextures");
6034 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6035 checkGLcall("glBindTexture");
6036 /* Copy the bitmap memory into the cursor texture */
6037 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6038 checkGLcall("glTexImage2D");
6039 HeapFree(GetProcessHeap(), 0, mem);
6041 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6049 context_release(context);
6053 FIXME("A cursor texture was not returned.\n");
6054 This->cursorTexture = 0;
6059 /* Draw a hardware cursor */
6060 ICONINFO cursorInfo;
6062 /* Create and clear maskBits because it is not needed for
6063 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6065 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6066 (s->resource.width * s->resource.height / 8));
6067 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6068 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6069 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6071 cursorInfo.fIcon = FALSE;
6072 cursorInfo.xHotspot = XHotSpot;
6073 cursorInfo.yHotspot = YHotSpot;
6074 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6075 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6076 IWineD3DSurface_Unmap(cursor_image);
6077 /* Create our cursor and clean up. */
6078 cursor = CreateIconIndirect(&cursorInfo);
6080 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6081 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6082 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6083 This->hardwareCursor = cursor;
6084 HeapFree(GetProcessHeap(), 0, maskBits);
6088 This->xHotSpot = XHotSpot;
6089 This->yHotSpot = YHotSpot;
6093 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6094 int XScreenSpace, int YScreenSpace, DWORD flags)
6096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6098 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6099 iface, XScreenSpace, YScreenSpace, flags);
6101 This->xScreenSpace = XScreenSpace;
6102 This->yScreenSpace = YScreenSpace;
6105 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6107 BOOL oldVisible = This->bCursorVisible;
6110 TRACE("(%p) : visible(%d)\n", This, bShow);
6113 * When ShowCursor is first called it should make the cursor appear at the OS's last
6114 * known cursor position. Because of this, some applications just repetitively call
6115 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6118 This->xScreenSpace = pt.x;
6119 This->yScreenSpace = pt.y;
6121 if (This->haveHardwareCursor) {
6122 This->bCursorVisible = bShow;
6124 SetCursor(This->hardwareCursor);
6130 if (This->cursorTexture)
6131 This->bCursorVisible = bShow;
6137 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6139 TRACE("checking resource %p for eviction\n", resource);
6141 if (resource->pool == WINED3DPOOL_MANAGED)
6143 TRACE("Evicting %p.\n", resource);
6144 resource->resource_ops->resource_unload(resource);
6150 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6152 TRACE("iface %p.\n", iface);
6154 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6155 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6156 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6161 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6163 IWineD3DDeviceImpl *device = surface->resource.device;
6164 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6166 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6167 if (surface->flags & SFLAG_DIBSECTION)
6169 /* Release the DC */
6170 SelectObject(surface->hDC, surface->dib.holdbitmap);
6171 DeleteDC(surface->hDC);
6172 /* Release the DIB section */
6173 DeleteObject(surface->dib.DIBsection);
6174 surface->dib.bitmap_data = NULL;
6175 surface->resource.allocatedMemory = NULL;
6176 surface->flags &= ~SFLAG_DIBSECTION;
6178 surface->resource.width = pPresentationParameters->BackBufferWidth;
6179 surface->resource.height = pPresentationParameters->BackBufferHeight;
6180 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6181 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6183 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6184 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6186 surface->pow2Width = surface->pow2Height = 1;
6187 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6188 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6191 if (surface->texture_name)
6193 struct wined3d_context *context = context_acquire(device, NULL);
6195 glDeleteTextures(1, &surface->texture_name);
6197 context_release(context);
6198 surface->texture_name = 0;
6199 surface->flags &= ~SFLAG_CLIENT;
6201 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6202 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6204 surface->flags |= SFLAG_NONPOW2;
6208 surface->flags &= ~SFLAG_NONPOW2;
6210 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6211 surface->resource.allocatedMemory = NULL;
6212 surface->resource.heapMemory = NULL;
6213 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6215 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6217 if (!surface_init_sysmem(surface))
6219 return E_OUTOFMEMORY;
6224 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6227 WINED3DDISPLAYMODE m;
6230 /* All Windowed modes are supported, as is leaving the current mode */
6231 if(pp->Windowed) return TRUE;
6232 if(!pp->BackBufferWidth) return TRUE;
6233 if(!pp->BackBufferHeight) return TRUE;
6235 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6236 for (i = 0; i < count; ++i)
6238 memset(&m, 0, sizeof(m));
6239 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6241 ERR("Failed to enumerate adapter mode.\n");
6242 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6243 /* Mode found, it is supported. */
6246 /* Mode not found -> not supported */
6250 /* Do not call while under the GL lock. */
6251 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6253 const struct wined3d_gl_info *gl_info;
6254 struct wined3d_context *context;
6255 IWineD3DBaseShaderImpl *shader;
6257 context = context_acquire(device, NULL);
6258 gl_info = context->gl_info;
6260 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6261 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, shader_list_entry)
6263 device->shader_backend->shader_destroy(shader);
6267 if (device->depth_blt_texture)
6269 glDeleteTextures(1, &device->depth_blt_texture);
6270 device->depth_blt_texture = 0;
6272 if (device->depth_blt_rb)
6274 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6275 device->depth_blt_rb = 0;
6276 device->depth_blt_rb_w = 0;
6277 device->depth_blt_rb_h = 0;
6281 device->blitter->free_private(device);
6282 device->frag_pipe->free_private(device);
6283 device->shader_backend->shader_free_private(device);
6284 destroy_dummy_textures(device, gl_info);
6286 context_release(context);
6288 while (device->numContexts)
6290 context_destroy(device, device->contexts[0]);
6292 HeapFree(GetProcessHeap(), 0, swapchain->context);
6293 swapchain->context = NULL;
6294 swapchain->num_contexts = 0;
6297 /* Do not call while under the GL lock. */
6298 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6300 struct wined3d_context *context;
6302 IWineD3DSurfaceImpl *target;
6304 /* Recreate the primary swapchain's context */
6305 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6306 if (!swapchain->context)
6308 ERR("Failed to allocate memory for swapchain context array.\n");
6309 return E_OUTOFMEMORY;
6312 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6313 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6315 WARN("Failed to create context.\n");
6316 HeapFree(GetProcessHeap(), 0, swapchain->context);
6320 swapchain->context[0] = context;
6321 swapchain->num_contexts = 1;
6322 create_dummy_textures(device);
6323 context_release(context);
6325 hr = device->shader_backend->shader_alloc_private(device);
6328 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6332 hr = device->frag_pipe->alloc_private(device);
6335 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6336 device->shader_backend->shader_free_private(device);
6340 hr = device->blitter->alloc_private(device);
6343 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6344 device->frag_pipe->free_private(device);
6345 device->shader_backend->shader_free_private(device);
6352 context_acquire(device, NULL);
6353 destroy_dummy_textures(device, context->gl_info);
6354 context_release(context);
6355 context_destroy(device, context);
6356 HeapFree(GetProcessHeap(), 0, swapchain->context);
6357 swapchain->num_contexts = 0;
6361 /* Do not call while under the GL lock. */
6362 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6363 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6366 IWineD3DSwapChainImpl *swapchain;
6368 BOOL DisplayModeChanged = FALSE;
6369 WINED3DDISPLAYMODE mode;
6370 TRACE("(%p)\n", This);
6372 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6374 ERR("Failed to get the first implicit swapchain\n");
6378 if(!is_display_mode_supported(This, pPresentationParameters)) {
6379 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6380 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6381 pPresentationParameters->BackBufferHeight);
6382 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6383 return WINED3DERR_INVALIDCALL;
6386 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6387 * on an existing gl context, so there's no real need for recreation.
6389 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6391 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6393 TRACE("New params:\n");
6394 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6395 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6396 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6397 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6398 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6399 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6400 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6401 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6402 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6403 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6404 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6405 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6406 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6408 /* No special treatment of these parameters. Just store them */
6409 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6410 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6411 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6412 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6414 /* What to do about these? */
6415 if (pPresentationParameters->BackBufferCount
6416 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6417 ERR("Cannot change the back buffer count yet\n");
6419 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6420 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6421 ERR("Cannot change the back buffer format yet\n");
6424 if (pPresentationParameters->hDeviceWindow
6425 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6426 ERR("Cannot change the device window yet\n");
6428 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6432 TRACE("Creating the depth stencil buffer\n");
6434 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6435 pPresentationParameters->BackBufferWidth,
6436 pPresentationParameters->BackBufferHeight,
6437 pPresentationParameters->AutoDepthStencilFormat,
6438 pPresentationParameters->MultiSampleType,
6439 pPresentationParameters->MultiSampleQuality,
6441 (IWineD3DSurface **)&This->auto_depth_stencil);
6444 ERR("Failed to create the depth stencil buffer\n");
6445 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6446 return WINED3DERR_INVALIDCALL;
6450 if (This->onscreen_depth_stencil)
6452 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6453 This->onscreen_depth_stencil = NULL;
6456 /* Reset the depth stencil */
6457 if (pPresentationParameters->EnableAutoDepthStencil)
6458 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6460 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6462 TRACE("Resetting stateblock\n");
6463 wined3d_stateblock_decref(This->updateStateBlock);
6464 wined3d_stateblock_decref(This->stateBlock);
6466 delete_opengl_contexts(This, swapchain);
6468 if(pPresentationParameters->Windowed) {
6469 mode.Width = swapchain->orig_width;
6470 mode.Height = swapchain->orig_height;
6471 mode.RefreshRate = 0;
6472 mode.Format = swapchain->presentParms.BackBufferFormat;
6474 mode.Width = pPresentationParameters->BackBufferWidth;
6475 mode.Height = pPresentationParameters->BackBufferHeight;
6476 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6477 mode.Format = swapchain->presentParms.BackBufferFormat;
6480 /* Should Width == 800 && Height == 0 set 800x600? */
6481 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6482 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6483 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6487 if(!pPresentationParameters->Windowed) {
6488 DisplayModeChanged = TRUE;
6490 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6491 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6493 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6496 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6500 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6502 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6505 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6509 if (This->auto_depth_stencil)
6511 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6514 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6520 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6521 || DisplayModeChanged)
6523 BOOL filter = This->filter_messages;
6524 This->filter_messages = TRUE;
6526 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6528 if (!pPresentationParameters->Windowed)
6530 if (swapchain->presentParms.Windowed)
6532 HWND focus_window = This->createParms.hFocusWindow;
6533 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6534 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6536 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6537 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6541 /* switch from windowed to fs */
6542 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6543 pPresentationParameters->BackBufferWidth,
6544 pPresentationParameters->BackBufferHeight);
6548 /* Fullscreen -> fullscreen mode change */
6549 MoveWindow(swapchain->device_window, 0, 0,
6550 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6554 else if (!swapchain->presentParms.Windowed)
6556 /* Fullscreen -> windowed switch */
6557 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6558 IWineD3DDevice_ReleaseFocusWindow(iface);
6560 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6562 This->filter_messages = filter;
6564 else if (!pPresentationParameters->Windowed)
6566 DWORD style = This->style, exStyle = This->exStyle;
6567 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6568 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6569 * Reset to clear up their mess. Guild Wars also loses the device during that.
6573 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6574 pPresentationParameters->BackBufferWidth,
6575 pPresentationParameters->BackBufferHeight);
6576 This->style = style;
6577 This->exStyle = exStyle;
6580 /* Note: No parent needed for initial internal stateblock */
6581 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6582 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6583 else TRACE("Created stateblock %p\n", This->stateBlock);
6584 This->updateStateBlock = This->stateBlock;
6585 wined3d_stateblock_incref(This->updateStateBlock);
6587 stateblock_init_default_state(This->stateBlock);
6589 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6592 GetClientRect(swapchain->win_handle, &client_rect);
6594 if(!swapchain->presentParms.BackBufferCount)
6596 TRACE("Single buffered rendering\n");
6597 swapchain->render_to_fbo = FALSE;
6599 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6600 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6602 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6603 swapchain->presentParms.BackBufferWidth,
6604 swapchain->presentParms.BackBufferHeight,
6605 client_rect.right, client_rect.bottom);
6606 swapchain->render_to_fbo = TRUE;
6610 TRACE("Rendering directly to GL_BACK\n");
6611 swapchain->render_to_fbo = FALSE;
6615 hr = create_primary_opengl_context(This, swapchain);
6616 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6618 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6624 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6626 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6628 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6634 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6636 TRACE("(%p) : pParameters %p\n", This, pParameters);
6638 *pParameters = This->createParms;
6642 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6643 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6645 IWineD3DSwapChain *swapchain;
6647 TRACE("Relaying to swapchain\n");
6649 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6651 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6652 IWineD3DSwapChain_Release(swapchain);
6656 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6657 IWineD3DSwapChain *swapchain;
6659 TRACE("Relaying to swapchain\n");
6661 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6662 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6663 IWineD3DSwapChain_Release(swapchain);
6667 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6669 TRACE("device %p, resource %p.\n", device, resource);
6671 list_add_head(&device->resources, &resource->resource_list_entry);
6674 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6676 TRACE("device %p, resource %p.\n", device, resource);
6678 list_remove(&resource->resource_list_entry);
6681 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6683 WINED3DRESOURCETYPE type = resource->resourceType;
6686 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6688 context_resource_released(device, resource, type);
6692 case WINED3DRTYPE_SURFACE:
6694 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6696 if (!device->d3d_initialized) break;
6698 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6700 if (device->render_targets[i] == surface)
6702 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6703 device->render_targets[i] = NULL;
6707 if (device->depth_stencil == surface)
6709 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6710 device->depth_stencil = NULL;
6715 case WINED3DRTYPE_TEXTURE:
6716 case WINED3DRTYPE_CUBETEXTURE:
6717 case WINED3DRTYPE_VOLUMETEXTURE:
6718 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6720 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6722 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6724 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6725 texture, device->stateBlock, i);
6726 device->stateBlock->state.textures[i] = NULL;
6729 if (device->updateStateBlock != device->stateBlock
6730 && device->updateStateBlock->state.textures[i] == texture)
6732 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6733 texture, device->updateStateBlock, i);
6734 device->updateStateBlock->state.textures[i] = NULL;
6739 case WINED3DRTYPE_BUFFER:
6741 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6743 for (i = 0; i < MAX_STREAMS; ++i)
6745 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6747 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6748 buffer, device->stateBlock, i);
6749 device->stateBlock->state.streams[i].buffer = NULL;
6752 if (device->updateStateBlock != device->stateBlock
6753 && device->updateStateBlock->state.streams[i].buffer == buffer)
6755 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6756 buffer, device->updateStateBlock, i);
6757 device->updateStateBlock->state.streams[i].buffer = NULL;
6762 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6764 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6765 buffer, device->stateBlock);
6766 device->stateBlock->state.index_buffer = NULL;
6769 if (device->updateStateBlock != device->stateBlock
6770 && device->updateStateBlock->state.index_buffer == buffer)
6772 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6773 buffer, device->updateStateBlock);
6774 device->updateStateBlock->state.index_buffer = NULL;
6783 /* Remove the resource from the resourceStore */
6784 device_resource_remove(device, resource);
6786 TRACE("Resource released.\n");
6789 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6790 D3DCB_ENUMRESOURCES callback, void *data)
6792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6793 struct wined3d_resource *resource, *cursor;
6795 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6797 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6799 TRACE("enumerating resource %p.\n", resource);
6800 if (callback(resource, data) == S_FALSE)
6802 TRACE("Canceling enumeration.\n");
6810 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6813 struct wined3d_resource *resource;
6815 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6817 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6819 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6823 TRACE("Found surface %p for dc %p.\n", s, dc);
6824 *surface = (IWineD3DSurface *)s;
6830 return WINED3DERR_INVALIDCALL;
6833 /**********************************************************
6834 * IWineD3DDevice VTbl follows
6835 **********************************************************/
6837 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6839 /*** IUnknown methods ***/
6840 IWineD3DDeviceImpl_QueryInterface,
6841 IWineD3DDeviceImpl_AddRef,
6842 IWineD3DDeviceImpl_Release,
6843 /*** IWineD3DDevice methods ***/
6844 /*** Creation methods**/
6845 IWineD3DDeviceImpl_CreateBuffer,
6846 IWineD3DDeviceImpl_CreateVertexBuffer,
6847 IWineD3DDeviceImpl_CreateIndexBuffer,
6848 IWineD3DDeviceImpl_CreateStateBlock,
6849 IWineD3DDeviceImpl_CreateSurface,
6850 IWineD3DDeviceImpl_CreateRendertargetView,
6851 IWineD3DDeviceImpl_CreateTexture,
6852 IWineD3DDeviceImpl_CreateVolumeTexture,
6853 IWineD3DDeviceImpl_CreateVolume,
6854 IWineD3DDeviceImpl_CreateCubeTexture,
6855 IWineD3DDeviceImpl_CreateQuery,
6856 IWineD3DDeviceImpl_CreateSwapChain,
6857 IWineD3DDeviceImpl_CreateVertexDeclaration,
6858 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6859 IWineD3DDeviceImpl_CreateVertexShader,
6860 IWineD3DDeviceImpl_CreateGeometryShader,
6861 IWineD3DDeviceImpl_CreatePixelShader,
6862 IWineD3DDeviceImpl_CreatePalette,
6863 /*** Odd functions **/
6864 IWineD3DDeviceImpl_Init3D,
6865 IWineD3DDeviceImpl_InitGDI,
6866 IWineD3DDeviceImpl_Uninit3D,
6867 IWineD3DDeviceImpl_UninitGDI,
6868 IWineD3DDeviceImpl_SetMultithreaded,
6869 IWineD3DDeviceImpl_EvictManagedResources,
6870 IWineD3DDeviceImpl_GetAvailableTextureMem,
6871 IWineD3DDeviceImpl_GetBackBuffer,
6872 IWineD3DDeviceImpl_GetCreationParameters,
6873 IWineD3DDeviceImpl_GetDeviceCaps,
6874 IWineD3DDeviceImpl_GetDirect3D,
6875 IWineD3DDeviceImpl_GetDisplayMode,
6876 IWineD3DDeviceImpl_SetDisplayMode,
6877 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6878 IWineD3DDeviceImpl_GetRasterStatus,
6879 IWineD3DDeviceImpl_GetSwapChain,
6880 IWineD3DDeviceImpl_Reset,
6881 IWineD3DDeviceImpl_SetDialogBoxMode,
6882 IWineD3DDeviceImpl_SetCursorProperties,
6883 IWineD3DDeviceImpl_SetCursorPosition,
6884 IWineD3DDeviceImpl_ShowCursor,
6885 /*** Getters and setters **/
6886 IWineD3DDeviceImpl_SetClipPlane,
6887 IWineD3DDeviceImpl_GetClipPlane,
6888 IWineD3DDeviceImpl_SetClipStatus,
6889 IWineD3DDeviceImpl_GetClipStatus,
6890 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6891 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6892 IWineD3DDeviceImpl_SetDepthStencilSurface,
6893 IWineD3DDeviceImpl_GetDepthStencilSurface,
6894 IWineD3DDeviceImpl_SetGammaRamp,
6895 IWineD3DDeviceImpl_GetGammaRamp,
6896 IWineD3DDeviceImpl_SetIndexBuffer,
6897 IWineD3DDeviceImpl_GetIndexBuffer,
6898 IWineD3DDeviceImpl_SetBaseVertexIndex,
6899 IWineD3DDeviceImpl_GetBaseVertexIndex,
6900 IWineD3DDeviceImpl_SetLight,
6901 IWineD3DDeviceImpl_GetLight,
6902 IWineD3DDeviceImpl_SetLightEnable,
6903 IWineD3DDeviceImpl_GetLightEnable,
6904 IWineD3DDeviceImpl_SetMaterial,
6905 IWineD3DDeviceImpl_GetMaterial,
6906 IWineD3DDeviceImpl_SetNPatchMode,
6907 IWineD3DDeviceImpl_GetNPatchMode,
6908 IWineD3DDeviceImpl_SetPaletteEntries,
6909 IWineD3DDeviceImpl_GetPaletteEntries,
6910 IWineD3DDeviceImpl_SetPixelShader,
6911 IWineD3DDeviceImpl_GetPixelShader,
6912 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6913 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6914 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6915 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6916 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6917 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6918 IWineD3DDeviceImpl_SetRenderState,
6919 IWineD3DDeviceImpl_GetRenderState,
6920 IWineD3DDeviceImpl_SetRenderTarget,
6921 IWineD3DDeviceImpl_GetRenderTarget,
6922 IWineD3DDeviceImpl_SetSamplerState,
6923 IWineD3DDeviceImpl_GetSamplerState,
6924 IWineD3DDeviceImpl_SetScissorRect,
6925 IWineD3DDeviceImpl_GetScissorRect,
6926 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6927 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6928 IWineD3DDeviceImpl_SetStreamSource,
6929 IWineD3DDeviceImpl_GetStreamSource,
6930 IWineD3DDeviceImpl_SetStreamSourceFreq,
6931 IWineD3DDeviceImpl_GetStreamSourceFreq,
6932 IWineD3DDeviceImpl_SetTexture,
6933 IWineD3DDeviceImpl_GetTexture,
6934 IWineD3DDeviceImpl_SetTextureStageState,
6935 IWineD3DDeviceImpl_GetTextureStageState,
6936 IWineD3DDeviceImpl_SetTransform,
6937 IWineD3DDeviceImpl_GetTransform,
6938 IWineD3DDeviceImpl_SetVertexDeclaration,
6939 IWineD3DDeviceImpl_GetVertexDeclaration,
6940 IWineD3DDeviceImpl_SetVertexShader,
6941 IWineD3DDeviceImpl_GetVertexShader,
6942 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6943 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6944 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6945 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6946 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6947 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6948 IWineD3DDeviceImpl_SetViewport,
6949 IWineD3DDeviceImpl_GetViewport,
6950 IWineD3DDeviceImpl_MultiplyTransform,
6951 IWineD3DDeviceImpl_ValidateDevice,
6952 IWineD3DDeviceImpl_ProcessVertices,
6953 /*** State block ***/
6954 IWineD3DDeviceImpl_BeginStateBlock,
6955 IWineD3DDeviceImpl_EndStateBlock,
6956 /*** Scene management ***/
6957 IWineD3DDeviceImpl_BeginScene,
6958 IWineD3DDeviceImpl_EndScene,
6959 IWineD3DDeviceImpl_Present,
6960 IWineD3DDeviceImpl_Clear,
6961 IWineD3DDeviceImpl_ClearRendertargetView,
6963 IWineD3DDeviceImpl_SetPrimitiveType,
6964 IWineD3DDeviceImpl_GetPrimitiveType,
6965 IWineD3DDeviceImpl_DrawPrimitive,
6966 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6967 IWineD3DDeviceImpl_DrawPrimitiveUP,
6968 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6969 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6970 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6971 IWineD3DDeviceImpl_DrawRectPatch,
6972 IWineD3DDeviceImpl_DrawTriPatch,
6973 IWineD3DDeviceImpl_DeletePatch,
6974 IWineD3DDeviceImpl_ColorFill,
6975 IWineD3DDeviceImpl_UpdateTexture,
6976 IWineD3DDeviceImpl_UpdateSurface,
6977 IWineD3DDeviceImpl_GetFrontBufferData,
6978 /*** object tracking ***/
6979 IWineD3DDeviceImpl_EnumResources,
6980 IWineD3DDeviceImpl_GetSurfaceFromDC,
6981 IWineD3DDeviceImpl_AcquireFocusWindow,
6982 IWineD3DDeviceImpl_ReleaseFocusWindow,
6983 IWineD3DDeviceImpl_SetupFullscreenWindow,
6984 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6987 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6988 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6989 IWineD3DDeviceParent *device_parent)
6991 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6992 const struct fragment_pipeline *fragment_pipeline;
6993 struct shader_caps shader_caps;
6994 struct fragment_caps ffp_caps;
6995 WINED3DDISPLAYMODE mode;
6999 device->lpVtbl = &IWineD3DDevice_Vtbl;
7001 device->wined3d = wined3d;
7002 wined3d_incref(device->wined3d);
7003 device->adapter = wined3d->adapter_count ? adapter : NULL;
7004 device->device_parent = device_parent;
7005 list_init(&device->resources);
7006 list_init(&device->shaders);
7008 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7010 /* Get the initial screen setup for ddraw. */
7011 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7014 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7015 wined3d_decref(device->wined3d);
7018 device->ddraw_width = mode.Width;
7019 device->ddraw_height = mode.Height;
7020 device->ddraw_format = mode.Format;
7022 /* Save the creation parameters. */
7023 device->createParms.AdapterOrdinal = adapter_idx;
7024 device->createParms.DeviceType = device_type;
7025 device->createParms.hFocusWindow = focus_window;
7026 device->createParms.BehaviorFlags = flags;
7028 device->devType = device_type;
7029 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7031 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7032 device->shader_backend = adapter->shader_backend;
7034 if (device->shader_backend)
7036 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7037 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7038 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7039 device->vs_clipping = shader_caps.VSClipping;
7041 fragment_pipeline = adapter->fragment_pipe;
7042 device->frag_pipe = fragment_pipeline;
7043 if (fragment_pipeline)
7045 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7046 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7048 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7049 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7052 ERR("Failed to compile state table, hr %#x.\n", hr);
7053 wined3d_decref(device->wined3d);
7057 device->blitter = adapter->blitter;
7063 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7064 DWORD rep = This->StateTable[state].representative;
7065 struct wined3d_context *context;
7070 for(i = 0; i < This->numContexts; i++) {
7071 context = This->contexts[i];
7072 if(isStateDirty(context, rep)) continue;
7074 context->dirtyArray[context->numDirtyEntries++] = rep;
7075 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7076 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7077 context->isStateDirty[idx] |= (1 << shift);
7081 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7083 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7084 *width = context->current_rt->pow2Width;
7085 *height = context->current_rt->pow2Height;
7088 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7090 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7091 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7092 * current context's drawable, which is the size of the back buffer of the swapchain
7093 * the active context belongs to. */
7094 *width = swapchain->presentParms.BackBufferWidth;
7095 *height = swapchain->presentParms.BackBufferHeight;
7098 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7099 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7101 if (device->filter_messages)
7103 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7104 window, message, wparam, lparam);
7106 return DefWindowProcW(window, message, wparam, lparam);
7108 return DefWindowProcA(window, message, wparam, lparam);
7111 if (message == WM_DESTROY)
7113 TRACE("unregister window %p.\n", window);
7114 wined3d_unregister_window(window);
7116 if (device->focus_window == window) device->focus_window = NULL;
7117 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7121 return CallWindowProcW(proc, window, message, wparam, lparam);
7123 return CallWindowProcA(proc, window, message, wparam, lparam);