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,
508 sizeof(*new_array) * (device->context_count + 1));
512 ERR("Failed to grow the context array.\n");
516 new_array[device->context_count++] = context;
517 device->contexts = new_array;
521 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
523 struct wined3d_context **new_array;
527 TRACE("Removing context %p.\n", context);
529 for (i = 0; i < device->context_count; ++i)
531 if (device->contexts[i] == context)
540 ERR("Context %p doesn't exist in context array.\n", context);
544 if (!--device->context_count)
546 HeapFree(GetProcessHeap(), 0, device->contexts);
547 device->contexts = NULL;
551 memmove(&device->contexts[i], &device->contexts[i + 1], (device->context_count - i) * sizeof(*device->contexts));
552 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->context_count * sizeof(*device->contexts));
555 ERR("Failed to shrink context array. Oh well.\n");
559 device->contexts = new_array;
562 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
564 struct wined3d_stateblock *stateblock = device->stateBlock;
565 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
567 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
569 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
571 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
575 /* Do not call while under the GL lock. */
576 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
577 struct wined3d_context *context, struct wined3d_surface *depth_stencil)
579 if (device->onscreen_depth_stencil)
581 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
582 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
583 device->onscreen_depth_stencil->ds_current_size.cx,
584 device->onscreen_depth_stencil->ds_current_size.cy);
585 wined3d_surface_decref(device->onscreen_depth_stencil);
587 device->onscreen_depth_stencil = depth_stencil;
588 wined3d_surface_incref(device->onscreen_depth_stencil);
591 static BOOL is_full_clear(struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect)
593 /* partial draw rect */
594 if (draw_rect->left || draw_rect->top
595 || draw_rect->right < target->resource.width
596 || draw_rect->bottom < target->resource.height)
599 /* partial clear rect */
600 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
601 || clear_rect->right < target->resource.width
602 || clear_rect->bottom < target->resource.height))
608 static void prepare_ds_clear(struct wined3d_surface *ds, struct wined3d_context *context,
609 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
611 RECT current_rect, r;
613 if (ds->flags & location)
614 SetRect(¤t_rect, 0, 0,
615 ds->ds_current_size.cx,
616 ds->ds_current_size.cy);
618 SetRectEmpty(¤t_rect);
620 IntersectRect(&r, draw_rect, ¤t_rect);
621 if (EqualRect(&r, draw_rect))
623 /* current_rect ⊇ draw_rect, modify only. */
624 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
628 if (EqualRect(&r, ¤t_rect))
630 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
634 /* Full clear, modify only. */
635 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
639 IntersectRect(&r, draw_rect, clear_rect);
640 if (EqualRect(&r, draw_rect))
642 /* clear_rect ⊇ draw_rect, modify only. */
643 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
649 surface_load_ds_location(ds, context, location);
650 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
653 /* Do not call while under the GL lock. */
654 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, struct wined3d_surface **rts,
655 struct wined3d_surface *depth_stencil, UINT rect_count, const RECT *rects, const RECT *draw_rect,
656 DWORD flags, const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
658 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
659 struct wined3d_surface *target = rt_count ? rts[0] : NULL;
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
663 BOOL render_offscreen;
666 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
667 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
668 * for the cleared parts, and the untouched parts.
670 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
671 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
672 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
673 * checking all this if the dest surface is in the drawable anyway. */
674 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
676 for (i = 0; i < rt_count; ++i)
678 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
682 context = context_acquire(device, target);
685 context_release(context);
686 WARN("Invalid context, skipping clear.\n");
690 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
692 context_release(context);
693 WARN("Failed to apply clear state, skipping clear.\n");
699 render_offscreen = context->render_offscreen;
700 target->get_drawable_size(context, &drawable_width, &drawable_height);
704 render_offscreen = TRUE;
705 drawable_width = depth_stencil->pow2Width;
706 drawable_height = depth_stencil->pow2Height;
711 /* Only set the values up once, as they are not changing. */
712 if (flags & WINED3DCLEAR_STENCIL)
714 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
716 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
717 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
720 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
721 glClearStencil(stencil);
722 checkGLcall("glClearStencil");
723 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
726 if (flags & WINED3DCLEAR_ZBUFFER)
728 DWORD location = render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
730 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
733 device_switch_onscreen_ds(device, context, depth_stencil);
736 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
737 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
739 glDepthMask(GL_TRUE);
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
742 checkGLcall("glClearDepth");
743 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
746 if (flags & WINED3DCLEAR_TARGET)
748 for (i = 0; i < rt_count; ++i)
750 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
753 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
754 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
755 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
756 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
757 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
758 glClearColor(color->r, color->g, color->b, color->a);
759 checkGLcall("glClearColor");
760 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
765 if (render_offscreen)
767 glScissor(draw_rect->left, draw_rect->top,
768 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
772 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
773 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
775 checkGLcall("glScissor");
777 checkGLcall("glClear");
783 /* Now process each rect in turn. */
784 for (i = 0; i < rect_count; ++i)
786 /* Note that GL uses lower left, width/height. */
787 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
789 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
790 wine_dbgstr_rect(&clear_rect[i]),
791 wine_dbgstr_rect(¤t_rect));
793 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
794 * The rectangle is not cleared, no error is returned, but further rectanlges are
795 * still cleared if they are valid. */
796 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
798 TRACE("Rectangle with negative dimensions, ignoring.\n");
802 if (render_offscreen)
804 glScissor(current_rect.left, current_rect.top,
805 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
809 glScissor(current_rect.left, drawable_height - current_rect.bottom,
810 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
812 checkGLcall("glScissor");
815 checkGLcall("glClear");
821 if (wined3d_settings.strict_draw_ordering || (flags & WINED3DCLEAR_TARGET
822 && target->container.type == WINED3D_CONTAINER_SWAPCHAIN
823 && target->container.u.swapchain->front_buffer == target))
824 wglFlush(); /* Flush to ensure ordering across contexts. */
826 context_release(context);
831 ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
833 ULONG refcount = InterlockedIncrement(&device->ref);
835 TRACE("%p increasing refcount to %u.\n", device, refcount);
840 ULONG CDECL wined3d_device_decref(struct wined3d_device *device)
842 ULONG refcount = InterlockedDecrement(&device->ref);
844 TRACE("%p decreasing refcount to %u.\n", device, refcount);
850 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
852 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
853 device->multistate_funcs[i] = NULL;
856 if (!list_empty(&device->resources))
858 struct wined3d_resource *resource;
860 FIXME("Device released with resources still bound, acceptable but unexpected.\n");
862 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
864 FIXME("Leftover resource %p with type %s (%#x).\n",
865 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
869 if (device->contexts)
870 ERR("Context array not freed!\n");
871 if (device->hardwareCursor)
872 DestroyCursor(device->hardwareCursor);
873 device->haveHardwareCursor = FALSE;
875 wined3d_decref(device->wined3d);
876 device->wined3d = NULL;
877 HeapFree(GetProcessHeap(), 0, device);
878 TRACE("Freed device %p.\n", device);
884 UINT CDECL wined3d_device_get_swapchain_count(struct wined3d_device *device)
886 TRACE("device %p.\n", device);
888 return device->swapchain_count;
891 HRESULT CDECL wined3d_device_get_swapchain(IWineD3DDevice *iface,
892 UINT swapchain_idx, struct wined3d_swapchain **swapchain)
894 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
896 TRACE("iface %p, swapchain_idx %u, swapchain %p.\n",
897 iface, swapchain_idx, swapchain);
899 if (swapchain_idx >= device->swapchain_count)
901 WARN("swapchain_idx %u >= swapchain_count %u.\n",
902 swapchain_idx, device->swapchain_count);
905 return WINED3DERR_INVALIDCALL;
908 *swapchain = device->swapchains[swapchain_idx];
909 wined3d_swapchain_incref(*swapchain);
910 TRACE("Returning %p.\n", *swapchain);
915 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
919 HDC dcb = NULL, dcs = NULL;
920 WINEDDCOLORKEY colorkey;
922 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
925 GetObjectA(hbm, sizeof(BITMAP), &bm);
926 dcb = CreateCompatibleDC(NULL);
928 SelectObject(dcb, hbm);
932 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
935 memset(&bm, 0, sizeof(bm));
940 hr = wined3d_surface_create((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
941 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
942 &wined3d_null_parent_ops, &This->logo_surface);
945 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
951 if (FAILED(hr = wined3d_surface_getdc(This->logo_surface, &dcs)))
953 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
954 wined3d_surface_releasedc(This->logo_surface, dcs);
956 colorkey.dwColorSpaceLowValue = 0;
957 colorkey.dwColorSpaceHighValue = 0;
958 wined3d_surface_set_color_key(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
962 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
963 /* Fill the surface with a white color to show that wined3d is there */
964 wined3d_device_color_fill(This, This->logo_surface, NULL, &c);
968 if (dcb) DeleteDC(dcb);
969 if (hbm) DeleteObject(hbm);
972 /* Context activation is done by the caller. */
973 static void create_dummy_textures(IWineD3DDeviceImpl *This)
975 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
977 /* Under DirectX you can have texture stage operations even if no texture is
978 bound, whereas opengl will only do texture operations when a valid texture is
979 bound. We emulate this by creating dummy textures and binding them to each
980 texture stage, but disable all stages by default. Hence if a stage is enabled
981 then the default texture will kick in until replaced by a SetTexture call */
984 if (gl_info->supported[APPLE_CLIENT_STORAGE])
986 /* The dummy texture does not have client storage backing */
987 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
988 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
991 for (i = 0; i < gl_info->limits.textures; ++i)
995 /* Make appropriate texture active */
996 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
997 checkGLcall("glActiveTextureARB");
999 /* Generate an opengl texture name */
1000 glGenTextures(1, &This->dummyTextureName[i]);
1001 checkGLcall("glGenTextures");
1002 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1004 /* Generate a dummy 2d texture (not using 1d because they cause many
1005 * DRI drivers fall back to sw) */
1006 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1007 checkGLcall("glBindTexture");
1009 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1010 checkGLcall("glTexImage2D");
1013 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1015 /* Reenable because if supported it is enabled by default */
1016 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1017 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1023 /* Context activation is done by the caller. */
1024 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1027 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1028 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1031 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1034 static LONG fullscreen_style(LONG style)
1036 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1037 style |= WS_POPUP | WS_SYSMENU;
1038 style &= ~(WS_CAPTION | WS_THICKFRAME);
1043 static LONG fullscreen_exstyle(LONG exstyle)
1045 /* Filter out window decorations. */
1046 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1051 void CDECL wined3d_device_setup_fullscreen_window(struct wined3d_device *device, HWND window, UINT w, UINT h)
1053 BOOL filter_messages;
1054 LONG style, exstyle;
1056 TRACE("Setting up window %p for fullscreen mode.\n", window);
1058 if (device->style || device->exStyle)
1060 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1061 window, device->style, device->exStyle);
1064 device->style = GetWindowLongW(window, GWL_STYLE);
1065 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1067 style = fullscreen_style(device->style);
1068 exstyle = fullscreen_exstyle(device->exStyle);
1070 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1071 device->style, device->exStyle, style, exstyle);
1073 filter_messages = device->filter_messages;
1074 device->filter_messages = TRUE;
1076 SetWindowLongW(window, GWL_STYLE, style);
1077 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1078 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1080 device->filter_messages = filter_messages;
1083 void CDECL wined3d_device_restore_fullscreen_window(struct wined3d_device *device, HWND window)
1085 BOOL filter_messages;
1086 LONG style, exstyle;
1088 if (!device->style && !device->exStyle) return;
1090 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1091 window, device->style, device->exStyle);
1093 style = GetWindowLongW(window, GWL_STYLE);
1094 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1096 filter_messages = device->filter_messages;
1097 device->filter_messages = TRUE;
1099 /* Only restore the style if the application didn't modify it during the
1100 * fullscreen phase. Some applications change it before calling Reset()
1101 * when switching between windowed and fullscreen modes (HL2), some
1102 * depend on the original style (Eve Online). */
1103 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1105 SetWindowLongW(window, GWL_STYLE, device->style);
1106 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1108 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1110 device->filter_messages = filter_messages;
1112 /* Delete the old values. */
1114 device->exStyle = 0;
1117 HRESULT CDECL wined3d_device_acquire_focus_window(struct wined3d_device *device, HWND window)
1119 TRACE("device %p, window %p.\n", device, window);
1121 if (!wined3d_register_window(window, device))
1123 ERR("Failed to register window %p.\n", window);
1127 device->focus_window = window;
1128 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1133 void CDECL wined3d_device_release_focus_window(struct wined3d_device *device)
1135 TRACE("device %p.\n", device);
1137 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1138 device->focus_window = NULL;
1141 HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device,
1142 WINED3DPRESENT_PARAMETERS *present_parameters)
1144 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1145 struct wined3d_swapchain *swapchain = NULL;
1146 struct wined3d_context *context;
1151 TRACE("device %p, present_parameters %p.\n", device, present_parameters);
1153 if (device->d3d_initialized)
1154 return WINED3DERR_INVALIDCALL;
1155 if (!device->adapter->opengl)
1156 return WINED3DERR_INVALIDCALL;
1158 TRACE("Creating stateblock.\n");
1159 hr = wined3d_stateblock_create(device, WINED3DSBT_INIT, &device->stateBlock);
1162 WARN("Failed to create stateblock\n");
1166 TRACE("Created stateblock %p.\n", device->stateBlock);
1167 device->updateStateBlock = device->stateBlock;
1168 wined3d_stateblock_incref(device->updateStateBlock);
1170 device->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1171 sizeof(*device->render_targets) * gl_info->limits.buffers);
1173 device->palette_count = 1;
1174 device->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1175 if (!device->palettes || !device->render_targets)
1177 ERR("Out of memory!\n");
1182 device->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1183 if (!device->palettes[0])
1185 ERR("Out of memory!\n");
1190 for (i = 0; i < 256; ++i)
1192 device->palettes[0][i].peRed = 0xff;
1193 device->palettes[0][i].peGreen = 0xff;
1194 device->palettes[0][i].peBlue = 0xff;
1195 device->palettes[0][i].peFlags = 0xff;
1197 device->currentPalette = 0;
1199 /* Initialize the texture unit mapping to a 1:1 mapping */
1200 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1202 if (state < gl_info->limits.fragment_samplers)
1204 device->texUnitMap[state] = state;
1205 device->rev_tex_unit_map[state] = state;
1209 device->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1210 device->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1214 /* Setup the implicit swapchain. This also initializes a context. */
1215 TRACE("Creating implicit swapchain\n");
1216 hr = IWineD3DDeviceParent_CreateSwapChain(device->device_parent,
1217 present_parameters, &swapchain);
1220 WARN("Failed to create implicit swapchain\n");
1224 device->swapchain_count = 1;
1225 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1226 if (!device->swapchains)
1228 ERR("Out of memory!\n");
1231 device->swapchains[0] = swapchain;
1233 if (swapchain->back_buffers && swapchain->back_buffers[0])
1235 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1236 device->render_targets[0] = swapchain->back_buffers[0];
1240 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1241 device->render_targets[0] = swapchain->front_buffer;
1243 wined3d_surface_incref(device->render_targets[0]);
1245 /* Depth Stencil support */
1246 device->depth_stencil = device->auto_depth_stencil;
1247 if (device->depth_stencil)
1248 wined3d_surface_incref(device->depth_stencil);
1250 hr = device->shader_backend->shader_alloc_private(device);
1253 TRACE("Shader private data couldn't be allocated\n");
1256 hr = device->frag_pipe->alloc_private(device);
1259 TRACE("Fragment pipeline private data couldn't be allocated\n");
1262 hr = device->blitter->alloc_private(device);
1265 TRACE("Blitter private data couldn't be allocated\n");
1269 /* Set up some starting GL setup */
1271 /* Setup all the devices defaults */
1272 stateblock_init_default_state(device->stateBlock);
1274 context = context_acquire(device, swapchain->front_buffer);
1276 create_dummy_textures(device);
1280 /* Initialize the current view state */
1281 device->view_ident = 1;
1282 device->contexts[0]->last_was_rhw = 0;
1283 glGetIntegerv(GL_MAX_LIGHTS, &device->maxConcurrentLights);
1284 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &device->maxConcurrentLights)");
1286 switch (wined3d_settings.offscreen_rendering_mode)
1289 device->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1292 case ORM_BACKBUFFER:
1294 if (context_get_current()->aux_buffers > 0)
1296 TRACE("Using auxilliary buffer for offscreen rendering\n");
1297 device->offscreenBuffer = GL_AUX0;
1301 TRACE("Using back buffer for offscreen rendering\n");
1302 device->offscreenBuffer = GL_BACK;
1307 TRACE("All defaults now set up, leaving 3D init.\n");
1310 context_release(context);
1312 /* Clear the screen */
1313 wined3d_device_clear(device, 0, NULL, WINED3DCLEAR_TARGET
1314 | (present_parameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0),
1317 device->d3d_initialized = TRUE;
1319 if (wined3d_settings.logo)
1320 IWineD3DDeviceImpl_LoadLogo(device, wined3d_settings.logo);
1321 device->highest_dirty_ps_const = 0;
1322 device->highest_dirty_vs_const = 0;
1326 HeapFree(GetProcessHeap(), 0, device->render_targets);
1327 HeapFree(GetProcessHeap(), 0, device->swapchains);
1328 device->swapchain_count = 0;
1329 if (device->palettes)
1331 HeapFree(GetProcessHeap(), 0, device->palettes[0]);
1332 HeapFree(GetProcessHeap(), 0, device->palettes);
1334 device->palette_count = 0;
1336 wined3d_swapchain_decref(swapchain);
1337 if (device->stateBlock)
1339 wined3d_stateblock_decref(device->stateBlock);
1340 device->stateBlock = NULL;
1342 if (device->blit_priv)
1343 device->blitter->free_private(device);
1344 if (device->fragment_priv)
1345 device->frag_pipe->free_private(device);
1346 if (device->shader_priv)
1347 device->shader_backend->shader_free_private(device);
1352 HRESULT CDECL wined3d_device_init_gdi(struct wined3d_device *device,
1353 WINED3DPRESENT_PARAMETERS *present_parameters)
1355 struct wined3d_swapchain *swapchain = NULL;
1358 TRACE("device %p, present_parameters %p.\n", device, present_parameters);
1360 /* Setup the implicit swapchain */
1361 TRACE("Creating implicit swapchain\n");
1362 hr = IWineD3DDeviceParent_CreateSwapChain(device->device_parent,
1363 present_parameters, &swapchain);
1366 WARN("Failed to create implicit swapchain\n");
1370 device->swapchain_count = 1;
1371 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1372 if (!device->swapchains)
1374 ERR("Out of memory!\n");
1377 device->swapchains[0] = swapchain;
1381 wined3d_swapchain_decref(swapchain);
1385 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
1387 TRACE("Unloading resource %p.\n", resource);
1389 resource->resource_ops->resource_unload(resource);
1394 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
1396 const struct wined3d_gl_info *gl_info;
1397 struct wined3d_context *context;
1398 struct wined3d_surface *surface;
1401 TRACE("device %p.\n", device);
1403 if (!device->d3d_initialized)
1404 return WINED3DERR_INVALIDCALL;
1406 /* Force making the context current again, to verify it is still valid
1407 * (workaround for broken drivers) */
1408 context_set_current(NULL);
1409 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1410 * it was created. Thus make sure a context is active for the glDelete* calls
1412 context = context_acquire(device, NULL);
1413 gl_info = context->gl_info;
1415 if (device->logo_surface)
1416 wined3d_surface_decref(device->logo_surface);
1418 /* Unload resources */
1419 wined3d_device_enum_resources(device, device_unload_resource, NULL);
1421 TRACE("Deleting high order patches\n");
1422 for(i = 0; i < PATCHMAP_SIZE; i++) {
1423 struct list *e1, *e2;
1424 struct WineD3DRectPatch *patch;
1425 LIST_FOR_EACH_SAFE(e1, e2, &device->patches[i])
1427 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1428 wined3d_device_delete_patch(device, patch->Handle);
1432 /* Delete the mouse cursor texture */
1433 if (device->cursorTexture)
1436 glDeleteTextures(1, &device->cursorTexture);
1438 device->cursorTexture = 0;
1441 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1442 * private data, it might contain opengl pointers
1444 if (device->depth_blt_texture)
1447 glDeleteTextures(1, &device->depth_blt_texture);
1449 device->depth_blt_texture = 0;
1451 if (device->depth_blt_rb)
1454 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
1456 device->depth_blt_rb = 0;
1457 device->depth_blt_rb_w = 0;
1458 device->depth_blt_rb_h = 0;
1461 /* Release the update stateblock */
1462 if (wined3d_stateblock_decref(device->updateStateBlock))
1464 if (device->updateStateBlock != device->stateBlock)
1465 FIXME("Something's still holding the update stateblock.\n");
1467 device->updateStateBlock = NULL;
1470 struct wined3d_stateblock *stateblock = device->stateBlock;
1471 device->stateBlock = NULL;
1473 /* Release the stateblock */
1474 if (wined3d_stateblock_decref(stateblock))
1475 FIXME("Something's still holding the stateblock.\n");
1478 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1479 device->blitter->free_private(device);
1480 device->frag_pipe->free_private(device);
1481 device->shader_backend->shader_free_private(device);
1483 /* Release the buffers (with sanity checks)*/
1484 if (device->onscreen_depth_stencil)
1486 surface = device->onscreen_depth_stencil;
1487 device->onscreen_depth_stencil = NULL;
1488 wined3d_surface_decref(surface);
1491 if (device->depth_stencil)
1493 surface = device->depth_stencil;
1495 TRACE("Releasing depth/stencil buffer %p.\n", surface);
1497 device->depth_stencil = NULL;
1498 if (wined3d_surface_decref(surface)
1499 && surface != device->auto_depth_stencil)
1500 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
1503 if (device->auto_depth_stencil)
1505 surface = device->auto_depth_stencil;
1506 device->auto_depth_stencil = NULL;
1507 if (wined3d_surface_decref(surface))
1508 FIXME("Something's still holding the auto depth stencil buffer (%p).\n", surface);
1511 for (i = 1; i < gl_info->limits.buffers; ++i)
1513 wined3d_device_set_render_target(device, i, NULL, FALSE);
1516 surface = device->render_targets[0];
1517 TRACE("Setting rendertarget 0 to NULL\n");
1518 device->render_targets[0] = NULL;
1519 TRACE("Releasing the render target at %p\n", surface);
1520 wined3d_surface_decref(surface);
1522 context_release(context);
1524 for (i = 0; i < device->swapchain_count; ++i)
1526 TRACE("Releasing the implicit swapchain %u.\n", i);
1527 if (wined3d_swapchain_decref(device->swapchains[i]))
1528 FIXME("Something's still holding the implicit swapchain.\n");
1531 HeapFree(GetProcessHeap(), 0, device->swapchains);
1532 device->swapchains = NULL;
1533 device->swapchain_count = 0;
1535 for (i = 0; i < device->palette_count; ++i)
1536 HeapFree(GetProcessHeap(), 0, device->palettes[i]);
1537 HeapFree(GetProcessHeap(), 0, device->palettes);
1538 device->palettes = NULL;
1539 device->palette_count = 0;
1541 HeapFree(GetProcessHeap(), 0, device->render_targets);
1542 device->render_targets = NULL;
1544 device->d3d_initialized = FALSE;
1549 HRESULT CDECL wined3d_device_uninit_gdi(IWineD3DDevice *iface)
1551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1554 for (i = 0; i < This->swapchain_count; ++i)
1556 TRACE("Releasing the implicit swapchain %u.\n", i);
1557 if (wined3d_swapchain_decref(This->swapchains[i]))
1558 FIXME("Something's still holding the implicit swapchain.\n");
1561 HeapFree(GetProcessHeap(), 0, This->swapchains);
1562 This->swapchains = NULL;
1563 This->swapchain_count = 0;
1567 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1568 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1569 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1571 * There is no way to deactivate thread safety once it is enabled.
1573 void CDECL wined3d_device_set_multithreaded(struct wined3d_device *device)
1575 TRACE("device %p.\n", device);
1577 /* For now just store the flag (needed in case of ddraw). */
1578 device->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1581 HRESULT CDECL wined3d_device_set_display_mode(IWineD3DDevice *iface, UINT iSwapChain,
1582 const WINED3DDISPLAYMODE* pMode)
1585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1586 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
1590 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1592 /* Resize the screen even without a window:
1593 * The app could have unset it with SetCooperativeLevel, but not called
1594 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1595 * but we don't have any hwnd
1598 memset(&devmode, 0, sizeof(devmode));
1599 devmode.dmSize = sizeof(devmode);
1600 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1601 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
1602 devmode.dmPelsWidth = pMode->Width;
1603 devmode.dmPelsHeight = pMode->Height;
1605 devmode.dmDisplayFrequency = pMode->RefreshRate;
1606 if (pMode->RefreshRate)
1607 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1609 /* Only change the mode if necessary */
1610 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
1611 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
1614 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1615 if (ret != DISP_CHANGE_SUCCESSFUL)
1617 if (devmode.dmDisplayFrequency)
1619 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1620 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1621 devmode.dmDisplayFrequency = 0;
1622 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1624 if(ret != DISP_CHANGE_SUCCESSFUL) {
1625 return WINED3DERR_NOTAVAILABLE;
1629 /* Store the new values */
1630 This->ddraw_width = pMode->Width;
1631 This->ddraw_height = pMode->Height;
1632 This->ddraw_format = pMode->Format;
1634 /* And finally clip mouse to our screen */
1635 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1636 ClipCursor(&clip_rc);
1641 HRESULT CDECL wined3d_device_get_wined3d(IWineD3DDevice *iface, struct wined3d **wined3d)
1643 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1645 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
1647 *wined3d = device->wined3d;
1648 wined3d_incref(*wined3d);
1650 TRACE("Returning %p.\n", *wined3d);
1655 UINT CDECL wined3d_device_get_available_texture_mem(IWineD3DDevice *iface)
1657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1659 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1660 (This->adapter->TextureRam/(1024*1024)),
1661 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1662 /* return simulated texture memory left */
1663 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1666 HRESULT CDECL wined3d_device_set_stream_source(IWineD3DDevice *iface, UINT stream_idx,
1667 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1669 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1670 struct wined3d_stream_state *stream;
1671 struct wined3d_buffer *prev_buffer;
1673 TRACE("device %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
1674 device, stream_idx, buffer, offset, stride);
1676 if (stream_idx >= MAX_STREAMS)
1678 WARN("Stream index %u out of range.\n", stream_idx);
1679 return WINED3DERR_INVALIDCALL;
1681 else if (offset & 0x3)
1683 WARN("Offset %u is not 4 byte aligned.\n", offset);
1684 return WINED3DERR_INVALIDCALL;
1687 stream = &device->updateStateBlock->state.streams[stream_idx];
1688 prev_buffer = stream->buffer;
1690 device->updateStateBlock->changed.streamSource |= 1 << stream_idx;
1692 if (prev_buffer == buffer
1693 && stream->stride == stride
1694 && stream->offset == offset)
1696 TRACE("Application is setting the old values over, nothing to do.\n");
1700 stream->buffer = buffer;
1703 stream->stride = stride;
1704 stream->offset = offset;
1707 /* Handle recording of state blocks. */
1708 if (device->isRecordingState)
1710 TRACE("Recording... not performing anything.\n");
1712 wined3d_buffer_incref(buffer);
1714 wined3d_buffer_decref(prev_buffer);
1720 InterlockedIncrement(&buffer->bind_count);
1721 wined3d_buffer_incref(buffer);
1725 InterlockedDecrement(&prev_buffer->bind_count);
1726 wined3d_buffer_decref(prev_buffer);
1729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC);
1734 HRESULT CDECL wined3d_device_get_stream_source(IWineD3DDevice *iface,
1735 UINT stream_idx, struct wined3d_buffer **buffer, UINT *offset, UINT *stride)
1737 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1738 struct wined3d_stream_state *stream;
1740 TRACE("device %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
1741 device, stream_idx, buffer, offset, stride);
1743 if (stream_idx >= MAX_STREAMS)
1745 WARN("Stream index %u out of range.\n", stream_idx);
1746 return WINED3DERR_INVALIDCALL;
1749 stream = &device->stateBlock->state.streams[stream_idx];
1750 *buffer = stream->buffer;
1752 wined3d_buffer_incref(*buffer);
1754 *offset = stream->offset;
1755 *stride = stream->stride;
1760 HRESULT CDECL wined3d_device_set_stream_source_freq(IWineD3DDevice *iface, UINT stream_idx, UINT divider)
1762 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1763 struct wined3d_stream_state *stream;
1764 UINT old_flags, old_freq;
1766 TRACE("device %p, stream_idx %u, divider %#x.\n", device, stream_idx, divider);
1768 /* Verify input. At least in d3d9 this is invalid. */
1769 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
1771 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL.\n");
1772 return WINED3DERR_INVALIDCALL;
1774 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !stream_idx)
1776 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL.\n");
1777 return WINED3DERR_INVALIDCALL;
1781 WARN("Divider is 0, returning D3DERR_INVALIDCALL.\n");
1782 return WINED3DERR_INVALIDCALL;
1785 stream = &device->updateStateBlock->state.streams[stream_idx];
1786 old_flags = stream->flags;
1787 old_freq = stream->frequency;
1789 stream->flags = divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
1790 stream->frequency = divider & 0x7fffff;
1792 device->updateStateBlock->changed.streamFreq |= 1 << stream_idx;
1794 if (stream->frequency != old_freq || stream->flags != old_flags)
1795 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC);
1800 HRESULT CDECL wined3d_device_get_stream_source_freq(IWineD3DDevice *iface, UINT stream_idx, UINT *divider)
1802 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1803 struct wined3d_stream_state *stream;
1805 TRACE("device %p, stream_idx %u, divider %p.\n", device, stream_idx, divider);
1807 stream = &device->updateStateBlock->state.streams[stream_idx];
1808 *divider = stream->flags | stream->frequency;
1810 TRACE("Returning %#x.\n", *divider);
1815 HRESULT CDECL wined3d_device_set_transform(IWineD3DDevice *iface,
1816 WINED3DTRANSFORMSTATETYPE d3dts, const WINED3DMATRIX *matrix)
1818 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1820 TRACE("device %p, state %s, matrix %p.\n",
1821 device, debug_d3dtstype(d3dts), matrix);
1823 /* Handle recording of state blocks. */
1824 if (device->isRecordingState)
1826 TRACE("Recording... not performing anything.\n");
1827 device->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1828 device->updateStateBlock->state.transforms[d3dts] = *matrix;
1832 /* If the new matrix is the same as the current one,
1833 * we cut off any further processing. this seems to be a reasonable
1834 * optimization because as was noticed, some apps (warcraft3 for example)
1835 * tend towards setting the same matrix repeatedly for some reason.
1837 * From here on we assume that the new matrix is different, wherever it matters. */
1838 if (!memcmp(&device->stateBlock->state.transforms[d3dts].u.m[0][0], matrix, sizeof(*matrix)))
1840 TRACE("The application is setting the same matrix over again.\n");
1844 conv_mat(matrix, &device->stateBlock->state.transforms[d3dts].u.m[0][0]);
1846 /* ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
1847 * where ViewMat = Camera space, WorldMat = world space.
1849 * In OpenGL, camera and world space is combined into GL_MODELVIEW
1850 * matrix. The Projection matrix stay projection matrix. */
1852 if (d3dts == WINED3DTS_VIEW)
1853 device->view_ident = !memcmp(matrix, identity, 16 * sizeof(float));
1855 if (d3dts < WINED3DTS_WORLDMATRIX(device->adapter->gl_info.limits.blends))
1856 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TRANSFORM(d3dts));
1862 HRESULT CDECL wined3d_device_get_transform(IWineD3DDevice *iface,
1863 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
1865 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1867 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1869 *matrix = device->stateBlock->state.transforms[state];
1874 HRESULT CDECL wined3d_device_multiply_transform(IWineD3DDevice *iface,
1875 WINED3DTRANSFORMSTATETYPE State, const WINED3DMATRIX *pMatrix)
1877 const WINED3DMATRIX *mat = NULL;
1880 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
1881 * below means it will be recorded in a state block change, but it
1882 * works regardless where it is recorded.
1883 * If this is found to be wrong, change to StateBlock.
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
1888 if (State <= HIGHEST_TRANSFORMSTATE)
1890 mat = &This->updateStateBlock->state.transforms[State];
1894 FIXME("Unhandled transform state!!\n");
1897 multiply_matrix(&temp, mat, pMatrix);
1899 /* Apply change via set transform - will reapply to eg. lights this way. */
1900 return wined3d_device_set_transform(iface, State, &temp);
1903 /* Note lights are real special cases. Although the device caps state only
1904 * e.g. 8 are supported, you can reference any indexes you want as long as
1905 * that number max are enabled at any one point in time. Therefore since the
1906 * indices can be anything, we need a hashmap of them. However, this causes
1907 * stateblock problems. When capturing the state block, I duplicate the
1908 * hashmap, but when recording, just build a chain pretty much of commands to
1910 HRESULT CDECL wined3d_device_set_light(IWineD3DDevice *iface, DWORD light_idx, CONST WINED3DLIGHT *light)
1912 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1913 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1914 struct wined3d_light_info *object = NULL;
1918 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1920 /* Check the parameter range. Need for speed most wanted sets junk lights
1921 * which confuse the GL driver. */
1923 return WINED3DERR_INVALIDCALL;
1925 switch (light->Type)
1927 case WINED3DLIGHT_POINT:
1928 case WINED3DLIGHT_SPOT:
1929 case WINED3DLIGHT_PARALLELPOINT:
1930 case WINED3DLIGHT_GLSPOT:
1931 /* Incorrect attenuation values can cause the gl driver to crash.
1932 * Happens with Need for speed most wanted. */
1933 if (light->Attenuation0 < 0.0f || light->Attenuation1 < 0.0f || light->Attenuation2 < 0.0f)
1935 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL.\n");
1936 return WINED3DERR_INVALIDCALL;
1940 case WINED3DLIGHT_DIRECTIONAL:
1941 /* Ignores attenuation */
1945 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
1946 return WINED3DERR_INVALIDCALL;
1949 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1951 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
1952 if (object->OriginalIndex == light_idx)
1959 TRACE("Adding new light\n");
1960 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1963 ERR("Out of memory error when allocating a light\n");
1964 return E_OUTOFMEMORY;
1966 list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry);
1967 object->glIndex = -1;
1968 object->OriginalIndex = light_idx;
1971 /* Initialize the object. */
1972 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n",
1973 light_idx, light->Type,
1974 light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, light->Diffuse.a,
1975 light->Specular.r, light->Specular.g, light->Specular.b, light->Specular.a,
1976 light->Ambient.r, light->Ambient.g, light->Ambient.b, light->Ambient.a);
1977 TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->Position.x, light->Position.y, light->Position.z,
1978 light->Direction.x, light->Direction.y, light->Direction.z);
1979 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
1980 light->Range, light->Falloff, light->Theta, light->Phi);
1982 /* Save away the information. */
1983 object->OriginalParms = *light;
1985 switch (light->Type)
1987 case WINED3DLIGHT_POINT:
1989 object->lightPosn[0] = light->Position.x;
1990 object->lightPosn[1] = light->Position.y;
1991 object->lightPosn[2] = light->Position.z;
1992 object->lightPosn[3] = 1.0f;
1993 object->cutoff = 180.0f;
1997 case WINED3DLIGHT_DIRECTIONAL:
1999 object->lightPosn[0] = -light->Direction.x;
2000 object->lightPosn[1] = -light->Direction.y;
2001 object->lightPosn[2] = -light->Direction.z;
2002 object->lightPosn[3] = 0.0f;
2003 object->exponent = 0.0f;
2004 object->cutoff = 180.0f;
2007 case WINED3DLIGHT_SPOT:
2009 object->lightPosn[0] = light->Position.x;
2010 object->lightPosn[1] = light->Position.y;
2011 object->lightPosn[2] = light->Position.z;
2012 object->lightPosn[3] = 1.0f;
2015 object->lightDirn[0] = light->Direction.x;
2016 object->lightDirn[1] = light->Direction.y;
2017 object->lightDirn[2] = light->Direction.z;
2018 object->lightDirn[3] = 1.0f;
2020 /* opengl-ish and d3d-ish spot lights use too different models
2021 * for the light "intensity" as a function of the angle towards
2022 * the main light direction, so we only can approximate very
2023 * roughly. However, spot lights are rather rarely used in games
2024 * (if ever used at all). Furthermore if still used, probably
2025 * nobody pays attention to such details. */
2026 if (!light->Falloff)
2028 /* Falloff = 0 is easy, because d3d's and opengl's spot light
2029 * equations have the falloff resp. exponent parameter as an
2030 * exponent, so the spot light lighting will always be 1.0 for
2031 * both of them, and we don't have to care for the rest of the
2032 * rather complex calculation. */
2033 object->exponent = 0.0f;
2037 rho = light->Theta + (light->Phi - light->Theta) / (2 * light->Falloff);
2040 object->exponent = -0.3f / logf(cosf(rho / 2));
2043 if (object->exponent > 128.0f)
2044 object->exponent = 128.0f;
2046 object->cutoff = (float)(light->Phi * 90 / M_PI);
2051 FIXME("Unrecognized light type %#x.\n", light->Type);
2054 /* Update the live definitions if the light is currently assigned a glIndex. */
2055 if (object->glIndex != -1 && !device->isRecordingState)
2056 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_ACTIVELIGHT(object->glIndex));
2061 HRESULT CDECL wined3d_device_get_light(IWineD3DDevice *iface, UINT light_idx, WINED3DLIGHT *light)
2063 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2064 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2065 struct wined3d_light_info *light_info = NULL;
2068 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
2070 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2072 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2073 if (light_info->OriginalIndex == light_idx)
2080 TRACE("Light information requested but light not defined\n");
2081 return WINED3DERR_INVALIDCALL;
2084 *light = light_info->OriginalParms;
2088 HRESULT CDECL wined3d_device_set_light_enable(IWineD3DDevice *iface, UINT light_idx, BOOL enable)
2090 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2091 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2092 struct wined3d_light_info *light_info = NULL;
2095 TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable);
2097 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
2099 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2100 if (light_info->OriginalIndex == light_idx)
2104 TRACE("Found light %p.\n", light_info);
2106 /* Special case - enabling an undefined light creates one with a strict set of parameters. */
2109 TRACE("Light enabled requested but light not defined, so defining one!\n");
2110 wined3d_device_set_light(iface, light_idx, &WINED3D_default_light);
2112 /* Search for it again! Should be fairly quick as near head of list. */
2113 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
2115 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2116 if (light_info->OriginalIndex == light_idx)
2122 FIXME("Adding default lights has failed dismally\n");
2123 return WINED3DERR_INVALIDCALL;
2129 if (light_info->glIndex != -1)
2131 if (!device->isRecordingState)
2132 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_ACTIVELIGHT(light_info->glIndex));
2134 device->updateStateBlock->state.lights[light_info->glIndex] = NULL;
2135 light_info->glIndex = -1;
2139 TRACE("Light already disabled, nothing to do\n");
2141 light_info->enabled = FALSE;
2145 light_info->enabled = TRUE;
2146 if (light_info->glIndex != -1)
2148 TRACE("Nothing to do as light was enabled\n");
2153 /* Find a free GL light. */
2154 for (i = 0; i < device->maxConcurrentLights; ++i)
2156 if (!device->updateStateBlock->state.lights[i])
2158 device->updateStateBlock->state.lights[i] = light_info;
2159 light_info->glIndex = i;
2163 if (light_info->glIndex == -1)
2165 /* Our tests show that Windows returns D3D_OK in this situation, even with
2166 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2167 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2168 * as well for those lights.
2170 * TODO: Test how this affects rendering. */
2171 WARN("Too many concurrently active lights\n");
2175 /* i == light_info->glIndex */
2176 if (!device->isRecordingState)
2177 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_ACTIVELIGHT(i));
2184 HRESULT CDECL wined3d_device_get_light_enable(IWineD3DDevice *iface, UINT light_idx, BOOL *enable)
2186 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2187 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2188 struct wined3d_light_info *light_info = NULL;
2191 TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable);
2193 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2195 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2196 if (light_info->OriginalIndex == light_idx)
2203 TRACE("Light enabled state requested but light not defined.\n");
2204 return WINED3DERR_INVALIDCALL;
2206 /* true is 128 according to SetLightEnable */
2207 *enable = light_info->enabled ? 128 : 0;
2211 HRESULT CDECL wined3d_device_set_clip_plane(IWineD3DDevice *iface, UINT plane_idx, const float *plane)
2213 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2215 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2217 /* Validate plane_idx. */
2218 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2220 TRACE("Application has requested clipplane this device doesn't support.\n");
2221 return WINED3DERR_INVALIDCALL;
2224 device->updateStateBlock->changed.clipplane |= 1 << plane_idx;
2226 if (device->updateStateBlock->state.clip_planes[plane_idx][0] == plane[0]
2227 && device->updateStateBlock->state.clip_planes[plane_idx][1] == plane[1]
2228 && device->updateStateBlock->state.clip_planes[plane_idx][2] == plane[2]
2229 && device->updateStateBlock->state.clip_planes[plane_idx][3] == plane[3])
2231 TRACE("Application is setting old values over, nothing to do.\n");
2235 device->updateStateBlock->state.clip_planes[plane_idx][0] = plane[0];
2236 device->updateStateBlock->state.clip_planes[plane_idx][1] = plane[1];
2237 device->updateStateBlock->state.clip_planes[plane_idx][2] = plane[2];
2238 device->updateStateBlock->state.clip_planes[plane_idx][3] = plane[3];
2240 /* Handle recording of state blocks. */
2241 if (device->isRecordingState)
2243 TRACE("Recording... not performing anything.\n");
2247 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_CLIPPLANE(plane_idx));
2252 HRESULT CDECL wined3d_device_get_clip_plane(IWineD3DDevice *iface, DWORD plane_idx, float *plane)
2254 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2256 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2258 /* Validate plane_idx. */
2259 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2261 TRACE("Application has requested clipplane this device doesn't support.\n");
2262 return WINED3DERR_INVALIDCALL;
2265 plane[0] = (float)device->stateBlock->state.clip_planes[plane_idx][0];
2266 plane[1] = (float)device->stateBlock->state.clip_planes[plane_idx][1];
2267 plane[2] = (float)device->stateBlock->state.clip_planes[plane_idx][2];
2268 plane[3] = (float)device->stateBlock->state.clip_planes[plane_idx][3];
2273 HRESULT CDECL wined3d_device_set_clip_status(IWineD3DDevice *iface, const WINED3DCLIPSTATUS *clip_status)
2275 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2277 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2280 return WINED3DERR_INVALIDCALL;
2282 device->updateStateBlock->state.clip_status.ClipUnion = clip_status->ClipUnion;
2283 device->updateStateBlock->state.clip_status.ClipIntersection = clip_status->ClipIntersection;
2288 HRESULT CDECL wined3d_device_get_clip_status(IWineD3DDevice *iface, WINED3DCLIPSTATUS *clip_status)
2290 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2292 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2295 return WINED3DERR_INVALIDCALL;
2297 clip_status->ClipUnion = device->updateStateBlock->state.clip_status.ClipUnion;
2298 clip_status->ClipIntersection = device->updateStateBlock->state.clip_status.ClipIntersection;
2303 HRESULT CDECL wined3d_device_set_material(IWineD3DDevice *iface, const WINED3DMATERIAL *material)
2305 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2307 TRACE("device %p, material %p.\n", device, material);
2309 device->updateStateBlock->changed.material = TRUE;
2310 device->updateStateBlock->state.material = *material;
2312 /* Handle recording of state blocks */
2313 if (device->isRecordingState)
2315 TRACE("Recording... not performing anything.\n");
2319 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_MATERIAL);
2324 HRESULT CDECL wined3d_device_get_material(IWineD3DDevice *iface, WINED3DMATERIAL *material)
2326 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2328 TRACE("device %p, material %p.\n", device, material);
2330 *material = device->updateStateBlock->state.material;
2332 TRACE("Diffuse {%.8e, %.8e, %.8e, %.8e}\n",
2333 material->Diffuse.r, material->Diffuse.g,
2334 material->Diffuse.b, material->Diffuse.a);
2335 TRACE("Ambient {%.8e, %.8e, %.8e, %.8e}\n",
2336 material->Ambient.r, material->Ambient.g,
2337 material->Ambient.b, material->Ambient.a);
2338 TRACE("Specular {%.8e, %.8e, %.8e, %.8e}\n",
2339 material->Specular.r, material->Specular.g,
2340 material->Specular.b, material->Specular.a);
2341 TRACE("Emissive {%.8e, %.8e, %.8e, %.8e}\n",
2342 material->Emissive.r, material->Emissive.g,
2343 material->Emissive.b, material->Emissive.a);
2344 TRACE("Power %.8e.\n", material->Power);
2349 HRESULT CDECL wined3d_device_set_index_buffer(IWineD3DDevice *iface,
2350 struct wined3d_buffer *buffer, enum wined3d_format_id format_id)
2352 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2353 struct wined3d_buffer *prev_buffer;
2355 TRACE("iface %p, buffer %p, format %s.\n",
2356 iface, buffer, debug_d3dformat(format_id));
2358 prev_buffer = device->updateStateBlock->state.index_buffer;
2360 device->updateStateBlock->changed.indices = TRUE;
2361 device->updateStateBlock->state.index_buffer = buffer;
2362 device->updateStateBlock->state.index_format = format_id;
2364 /* Handle recording of state blocks. */
2365 if (device->isRecordingState)
2367 TRACE("Recording... not performing anything.\n");
2369 wined3d_buffer_incref(buffer);
2371 wined3d_buffer_decref(prev_buffer);
2375 if (prev_buffer != buffer)
2377 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_INDEXBUFFER);
2380 InterlockedIncrement(&buffer->bind_count);
2381 wined3d_buffer_incref(buffer);
2385 InterlockedDecrement(&prev_buffer->bind_count);
2386 wined3d_buffer_decref(prev_buffer);
2393 HRESULT CDECL wined3d_device_get_index_buffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
2395 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2397 TRACE("iface %p, buffer %p.\n", iface, buffer);
2399 *buffer = device->stateBlock->state.index_buffer;
2402 wined3d_buffer_incref(*buffer);
2404 TRACE("Returning %p.\n", *buffer);
2409 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2410 HRESULT CDECL wined3d_device_set_base_vertex_index(IWineD3DDevice *iface, INT base_index)
2412 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2414 TRACE("device %p, base_index %d.\n", device, base_index);
2416 if (device->updateStateBlock->state.base_vertex_index == base_index)
2418 TRACE("Application is setting the old value over, nothing to do\n");
2422 device->updateStateBlock->state.base_vertex_index = base_index;
2424 if (device->isRecordingState)
2426 TRACE("Recording... not performing anything\n");
2430 /* The base vertex index affects the stream sources */
2431 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC);
2436 INT CDECL wined3d_device_get_base_vertex_index(IWineD3DDevice *iface)
2438 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2440 TRACE("device %p.\n", device);
2442 return device->stateBlock->state.base_vertex_index;
2445 HRESULT CDECL wined3d_device_set_viewport(IWineD3DDevice *iface, const WINED3DVIEWPORT *viewport)
2447 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2449 TRACE("device %p, viewport %p.\n", device, viewport);
2450 TRACE("x %u, y %u, w %u, h %u, minz %.8e, maxz %.8e.\n",
2451 viewport->X, viewport->Y, viewport->Width, viewport->Height, viewport->MinZ, viewport->MaxZ);
2453 device->updateStateBlock->changed.viewport = TRUE;
2454 device->updateStateBlock->state.viewport = *viewport;
2456 /* Handle recording of state blocks */
2457 if (device->isRecordingState)
2459 TRACE("Recording... not performing anything\n");
2463 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
2468 HRESULT CDECL wined3d_device_get_viewport(IWineD3DDevice *iface, WINED3DVIEWPORT *viewport)
2470 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2472 TRACE("device %p, viewport %p.\n", device, viewport);
2474 *viewport = device->stateBlock->state.viewport;
2479 HRESULT CDECL wined3d_device_set_render_state(IWineD3DDevice *iface,
2480 WINED3DRENDERSTATETYPE state, DWORD value)
2482 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2483 DWORD old_value = device->stateBlock->state.render_states[state];
2485 TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value);
2487 device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f);
2488 device->updateStateBlock->state.render_states[state] = value;
2490 /* Handle recording of state blocks. */
2491 if (device->isRecordingState)
2493 TRACE("Recording... not performing anything.\n");
2497 /* Compared here and not before the assignment to allow proper stateblock recording. */
2498 if (value == old_value)
2499 TRACE("Application is setting the old value over, nothing to do.\n");
2501 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(state));
2506 HRESULT CDECL wined3d_device_get_render_state(IWineD3DDevice *iface,
2507 WINED3DRENDERSTATETYPE state, DWORD *value)
2509 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2511 TRACE("device %p, state %s (%#x), value %p.\n", device, debug_d3drenderstate(state), state, value);
2513 *value = device->stateBlock->state.render_states[state];
2518 HRESULT CDECL wined3d_device_set_sampler_state(IWineD3DDevice *iface,
2519 UINT sampler_idx, WINED3DSAMPLERSTATETYPE state, DWORD value)
2521 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2524 TRACE("device %p, sampler_idx %u, state %s, value %#x.\n",
2525 device, sampler_idx, debug_d3dsamplerstate(state), value);
2527 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2528 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2530 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2531 / sizeof(*device->stateBlock->state.sampler_states))
2533 WARN("Invalid sampler %u.\n", sampler_idx);
2534 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2537 old_value = device->stateBlock->state.sampler_states[sampler_idx][state];
2538 device->updateStateBlock->state.sampler_states[sampler_idx][state] = value;
2539 device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state;
2541 /* Handle recording of state blocks. */
2542 if (device->isRecordingState)
2544 TRACE("Recording... not performing anything.\n");
2548 if (old_value == value)
2550 TRACE("Application is setting the old value over, nothing to do.\n");
2554 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(sampler_idx));
2559 HRESULT CDECL wined3d_device_get_sampler_state(IWineD3DDevice *iface,
2560 UINT sampler_idx, WINED3DSAMPLERSTATETYPE state, DWORD *value)
2562 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2564 TRACE("device %p, sampler_idx %u, state %s, value %p.\n",
2565 device, sampler_idx, debug_d3dsamplerstate(state), value);
2567 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2568 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2570 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2571 / sizeof(*device->stateBlock->state.sampler_states))
2573 WARN("Invalid sampler %u.\n", sampler_idx);
2574 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2577 *value = device->stateBlock->state.sampler_states[sampler_idx][state];
2578 TRACE("Returning %#x.\n", *value);
2583 HRESULT CDECL wined3d_device_set_scissor_rect(IWineD3DDevice *iface, const RECT *rect)
2585 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2587 TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect));
2589 device->updateStateBlock->changed.scissorRect = TRUE;
2590 if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect))
2592 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
2595 CopyRect(&device->updateStateBlock->state.scissor_rect, rect);
2597 if (device->isRecordingState)
2599 TRACE("Recording... not performing anything.\n");
2603 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
2608 HRESULT CDECL wined3d_device_get_scissor_rect(IWineD3DDevice *iface, RECT *rect)
2610 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2612 TRACE("device %p, rect %p.\n", device, rect);
2614 *rect = device->updateStateBlock->state.scissor_rect;
2615 TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect));
2620 HRESULT CDECL wined3d_device_set_vertex_declaration(IWineD3DDevice *iface,
2621 struct wined3d_vertex_declaration *declaration)
2623 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2624 struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration;
2626 TRACE("device %p, declaration %p.\n", device, declaration);
2629 wined3d_vertex_declaration_incref(declaration);
2631 wined3d_vertex_declaration_decref(prev);
2633 device->updateStateBlock->state.vertex_declaration = declaration;
2634 device->updateStateBlock->changed.vertexDecl = TRUE;
2636 if (device->isRecordingState)
2638 TRACE("Recording... not performing anything.\n");
2641 else if (declaration == prev)
2643 /* Checked after the assignment to allow proper stateblock recording. */
2644 TRACE("Application is setting the old declaration over, nothing to do.\n");
2648 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VDECL);
2652 HRESULT CDECL wined3d_device_get_vertex_declaration(IWineD3DDevice *iface,
2653 struct wined3d_vertex_declaration **declaration)
2655 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2657 TRACE("device %p, declaration %p.\n", device, declaration);
2659 *declaration = device->stateBlock->state.vertex_declaration;
2661 wined3d_vertex_declaration_incref(*declaration);
2666 HRESULT CDECL wined3d_device_set_vertex_shader(IWineD3DDevice *iface, struct wined3d_shader *shader)
2668 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2669 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
2671 TRACE("device %p, shader %p.\n", device, shader);
2673 device->updateStateBlock->state.vertex_shader = shader;
2674 device->updateStateBlock->changed.vertexShader = TRUE;
2676 if (device->isRecordingState)
2679 wined3d_shader_incref(shader);
2681 wined3d_shader_decref(prev);
2682 TRACE("Recording... not performing anything.\n");
2688 TRACE("Application is setting the old shader over, nothing to do.\n");
2693 wined3d_shader_incref(shader);
2695 wined3d_shader_decref(prev);
2697 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
2702 struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(IWineD3DDevice *iface)
2704 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2705 struct wined3d_shader *shader;
2707 TRACE("device %p.\n", device);
2709 shader = device->stateBlock->state.vertex_shader;
2711 wined3d_shader_incref(shader);
2713 TRACE("Returning %p.\n", shader);
2717 HRESULT CDECL wined3d_device_set_vs_consts_b(IWineD3DDevice *iface,
2718 UINT start_register, const BOOL *constants, UINT bool_count)
2720 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2721 UINT count = min(bool_count, MAX_CONST_B - start_register);
2724 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2725 device, start_register, constants, bool_count);
2727 if (!constants || start_register >= MAX_CONST_B)
2728 return WINED3DERR_INVALIDCALL;
2730 memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL));
2731 for (i = 0; i < count; ++i)
2732 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2734 for (i = start_register; i < count + start_register; ++i)
2735 device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2737 if (!device->isRecordingState)
2738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VERTEXSHADERCONSTANT);
2743 HRESULT CDECL wined3d_device_get_vs_consts_b(IWineD3DDevice *iface,
2744 UINT start_register, BOOL *constants, UINT bool_count)
2746 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2747 UINT count = min(bool_count, MAX_CONST_B - start_register);
2749 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2750 device, start_register, constants, bool_count);
2752 if (!constants || start_register >= MAX_CONST_B)
2753 return WINED3DERR_INVALIDCALL;
2755 memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL));
2760 HRESULT CDECL wined3d_device_set_vs_consts_i(IWineD3DDevice *iface,
2761 UINT start_register, const int *constants, UINT vector4i_count)
2763 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2764 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2767 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2768 device, start_register, constants, vector4i_count);
2770 if (!constants || start_register >= MAX_CONST_I)
2771 return WINED3DERR_INVALIDCALL;
2773 memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
2774 for (i = 0; i < count; ++i)
2775 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
2776 constants[i * 4], constants[i * 4 + 1],
2777 constants[i * 4 + 2], constants[i * 4 + 3]);
2779 for (i = start_register; i < count + start_register; ++i)
2780 device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2782 if (!device->isRecordingState)
2783 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VERTEXSHADERCONSTANT);
2788 HRESULT CDECL wined3d_device_get_vs_consts_i(IWineD3DDevice *iface,
2789 UINT start_register, int *constants, UINT vector4i_count)
2791 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2792 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2794 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2795 device, start_register, constants, vector4i_count);
2797 if (!constants || start_register >= MAX_CONST_I)
2798 return WINED3DERR_INVALIDCALL;
2800 memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4);
2804 HRESULT CDECL wined3d_device_set_vs_consts_f(IWineD3DDevice *iface,
2805 UINT start_register, const float *constants, UINT vector4f_count)
2807 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2810 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2811 device, start_register, constants, vector4f_count);
2813 /* Specifically test start_register > limit to catch MAX_UINT overflows
2814 * when adding start_register + vector4f_count. */
2816 || start_register + vector4f_count > device->d3d_vshader_constantF
2817 || start_register > device->d3d_vshader_constantF)
2818 return WINED3DERR_INVALIDCALL;
2820 memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4],
2821 constants, vector4f_count * sizeof(float) * 4);
2824 for (i = 0; i < vector4f_count; ++i)
2825 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
2826 constants[i * 4], constants[i * 4 + 1],
2827 constants[i * 4 + 2], constants[i * 4 + 3]);
2830 if (!device->isRecordingState)
2832 device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
2833 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VERTEXSHADERCONSTANT);
2836 memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1,
2837 sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count);
2842 HRESULT CDECL wined3d_device_get_vs_consts_f(IWineD3DDevice *iface,
2843 UINT start_register, float *constants, UINT vector4f_count)
2845 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2846 int count = min(vector4f_count, device->d3d_vshader_constantF - start_register);
2848 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2849 device, start_register, constants, vector4f_count);
2851 if (!constants || count < 0)
2852 return WINED3DERR_INVALIDCALL;
2854 memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4);
2859 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2861 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
2867 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
2869 DWORD i = This->rev_tex_unit_map[unit];
2870 DWORD j = This->texUnitMap[stage];
2872 This->texUnitMap[stage] = unit;
2873 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2875 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2878 This->rev_tex_unit_map[unit] = stage;
2879 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2881 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2885 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
2888 This->fixed_function_usage_map = 0;
2889 for (i = 0; i < MAX_TEXTURES; ++i)
2891 const struct wined3d_state *state = &This->stateBlock->state;
2892 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
2893 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
2894 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
2895 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
2896 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
2897 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
2898 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
2899 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
2901 if (color_op == WINED3DTOP_DISABLE) {
2902 /* Not used, and disable higher stages */
2906 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
2907 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
2908 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
2909 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
2910 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
2911 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
2912 This->fixed_function_usage_map |= (1 << i);
2915 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
2916 This->fixed_function_usage_map |= (1 << (i + 1));
2921 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
2923 unsigned int i, tex;
2926 device_update_fixed_function_usage_map(This);
2927 ffu_map = This->fixed_function_usage_map;
2929 if (This->max_ffp_textures == gl_info->limits.texture_stages
2930 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
2932 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2934 if (!(ffu_map & 1)) continue;
2936 if (This->texUnitMap[i] != i) {
2937 device_map_stage(This, i, i);
2938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
2939 markTextureStagesDirty(This, i);
2945 /* Now work out the mapping */
2947 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2949 if (!(ffu_map & 1)) continue;
2951 if (This->texUnitMap[i] != tex) {
2952 device_map_stage(This, i, tex);
2953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
2954 markTextureStagesDirty(This, i);
2961 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
2963 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
2964 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2967 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
2968 if (sampler_type[i] && This->texUnitMap[i] != i)
2970 device_map_stage(This, i, i);
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
2972 if (i < gl_info->limits.texture_stages)
2974 markTextureStagesDirty(This, i);
2980 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
2981 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
2983 DWORD current_mapping = This->rev_tex_unit_map[unit];
2985 /* Not currently used */
2986 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
2988 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
2989 /* Used by a fragment sampler */
2991 if (!pshader_sampler_tokens) {
2992 /* No pixel shader, check fixed function */
2993 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
2996 /* Pixel shader, check the shader's sampler map */
2997 return !pshader_sampler_tokens[current_mapping];
3000 /* Used by a vertex sampler */
3001 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3004 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3006 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3007 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3008 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3009 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3014 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3015 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3016 pshader_sampler_type = This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3019 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3020 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3021 if (vshader_sampler_type[i])
3023 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3025 /* Already mapped somewhere */
3029 while (start >= 0) {
3030 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3032 device_map_stage(This, vsampler_idx, start);
3033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3045 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3047 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3048 const struct wined3d_state *state = &This->stateBlock->state;
3049 BOOL vs = use_vs(state);
3050 BOOL ps = use_ps(state);
3053 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3054 * that would be really messy and require shader recompilation
3055 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3056 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3058 if (ps) device_map_psamplers(This, gl_info);
3059 else device_map_fixed_function_samplers(This, gl_info);
3061 if (vs) device_map_vsamplers(This, ps, gl_info);
3064 HRESULT CDECL wined3d_device_set_pixel_shader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3066 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3067 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
3069 TRACE("device %p, shader %p.\n", device, shader);
3071 device->updateStateBlock->state.pixel_shader = shader;
3072 device->updateStateBlock->changed.pixelShader = TRUE;
3074 if (device->isRecordingState)
3077 wined3d_shader_incref(shader);
3079 wined3d_shader_decref(prev);
3080 TRACE("Recording... not performing anything.\n");
3086 TRACE("Application is setting the old shader over, nothing to do.\n");
3091 wined3d_shader_incref(shader);
3093 wined3d_shader_decref(prev);
3095 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3100 struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(IWineD3DDevice *iface)
3102 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3103 struct wined3d_shader *shader;
3105 TRACE("device %p.\n", device);
3107 shader = device->stateBlock->state.pixel_shader;
3109 wined3d_shader_incref(shader);
3111 TRACE("Returning %p.\n", shader);
3115 HRESULT CDECL wined3d_device_set_ps_consts_b(IWineD3DDevice *iface,
3116 UINT start_register, const BOOL *constants, UINT bool_count)
3118 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3119 UINT count = min(bool_count, MAX_CONST_B - start_register);
3122 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3123 device, start_register, constants, bool_count);
3125 if (!constants || start_register >= MAX_CONST_B)
3126 return WINED3DERR_INVALIDCALL;
3128 memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL));
3129 for (i = 0; i < count; ++i)
3130 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
3132 for (i = start_register; i < count + start_register; ++i)
3133 device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3135 if (!device->isRecordingState)
3136 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADERCONSTANT);
3141 HRESULT CDECL wined3d_device_get_ps_consts_b(IWineD3DDevice *iface,
3142 UINT start_register, BOOL *constants, UINT bool_count)
3144 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3145 UINT count = min(bool_count, MAX_CONST_B - start_register);
3147 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3148 device, start_register, constants, bool_count);
3150 if (!constants || start_register >= MAX_CONST_B)
3151 return WINED3DERR_INVALIDCALL;
3153 memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL));
3158 HRESULT CDECL wined3d_device_set_ps_consts_i(IWineD3DDevice *iface,
3159 UINT start_register, const int *constants, UINT vector4i_count)
3161 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3162 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3165 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3166 device, start_register, constants, vector4i_count);
3168 if (!constants || start_register >= MAX_CONST_I)
3169 return WINED3DERR_INVALIDCALL;
3171 memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
3172 for (i = 0; i < count; ++i)
3173 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
3174 constants[i * 4], constants[i * 4 + 1],
3175 constants[i * 4 + 2], constants[i * 4 + 3]);
3177 for (i = start_register; i < count + start_register; ++i)
3178 device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3180 if (!device->isRecordingState)
3181 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADERCONSTANT);
3186 HRESULT CDECL wined3d_device_get_ps_consts_i(IWineD3DDevice *iface,
3187 UINT start_register, int *constants, UINT vector4i_count)
3189 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3190 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3192 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3193 device, start_register, constants, vector4i_count);
3195 if (!constants || start_register >= MAX_CONST_I)
3196 return WINED3DERR_INVALIDCALL;
3198 memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4);
3203 HRESULT CDECL wined3d_device_set_ps_consts_f(IWineD3DDevice *iface,
3204 UINT start_register, const float *constants, UINT vector4f_count)
3206 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3209 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3210 device, start_register, constants, vector4f_count);
3212 /* Specifically test start_register > limit to catch MAX_UINT overflows
3213 * when adding start_register + vector4f_count. */
3215 || start_register + vector4f_count > device->d3d_pshader_constantF
3216 || start_register > device->d3d_pshader_constantF)
3217 return WINED3DERR_INVALIDCALL;
3219 memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4],
3220 constants, vector4f_count * sizeof(float) * 4);
3223 for (i = 0; i < vector4f_count; ++i)
3224 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
3225 constants[i * 4], constants[i * 4 + 1],
3226 constants[i * 4 + 2], constants[i * 4 + 3]);
3229 if (!device->isRecordingState)
3231 device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
3232 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADERCONSTANT);
3235 memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1,
3236 sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count);
3241 HRESULT CDECL wined3d_device_get_ps_consts_f(IWineD3DDevice *iface,
3242 UINT start_register, float *constants, UINT vector4f_count)
3244 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3245 int count = min(vector4f_count, device->d3d_pshader_constantF - start_register);
3247 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3248 device, start_register, constants, vector4f_count);
3250 if (!constants || count < 0)
3251 return WINED3DERR_INVALIDCALL;
3253 memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4);
3258 /* Context activation is done by the caller. */
3259 /* Do not call while under the GL lock. */
3260 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3261 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3262 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3265 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3266 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3269 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3273 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3275 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3278 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3280 ERR("Source has no position mask\n");
3281 return WINED3DERR_INVALIDCALL;
3284 if (!dest->resource.allocatedMemory)
3285 buffer_get_sysmem(dest, gl_info);
3287 /* Get a pointer into the destination vbo(create one if none exists) and
3288 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3290 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3292 dest->flags |= WINED3D_BUFFER_CREATEBO;
3293 wined3d_buffer_preload(dest);
3296 if (dest->buffer_object)
3298 unsigned char extrabytes = 0;
3299 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3300 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3301 * this may write 4 extra bytes beyond the area that should be written
3303 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3304 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3305 if(!dest_conv_addr) {
3306 ERR("Out of memory\n");
3307 /* Continue without storing converted vertices */
3309 dest_conv = dest_conv_addr;
3312 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3314 static BOOL warned = FALSE;
3316 * The clipping code is not quite correct. Some things need
3317 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3318 * so disable clipping for now.
3319 * (The graphics in Half-Life are broken, and my processvertices
3320 * test crashes with IDirect3DDevice3)
3326 FIXME("Clipping is broken and disabled for now\n");
3328 } else doClip = FALSE;
3329 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3331 wined3d_device_get_transform((IWineD3DDevice *)This, WINED3DTS_VIEW, &view_mat);
3332 wined3d_device_get_transform((IWineD3DDevice *)This, WINED3DTS_PROJECTION, &proj_mat);
3333 wined3d_device_get_transform((IWineD3DDevice *)This, WINED3DTS_WORLDMATRIX(0), &world_mat);
3335 TRACE("View mat:\n");
3336 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);
3337 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);
3338 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);
3339 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);
3341 TRACE("Proj mat:\n");
3342 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);
3343 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);
3344 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);
3345 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);
3347 TRACE("World mat:\n");
3348 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);
3349 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);
3350 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);
3351 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);
3353 /* Get the viewport */
3354 wined3d_device_get_viewport((IWineD3DDevice *)This, &vp);
3355 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3356 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3358 multiply_matrix(&mat,&view_mat,&world_mat);
3359 multiply_matrix(&mat,&proj_mat,&mat);
3361 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3363 for (i = 0; i < dwCount; i+= 1) {
3364 unsigned int tex_index;
3366 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3367 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3368 /* The position first */
3369 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3370 const float *p = (const float *)(element->data + i * element->stride);
3372 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3374 /* Multiplication with world, view and projection matrix */
3375 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);
3376 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);
3377 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);
3378 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);
3380 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3382 /* WARNING: The following things are taken from d3d7 and were not yet checked
3383 * against d3d8 or d3d9!
3386 /* Clipping conditions: From msdn
3388 * A vertex is clipped if it does not match the following requirements
3392 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3394 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3395 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3400 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3401 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3404 /* "Normal" viewport transformation (not clipped)
3405 * 1) The values are divided by rhw
3406 * 2) The y axis is negative, so multiply it with -1
3407 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3408 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3409 * 4) Multiply x with Width/2 and add Width/2
3410 * 5) The same for the height
3411 * 6) Add the viewpoint X and Y to the 2D coordinates and
3412 * The minimum Z value to z
3413 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3415 * Well, basically it's simply a linear transformation into viewport
3427 z *= vp.MaxZ - vp.MinZ;
3429 x += vp.Width / 2 + vp.X;
3430 y += vp.Height / 2 + vp.Y;
3435 /* That vertex got clipped
3436 * Contrary to OpenGL it is not dropped completely, it just
3437 * undergoes a different calculation.
3439 TRACE("Vertex got clipped\n");
3446 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3447 * outside of the main vertex buffer memory. That needs some more
3452 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3455 ( (float *) dest_ptr)[0] = x;
3456 ( (float *) dest_ptr)[1] = y;
3457 ( (float *) dest_ptr)[2] = z;
3458 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3460 dest_ptr += 3 * sizeof(float);
3462 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3463 dest_ptr += sizeof(float);
3468 ( (float *) dest_conv)[0] = x * w;
3469 ( (float *) dest_conv)[1] = y * w;
3470 ( (float *) dest_conv)[2] = z * w;
3471 ( (float *) dest_conv)[3] = w;
3473 dest_conv += 3 * sizeof(float);
3475 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3476 dest_conv += sizeof(float);
3480 if (DestFVF & WINED3DFVF_PSIZE) {
3481 dest_ptr += sizeof(DWORD);
3482 if(dest_conv) dest_conv += sizeof(DWORD);
3484 if (DestFVF & WINED3DFVF_NORMAL) {
3485 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3486 const float *normal = (const float *)(element->data + i * element->stride);
3487 /* AFAIK this should go into the lighting information */
3488 FIXME("Didn't expect the destination to have a normal\n");
3489 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3491 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3495 if (DestFVF & WINED3DFVF_DIFFUSE) {
3496 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3497 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3498 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3500 static BOOL warned = FALSE;
3503 ERR("No diffuse color in source, but destination has one\n");
3507 *( (DWORD *) dest_ptr) = 0xffffffff;
3508 dest_ptr += sizeof(DWORD);
3511 *( (DWORD *) dest_conv) = 0xffffffff;
3512 dest_conv += sizeof(DWORD);
3516 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3518 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3519 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3520 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3521 dest_conv += sizeof(DWORD);
3526 if (DestFVF & WINED3DFVF_SPECULAR)
3528 /* What's the color value in the feedback buffer? */
3529 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3530 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3531 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3533 static BOOL warned = FALSE;
3536 ERR("No specular color in source, but destination has one\n");
3540 *( (DWORD *) dest_ptr) = 0xFF000000;
3541 dest_ptr += sizeof(DWORD);
3544 *( (DWORD *) dest_conv) = 0xFF000000;
3545 dest_conv += sizeof(DWORD);
3549 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3551 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3552 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3553 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3554 dest_conv += sizeof(DWORD);
3559 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3560 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3561 const float *tex_coord = (const float *)(element->data + i * element->stride);
3562 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3564 ERR("No source texture, but destination requests one\n");
3565 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3566 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3569 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3571 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3581 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3582 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3583 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3584 dwCount * get_flexible_vertex_size(DestFVF),
3586 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3590 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3595 #undef copy_and_next
3597 /* Do not call while under the GL lock. */
3598 HRESULT CDECL wined3d_device_process_vertices(IWineD3DDevice *iface,
3599 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
3600 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 struct wined3d_stream_info stream_info;
3604 const struct wined3d_gl_info *gl_info;
3605 struct wined3d_context *context;
3606 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
3609 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
3612 ERR("Output vertex declaration not implemented yet\n");
3615 /* Need any context to write to the vbo. */
3616 context = context_acquire(This, NULL);
3617 gl_info = context->gl_info;
3619 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3620 * control the streamIsUP flag, thus restore it afterwards.
3622 This->stateBlock->state.user_stream = FALSE;
3623 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3624 This->stateBlock->state.user_stream = streamWasUP;
3626 if(vbo || SrcStartIndex) {
3628 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3629 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3631 * Also get the start index in, but only loop over all elements if there's something to add at all.
3633 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3635 struct wined3d_stream_info_element *e;
3637 if (!(stream_info.use_map & (1 << i))) continue;
3639 e = &stream_info.elements[i];
3640 if (e->buffer_object)
3642 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
3643 e->buffer_object = 0;
3644 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3646 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3647 vb->buffer_object = 0;
3650 if (e->data) e->data += e->stride * SrcStartIndex;
3654 hr = process_vertices_strided(This, DestIndex, VertexCount,
3655 &stream_info, dst_buffer, flags, DestFVF);
3657 context_release(context);
3662 HRESULT CDECL wined3d_device_set_texture_stage_state(IWineD3DDevice *iface,
3663 UINT stage, WINED3DTEXTURESTAGESTATETYPE state, DWORD value)
3665 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3666 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3669 TRACE("device %p, stage %u, state %s, value %#x.\n",
3670 device, stage, debug_d3dtexturestate(state), value);
3672 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3674 WARN("Invalid state %#x passed.\n", state);
3678 if (stage >= gl_info->limits.texture_stages)
3680 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3681 stage, gl_info->limits.texture_stages - 1);
3685 old_value = device->updateStateBlock->state.texture_states[stage][state];
3686 device->updateStateBlock->changed.textureState[stage] |= 1 << state;
3687 device->updateStateBlock->state.texture_states[stage][state] = value;
3689 if (device->isRecordingState)
3691 TRACE("Recording... not performing anything.\n");
3695 /* Checked after the assignments to allow proper stateblock recording. */
3696 if (old_value == value)
3698 TRACE("Application is setting the old value over, nothing to do.\n");
3702 if (stage > device->stateBlock->state.lowest_disabled_stage
3703 && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative
3704 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
3706 /* Colorop change above lowest disabled stage? That won't change
3707 * anything in the GL setup. Changes in other states are important on
3708 * disabled stages too. */
3712 if (state == WINED3DTSS_COLOROP)
3716 if (value == WINED3DTOP_DISABLE && old_value != WINED3DTOP_DISABLE)
3718 /* Previously enabled stage disabled now. Make sure to dirtify
3719 * all enabled stages above stage, they have to be disabled.
3721 * The current stage is dirtified below. */
3722 for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i)
3724 TRACE("Additionally dirtifying stage %u.\n", i);
3725 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3727 device->stateBlock->state.lowest_disabled_stage = stage;
3728 TRACE("New lowest disabled: %u.\n", stage);
3730 else if (value != WINED3DTOP_DISABLE && old_value == WINED3DTOP_DISABLE)
3732 /* Previously disabled stage enabled. Stages above it may need
3733 * enabling. Stage must be lowest_disabled_stage here, if it's
3734 * bigger success is returned above, and stages below the lowest
3735 * disabled stage can't be enabled (because they are enabled
3738 * Again stage stage doesn't need to be dirtified here, it is
3740 for (i = stage + 1; i < gl_info->limits.texture_stages; ++i)
3742 if (device->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
3744 TRACE("Additionally dirtifying stage %u due to enable.\n", i);
3745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3747 device->stateBlock->state.lowest_disabled_stage = i;
3748 TRACE("New lowest disabled: %u.\n", i);
3752 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(stage, state));
3757 HRESULT CDECL wined3d_device_get_texture_stage_state(IWineD3DDevice *iface,
3758 DWORD stage, WINED3DTEXTURESTAGESTATETYPE state, DWORD *value)
3760 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3762 TRACE("device %p, stage %u, state %s, value %p.\n",
3763 device, stage, debug_d3dtexturestate(state), value);
3765 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3767 WARN("Invalid state %#x passed.\n", state);
3771 *value = device->updateStateBlock->state.texture_states[stage][state];
3772 TRACE("Returning %#x.\n", *value);
3777 HRESULT CDECL wined3d_device_set_texture(IWineD3DDevice *iface,
3778 DWORD stage, struct wined3d_texture *texture)
3780 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3781 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3782 struct wined3d_texture *prev;
3784 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3786 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3787 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3789 /* Windows accepts overflowing this array... we do not. */
3790 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3792 WARN("Ignoring invalid stage %u.\n", stage);
3796 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3797 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
3799 WARN("Rejecting attempt to set scratch texture.\n");
3800 return WINED3DERR_INVALIDCALL;
3803 device->updateStateBlock->changed.textures |= 1 << stage;
3805 prev = device->updateStateBlock->state.textures[stage];
3806 TRACE("Previous texture %p.\n", prev);
3808 if (texture == prev)
3810 TRACE("App is setting the same texture again, nothing to do.\n");
3814 TRACE("Setting new texture to %p.\n", texture);
3815 device->updateStateBlock->state.textures[stage] = texture;
3817 if (device->isRecordingState)
3819 TRACE("Recording... not performing anything\n");
3821 if (texture) wined3d_texture_incref(texture);
3822 if (prev) wined3d_texture_decref(prev);
3829 LONG bind_count = InterlockedIncrement(&texture->bind_count);
3831 wined3d_texture_incref(texture);
3833 if (!prev || texture->target != prev->target)
3834 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3836 if (!prev && stage < gl_info->limits.texture_stages)
3838 /* The source arguments for color and alpha ops have different
3839 * meanings when a NULL texture is bound, so the COLOROP and
3840 * ALPHAOP have to be dirtified. */
3841 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3842 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3845 if (bind_count == 1)
3846 texture->sampler = stage;
3851 LONG bind_count = InterlockedDecrement(&prev->bind_count);
3853 wined3d_texture_decref(prev);
3855 if (!texture && stage < gl_info->limits.texture_stages)
3857 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3858 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3861 if (bind_count && prev->sampler == stage)
3865 /* Search for other stages the texture is bound to. Shouldn't
3866 * happen if applications bind textures to a single stage only. */
3867 TRACE("Searching for other stages the texture is bound to.\n");
3868 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3870 if (device->updateStateBlock->state.textures[i] == prev)
3872 TRACE("Texture is also bound to stage %u.\n", i);
3880 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(stage));
3885 HRESULT CDECL wined3d_device_get_texture(IWineD3DDevice *iface,
3886 DWORD stage, struct wined3d_texture **texture)
3888 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3890 TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3892 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3893 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3895 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3897 WARN("Ignoring invalid stage %u.\n", stage);
3898 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3901 *texture = device->stateBlock->state.textures[stage];
3903 wined3d_texture_incref(*texture);
3905 TRACE("Returning %p.\n", *texture);
3910 HRESULT CDECL wined3d_device_get_back_buffer(IWineD3DDevice *iface, UINT swapchain_idx,
3911 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, struct wined3d_surface **backbuffer)
3913 struct wined3d_swapchain *swapchain;
3916 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3917 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3919 hr = wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain);
3922 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
3926 hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
3927 wined3d_swapchain_decref(swapchain);
3930 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
3937 HRESULT CDECL wined3d_device_get_device_caps(IWineD3DDevice *iface, WINED3DCAPS *caps)
3939 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3941 TRACE("iface %p, caps %p.\n", iface, caps);
3943 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
3946 HRESULT CDECL wined3d_device_get_display_mode(IWineD3DDevice *iface,
3947 UINT swapchain_idx, WINED3DDISPLAYMODE *mode)
3949 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3950 struct wined3d_swapchain *swapchain;
3953 TRACE("iface %p, swapchain_idx %u, mode %p.\n", iface, swapchain_idx, mode);
3957 hr = wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain);
3960 hr = wined3d_swapchain_get_display_mode(swapchain, mode);
3961 wined3d_swapchain_decref(swapchain);
3966 /* Don't read the real display mode, but return the stored mode
3967 * instead. X11 can't change the color depth, and some apps are
3968 * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out
3969 * that GetDisplayMode still returns 24 bpp.
3971 * Also don't relay to the swapchain because with ddraw it's possible
3972 * that there isn't a swapchain at all. */
3973 mode->Width = device->ddraw_width;
3974 mode->Height = device->ddraw_height;
3975 mode->Format = device->ddraw_format;
3976 mode->RefreshRate = 0;
3983 HRESULT CDECL wined3d_device_begin_stateblock(IWineD3DDevice *iface)
3985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3986 struct wined3d_stateblock *stateblock;
3989 TRACE("(%p)\n", This);
3991 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
3993 hr = wined3d_stateblock_create(iface, WINED3DSBT_RECORDED, &stateblock);
3994 if (FAILED(hr)) return hr;
3996 wined3d_stateblock_decref(This->updateStateBlock);
3997 This->updateStateBlock = stateblock;
3998 This->isRecordingState = TRUE;
4000 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4005 HRESULT CDECL wined3d_device_end_stateblock(IWineD3DDevice *iface,
4006 struct wined3d_stateblock **stateblock)
4008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4009 struct wined3d_stateblock *object = This->updateStateBlock;
4011 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4013 if (!This->isRecordingState) {
4014 WARN("(%p) not recording! returning error\n", This);
4016 return WINED3DERR_INVALIDCALL;
4019 stateblock_init_contained_states(object);
4021 *stateblock = object;
4022 This->isRecordingState = FALSE;
4023 This->updateStateBlock = This->stateBlock;
4024 wined3d_stateblock_incref(This->updateStateBlock);
4026 TRACE("Returning stateblock %p.\n", *stateblock);
4031 HRESULT CDECL wined3d_device_begin_scene(IWineD3DDevice *iface)
4033 /* At the moment we have no need for any functionality at the beginning
4035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4036 TRACE("(%p)\n", This);
4039 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4040 return WINED3DERR_INVALIDCALL;
4042 This->inScene = TRUE;
4046 HRESULT CDECL wined3d_device_end_scene(IWineD3DDevice *iface)
4048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4049 struct wined3d_context *context;
4051 TRACE("(%p)\n", This);
4053 if(!This->inScene) {
4054 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4055 return WINED3DERR_INVALIDCALL;
4058 context = context_acquire(This, NULL);
4059 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4061 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4063 context_release(context);
4065 This->inScene = FALSE;
4069 HRESULT CDECL wined3d_device_present(IWineD3DDevice *iface, const RECT *src_rect,
4070 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
4072 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4075 TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
4076 iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
4077 dst_window_override, dirty_region);
4079 for (i = 0; i < device->swapchain_count; ++i)
4081 wined3d_swapchain_present(device->swapchains[i], src_rect,
4082 dst_rect, dst_window_override, dirty_region, 0);
4088 /* Do not call while under the GL lock. */
4089 HRESULT CDECL wined3d_device_clear(IWineD3DDevice *iface, DWORD rect_count,
4090 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4092 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4093 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4096 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4097 iface, rect_count, rects, flags, color, depth, stencil);
4099 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4101 struct wined3d_surface *ds = device->depth_stencil;
4104 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4105 /* TODO: What about depth stencil buffers without stencil bits? */
4106 return WINED3DERR_INVALIDCALL;
4108 else if (flags & WINED3DCLEAR_TARGET)
4110 if(ds->resource.width < device->render_targets[0]->resource.width ||
4111 ds->resource.height < device->render_targets[0]->resource.height)
4113 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4119 device_get_draw_rect(device, &draw_rect);
4121 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4122 device->render_targets, device->depth_stencil, rect_count, rects,
4123 &draw_rect, flags, &c, depth, stencil);
4126 void CDECL wined3d_device_set_primitive_type(IWineD3DDevice *iface,
4127 WINED3DPRIMITIVETYPE primitive_type)
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4131 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4133 This->updateStateBlock->changed.primitive_type = TRUE;
4134 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4137 void CDECL wined3d_device_get_primitive_type(IWineD3DDevice *iface,
4138 WINED3DPRIMITIVETYPE *primitive_type)
4140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4144 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4146 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4149 HRESULT CDECL wined3d_device_draw_primitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4155 if (!This->stateBlock->state.vertex_declaration)
4157 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4158 return WINED3DERR_INVALIDCALL;
4161 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4162 if (This->stateBlock->state.user_stream)
4164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4165 This->stateBlock->state.user_stream = FALSE;
4168 if (This->stateBlock->state.load_base_vertex_index)
4170 This->stateBlock->state.load_base_vertex_index = 0;
4171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4173 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4174 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4178 HRESULT CDECL wined3d_device_draw_indexed_primitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 struct wined3d_buffer *index_buffer;
4185 index_buffer = This->stateBlock->state.index_buffer;
4188 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4189 * without an index buffer set. (The first time at least...)
4190 * D3D8 simply dies, but I doubt it can do much harm to return
4191 * D3DERR_INVALIDCALL there as well. */
4192 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4193 return WINED3DERR_INVALIDCALL;
4196 if (!This->stateBlock->state.vertex_declaration)
4198 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4199 return WINED3DERR_INVALIDCALL;
4202 if (This->stateBlock->state.user_stream)
4204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4205 This->stateBlock->state.user_stream = FALSE;
4207 vbo = index_buffer->buffer_object;
4209 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4211 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4216 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4218 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4222 drawPrimitive(This, index_count, startIndex, idxStride,
4223 vbo ? NULL : index_buffer->resource.allocatedMemory);
4228 HRESULT CDECL wined3d_device_draw_primitive_up(IWineD3DDevice *iface, UINT vertex_count,
4229 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4232 struct wined3d_stream_state *stream;
4233 struct wined3d_buffer *vb;
4235 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4236 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4238 if (!This->stateBlock->state.vertex_declaration)
4240 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4241 return WINED3DERR_INVALIDCALL;
4244 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4245 stream = &This->stateBlock->state.streams[0];
4246 vb = stream->buffer;
4247 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4249 wined3d_buffer_decref(vb);
4251 stream->stride = VertexStreamZeroStride;
4252 This->stateBlock->state.user_stream = TRUE;
4253 This->stateBlock->state.load_base_vertex_index = 0;
4255 /* TODO: Only mark dirty if drawing from a different UP address */
4256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4258 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4260 /* MSDN specifies stream zero settings must be set to NULL */
4261 stream->buffer = NULL;
4264 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4265 * the new stream sources or use UP drawing again
4270 HRESULT CDECL wined3d_device_draw_indexed_primitive_up(IWineD3DDevice *iface,
4271 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4272 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 struct wined3d_stream_state *stream;
4277 struct wined3d_buffer *vb, *ib;
4279 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4280 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4282 if (!This->stateBlock->state.vertex_declaration)
4284 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4285 return WINED3DERR_INVALIDCALL;
4288 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4294 stream = &This->stateBlock->state.streams[0];
4295 vb = stream->buffer;
4296 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4298 wined3d_buffer_decref(vb);
4300 stream->stride = VertexStreamZeroStride;
4301 This->stateBlock->state.user_stream = TRUE;
4303 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4304 This->stateBlock->state.base_vertex_index = 0;
4305 This->stateBlock->state.load_base_vertex_index = 0;
4306 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4310 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4312 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4313 stream->buffer = NULL;
4315 ib = This->stateBlock->state.index_buffer;
4318 wined3d_buffer_decref(ib);
4319 This->stateBlock->state.index_buffer = NULL;
4321 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4322 * SetStreamSource to specify a vertex buffer
4328 HRESULT CDECL wined3d_device_draw_primitive_strided(IWineD3DDevice *iface,
4329 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4333 /* Mark the state dirty until we have nicer tracking
4334 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4339 This->stateBlock->state.base_vertex_index = 0;
4340 This->up_strided = DrawPrimStrideData;
4341 drawPrimitive(This, vertex_count, 0, 0, NULL);
4342 This->up_strided = NULL;
4346 HRESULT CDECL wined3d_device_draw_indexed_primitive_strided(IWineD3DDevice *iface,
4347 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4348 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4351 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4353 /* Mark the state dirty until we have nicer tracking
4354 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4359 This->stateBlock->state.user_stream = TRUE;
4360 This->stateBlock->state.base_vertex_index = 0;
4361 This->up_strided = DrawPrimStrideData;
4362 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4363 This->up_strided = NULL;
4367 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4368 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4369 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
4371 WINED3DLOCKED_BOX src;
4372 WINED3DLOCKED_BOX dst;
4375 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4376 iface, src_volume, dst_volume);
4378 /* TODO: Implement direct loading into the gl volume instead of using
4379 * memcpy and dirtification to improve loading performance. */
4380 hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY);
4381 if (FAILED(hr)) return hr;
4382 hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD);
4385 wined3d_volume_unmap(src_volume);
4389 memcpy(dst.pBits, src.pBits, dst_volume->resource.size);
4391 hr = wined3d_volume_unmap(dst_volume);
4393 wined3d_volume_unmap(src_volume);
4395 hr = wined3d_volume_unmap(src_volume);
4400 HRESULT CDECL wined3d_device_update_texture(IWineD3DDevice *iface,
4401 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
4403 unsigned int level_count, i;
4404 WINED3DRESOURCETYPE type;
4407 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4409 /* Verify that the source and destination textures are non-NULL. */
4410 if (!src_texture || !dst_texture)
4412 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4413 return WINED3DERR_INVALIDCALL;
4416 if (src_texture == dst_texture)
4418 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4419 return WINED3DERR_INVALIDCALL;
4422 /* Verify that the source and destination textures are the same type. */
4423 type = wined3d_texture_get_type(src_texture);
4424 if (wined3d_texture_get_type(dst_texture) != type)
4426 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4427 return WINED3DERR_INVALIDCALL;
4430 /* Check that both textures have the identical numbers of levels. */
4431 level_count = wined3d_texture_get_level_count(src_texture);
4432 if (wined3d_texture_get_level_count(dst_texture) != level_count)
4434 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4435 return WINED3DERR_INVALIDCALL;
4438 /* Make sure that the destination texture is loaded. */
4439 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
4441 /* Update every surface level of the texture. */
4444 case WINED3DRTYPE_TEXTURE:
4446 struct wined3d_surface *src_surface;
4447 struct wined3d_surface *dst_surface;
4449 for (i = 0; i < level_count; ++i)
4451 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4452 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4453 hr = wined3d_device_update_surface(iface, src_surface, NULL, dst_surface, NULL);
4456 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4463 case WINED3DRTYPE_CUBETEXTURE:
4465 struct wined3d_surface *src_surface;
4466 struct wined3d_surface *dst_surface;
4468 for (i = 0; i < level_count * 6; ++i)
4470 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4471 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4472 hr = wined3d_device_update_surface(iface, src_surface, NULL, dst_surface, NULL);
4475 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4482 case WINED3DRTYPE_VOLUMETEXTURE:
4484 for (i = 0; i < level_count; ++i)
4486 hr = IWineD3DDeviceImpl_UpdateVolume(iface,
4487 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
4488 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
4491 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4499 FIXME("Unsupported texture type %#x.\n", type);
4500 return WINED3DERR_INVALIDCALL;
4506 HRESULT CDECL wined3d_device_get_front_buffer_data(IWineD3DDevice *iface,
4507 UINT swapchain_idx, struct wined3d_surface *dst_surface)
4509 struct wined3d_swapchain *swapchain;
4512 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
4514 hr = wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain);
4515 if (FAILED(hr)) return hr;
4517 hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
4518 wined3d_swapchain_decref(swapchain);
4523 HRESULT CDECL wined3d_device_validate_device(IWineD3DDevice *iface, DWORD *pNumPasses)
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4526 const struct wined3d_state *state = &This->stateBlock->state;
4527 struct wined3d_texture *texture;
4530 TRACE("(%p) : %p\n", This, pNumPasses);
4532 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4534 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
4536 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4537 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4539 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
4541 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4542 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4545 texture = state->textures[i];
4546 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
4548 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
4550 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4553 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
4555 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4558 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
4559 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
4561 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4566 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
4567 state->render_states[WINED3DRS_STENCILENABLE])
4569 struct wined3d_surface *ds = This->depth_stencil;
4570 struct wined3d_surface *target = This->render_targets[0];
4573 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
4575 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
4576 return WINED3DERR_CONFLICTINGRENDERSTATE;
4580 /* return a sensible default */
4583 TRACE("returning D3D_OK\n");
4587 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4591 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4593 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
4594 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
4595 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
4597 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4602 HRESULT CDECL wined3d_device_set_palette_entries(IWineD3DDevice *iface,
4603 UINT palette_idx, const PALETTEENTRY *entries)
4605 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4608 TRACE("device %p, palette_idx %u, entries %p.\n", device, palette_idx, entries);
4610 if (palette_idx >= MAX_PALETTES)
4612 WARN("Invalid palette index %u.\n", palette_idx);
4613 return WINED3DERR_INVALIDCALL;
4616 if (palette_idx >= device->palette_count)
4618 UINT new_size = device->palette_count;
4619 PALETTEENTRY **palettes;
4624 } while (palette_idx >= new_size);
4625 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, device->palettes, sizeof(*palettes) * new_size);
4628 ERR("Out of memory!\n");
4629 return E_OUTOFMEMORY;
4631 device->palettes = palettes;
4632 device->palette_count = new_size;
4635 if (!device->palettes[palette_idx])
4637 device->palettes[palette_idx] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4638 if (!device->palettes[palette_idx])
4640 ERR("Out of memory!\n");
4641 return E_OUTOFMEMORY;
4645 for (i = 0; i < 256; ++i)
4647 device->palettes[palette_idx][i].peRed = entries[i].peRed;
4648 device->palettes[palette_idx][i].peGreen = entries[i].peGreen;
4649 device->palettes[palette_idx][i].peBlue = entries[i].peBlue;
4650 device->palettes[palette_idx][i].peFlags = entries[i].peFlags;
4653 if (palette_idx == device->currentPalette)
4654 dirtify_p8_texture_samplers(device);
4659 HRESULT CDECL wined3d_device_get_palette_entries(IWineD3DDevice *iface,
4660 UINT palette_idx, PALETTEENTRY *entries)
4662 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4665 TRACE("device %p, palette_idx %u, entries %p.\n", device, palette_idx, entries);
4667 if (palette_idx >= device->palette_count || !device->palettes[palette_idx])
4669 /* What happens in such situation isn't documented; Native seems to
4670 * silently abort on such conditions. */
4671 WARN("Invalid palette index %u.\n", palette_idx);
4672 return WINED3DERR_INVALIDCALL;
4675 for (i = 0; i < 256; ++i)
4677 entries[i].peRed = device->palettes[palette_idx][i].peRed;
4678 entries[i].peGreen = device->palettes[palette_idx][i].peGreen;
4679 entries[i].peBlue = device->palettes[palette_idx][i].peBlue;
4680 entries[i].peFlags = device->palettes[palette_idx][i].peFlags;
4686 HRESULT CDECL wined3d_device_set_current_texture_palette(IWineD3DDevice *iface, UINT palette_idx)
4688 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4690 TRACE("device %p, palette_idx %u.\n", device, palette_idx);
4692 /* Native appears to silently abort on attempt to make an uninitialized
4693 * palette current and render. (tested with reference rasterizer). */
4694 if (palette_idx >= device->palette_count || !device->palettes[palette_idx])
4696 WARN("Invalid palette index %u.\n", palette_idx);
4697 return WINED3DERR_INVALIDCALL;
4700 /* TODO: stateblocks? */
4701 if (device->currentPalette != palette_idx)
4703 device->currentPalette = palette_idx;
4704 dirtify_p8_texture_samplers(device);
4710 HRESULT CDECL wined3d_device_get_current_texture_palette(IWineD3DDevice *iface, UINT *palette_idx)
4712 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4714 TRACE("device %p, palette_idx %p.\n", device, palette_idx);
4717 return WINED3DERR_INVALIDCALL;
4719 *palette_idx = device->currentPalette;
4724 HRESULT CDECL wined3d_device_set_software_vertex_processing(IWineD3DDevice *iface, BOOL software)
4726 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4729 TRACE("device %p, software %#x.\n", device, software);
4733 FIXME("device %p, software %#x stub!\n", device, software);
4737 device->softwareVertexProcessing = software;
4742 BOOL CDECL wined3d_device_get_software_vertex_processing(IWineD3DDevice *iface)
4744 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4747 TRACE("device %p.\n", device);
4751 TRACE("device %p stub!\n", device);
4755 return device->softwareVertexProcessing;
4758 HRESULT CDECL wined3d_device_get_raster_status(IWineD3DDevice *iface,
4759 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4761 struct wined3d_swapchain *swapchain;
4764 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4765 iface, swapchain_idx, raster_status);
4767 hr = wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain);
4770 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4774 hr = wined3d_swapchain_get_raster_status(swapchain, raster_status);
4775 wined3d_swapchain_decref(swapchain);
4778 WARN("Failed to get raster status, hr %#x.\n", hr);
4785 HRESULT CDECL wined3d_device_set_npatch_mode(IWineD3DDevice *iface, float segments)
4789 TRACE("iface %p, segments %.8e.\n", iface, segments);
4791 if (segments != 0.0f)
4795 FIXME("iface %p, segments %.8e stub!\n", iface, segments);
4803 float CDECL wined3d_device_get_npatch_mode(IWineD3DDevice *iface)
4807 TRACE("iface %p.\n", iface);
4811 FIXME("iface %p stub!\n", iface);
4818 HRESULT CDECL wined3d_device_update_surface(IWineD3DDevice *iface,
4819 struct wined3d_surface *src_surface, const RECT *src_rect,
4820 struct wined3d_surface *dst_surface, const POINT *dst_point)
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 const struct wined3d_format *src_format;
4824 const struct wined3d_format *dst_format;
4825 const struct wined3d_gl_info *gl_info;
4826 struct wined3d_context *context;
4827 const unsigned char *data;
4828 UINT update_w, update_h;
4829 CONVERT_TYPES convert;
4833 struct wined3d_format format;
4835 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
4836 iface, src_surface, wine_dbgstr_rect(src_rect),
4837 dst_surface, wine_dbgstr_point(dst_point));
4839 if (src_surface->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_surface->resource.pool != WINED3DPOOL_DEFAULT)
4841 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
4842 src_surface, dst_surface);
4843 return WINED3DERR_INVALIDCALL;
4846 src_format = src_surface->resource.format;
4847 dst_format = dst_surface->resource.format;
4849 if (src_format->id != dst_format->id)
4851 WARN("Source and destination surfaces should have the same format.\n");
4852 return WINED3DERR_INVALIDCALL;
4855 dst_x = dst_point ? dst_point->x : 0;
4856 dst_y = dst_point ? dst_point->y : 0;
4858 /* This call loads the OpenGL surface directly, instead of copying the
4859 * surface to the destination's sysmem copy. If surface conversion is
4860 * needed, use BltFast instead to copy in sysmem and use regular surface
4862 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
4863 if (convert != NO_CONVERSION || format.convert)
4864 return wined3d_surface_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
4866 context = context_acquire(This, NULL);
4867 gl_info = context->gl_info;
4870 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4871 checkGLcall("glActiveTextureARB");
4874 /* Make sure the surface is loaded and up to date */
4875 surface_internal_preload(dst_surface, SRGB_RGB);
4876 surface_bind(dst_surface, gl_info, FALSE);
4878 src_w = src_surface->resource.width;
4879 src_h = src_surface->resource.height;
4880 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
4881 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
4883 data = src_surface->resource.allocatedMemory;
4884 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
4888 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
4890 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
4891 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
4892 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
4896 data += (src_rect->top / src_format->block_height) * src_pitch;
4897 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
4900 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
4901 "format %#x, image_size %#x, data %p.\n", dst_surface->texture_target, dst_surface->texture_level,
4902 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
4904 if (row_length == src_pitch)
4906 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_surface->texture_target, dst_surface->texture_level,
4907 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
4913 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
4914 * can't use the unpack row length like below. */
4915 for (row = 0, y = dst_y; row < row_count; ++row)
4917 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_surface->texture_target, dst_surface->texture_level,
4918 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
4919 y += src_format->block_height;
4923 checkGLcall("glCompressedTexSubImage2DARB");
4929 data += src_rect->top * src_w * src_format->byte_count;
4930 data += src_rect->left * src_format->byte_count;
4933 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
4934 dst_surface->texture_target, dst_surface->texture_level, dst_x, dst_y,
4935 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
4937 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
4938 glTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level, dst_x, dst_y,
4939 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
4940 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4941 checkGLcall("glTexSubImage2D");
4945 context_release(context);
4947 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
4948 sampler = This->rev_tex_unit_map[0];
4949 if (sampler != WINED3D_UNMAPPED_STAGE)
4951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
4957 HRESULT CDECL wined3d_device_draw_rect_patch(IWineD3DDevice *iface, UINT Handle,
4958 const float *pNumSegs, const WINED3DRECTPATCH_INFO *pRectPatchInfo)
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 struct WineD3DRectPatch *patch;
4962 GLenum old_primitive_type;
4966 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4968 if(!(Handle || pRectPatchInfo)) {
4969 /* TODO: Write a test for the return value, thus the FIXME */
4970 FIXME("Both Handle and pRectPatchInfo are NULL\n");
4971 return WINED3DERR_INVALIDCALL;
4975 i = PATCHMAP_HASHFUNC(Handle);
4977 LIST_FOR_EACH(e, &This->patches[i]) {
4978 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
4979 if(patch->Handle == Handle) {
4986 TRACE("Patch does not exist. Creating a new one\n");
4987 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
4988 patch->Handle = Handle;
4989 list_add_head(&This->patches[i], &patch->entry);
4991 TRACE("Found existing patch %p\n", patch);
4994 /* Since opengl does not load tesselated vertex attributes into numbered vertex
4995 * attributes we have to tesselate, read back, and draw. This needs a patch
4996 * management structure instance. Create one.
4998 * A possible improvement is to check if a vertex shader is used, and if not directly
5001 FIXME("Drawing an uncached patch. This is slow\n");
5002 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5005 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5006 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5007 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5010 TRACE("Tesselation density or patch info changed, retesselating\n");
5012 if(pRectPatchInfo) {
5013 patch->RectPatchInfo = *pRectPatchInfo;
5015 patch->numSegs[0] = pNumSegs[0];
5016 patch->numSegs[1] = pNumSegs[1];
5017 patch->numSegs[2] = pNumSegs[2];
5018 patch->numSegs[3] = pNumSegs[3];
5020 hr = tesselate_rectpatch(This, patch);
5022 WARN("Patch tesselation failed\n");
5024 /* Do not release the handle to store the params of the patch */
5026 HeapFree(GetProcessHeap(), 0, patch);
5032 This->currentPatch = patch;
5033 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5034 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5035 wined3d_device_draw_primitive_strided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5036 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5037 This->currentPatch = NULL;
5039 /* Destroy uncached patches */
5041 HeapFree(GetProcessHeap(), 0, patch->mem);
5042 HeapFree(GetProcessHeap(), 0, patch);
5047 HRESULT CDECL wined3d_device_draw_tri_patch(IWineD3DDevice *iface, UINT handle,
5048 const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5050 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5051 iface, handle, segment_count, patch_info);
5056 HRESULT CDECL wined3d_device_delete_patch(IWineD3DDevice *iface, UINT Handle)
5058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5060 struct WineD3DRectPatch *patch;
5062 TRACE("(%p) Handle(%d)\n", This, Handle);
5064 i = PATCHMAP_HASHFUNC(Handle);
5065 LIST_FOR_EACH(e, &This->patches[i]) {
5066 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5067 if(patch->Handle == Handle) {
5068 TRACE("Deleting patch %p\n", patch);
5069 list_remove(&patch->entry);
5070 HeapFree(GetProcessHeap(), 0, patch->mem);
5071 HeapFree(GetProcessHeap(), 0, patch);
5076 /* TODO: Write a test for the return value */
5077 FIXME("Attempt to destroy nonexistent patch\n");
5078 return WINED3DERR_INVALIDCALL;
5081 /* Do not call while under the GL lock. */
5082 HRESULT CDECL wined3d_device_color_fill(IWineD3DDevice *iface,
5083 struct wined3d_surface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5085 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5086 iface, surface, wine_dbgstr_rect(rect),
5087 color->r, color->g, color->b, color->a);
5089 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM)
5091 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5092 return WINED3DERR_INVALIDCALL;
5095 return surface_color_fill(surface, rect, color);
5098 /* Do not call while under the GL lock. */
5099 void CDECL wined3d_device_clear_rendertarget_view(IWineD3DDevice *iface,
5100 struct wined3d_rendertarget_view *rendertarget_view, const WINED3DCOLORVALUE *color)
5102 struct wined3d_resource *resource;
5105 resource = rendertarget_view->resource;
5106 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5108 FIXME("Only supported on surface resources\n");
5112 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5113 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5116 HRESULT CDECL wined3d_device_get_render_target(IWineD3DDevice *iface,
5117 DWORD render_target_idx, struct wined3d_surface **render_target)
5119 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5121 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5122 iface, render_target_idx, render_target);
5124 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5126 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5127 return WINED3DERR_INVALIDCALL;
5130 *render_target = device->render_targets[render_target_idx];
5132 wined3d_surface_incref(*render_target);
5134 TRACE("Returning render target %p.\n", *render_target);
5139 HRESULT CDECL wined3d_device_get_depth_stencil(IWineD3DDevice *iface, struct wined3d_surface **depth_stencil)
5141 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5143 TRACE("device %p, depth_stencil %p.\n", device, depth_stencil);
5145 *depth_stencil = device->depth_stencil;
5146 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5148 if (!*depth_stencil)
5149 return WINED3DERR_NOTFOUND;
5151 wined3d_surface_incref(*depth_stencil);
5156 HRESULT CDECL wined3d_device_set_render_target(IWineD3DDevice *iface,
5157 DWORD render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
5159 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5160 struct wined3d_surface *prev;
5162 TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5163 device, render_target_idx, render_target, set_viewport);
5165 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5167 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5168 return WINED3DERR_INVALIDCALL;
5171 prev = device->render_targets[render_target_idx];
5172 if (render_target == prev)
5174 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5178 /* Render target 0 can't be set to NULL. */
5179 if (!render_target && !render_target_idx)
5181 WARN("Trying to set render target 0 to NULL.\n");
5182 return WINED3DERR_INVALIDCALL;
5185 if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
5187 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5188 return WINED3DERR_INVALIDCALL;
5192 wined3d_surface_incref(render_target);
5193 device->render_targets[render_target_idx] = render_target;
5194 /* Release after the assignment, to prevent device_resource_released()
5195 * from seeing the surface as still in use. */
5197 wined3d_surface_decref(prev);
5199 /* Render target 0 is special. */
5200 if (!render_target_idx && set_viewport)
5202 /* Set the viewport and scissor rectangles, if requested. Tests show
5203 * that stateblock recording is ignored, the change goes directly
5204 * into the primary stateblock. */
5205 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5206 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5207 device->stateBlock->state.viewport.X = 0;
5208 device->stateBlock->state.viewport.Y = 0;
5209 device->stateBlock->state.viewport.MaxZ = 1.0f;
5210 device->stateBlock->state.viewport.MinZ = 0.0f;
5211 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5213 device->stateBlock->state.scissor_rect.top = 0;
5214 device->stateBlock->state.scissor_rect.left = 0;
5215 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5216 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5217 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5223 HRESULT CDECL wined3d_device_set_depth_stencil(IWineD3DDevice *iface, struct wined3d_surface *depth_stencil)
5225 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5226 struct wined3d_surface *tmp;
5228 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n",
5229 device, depth_stencil, device->depth_stencil);
5231 if (device->depth_stencil == depth_stencil)
5233 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5237 if (device->depth_stencil)
5239 if (device->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5240 || device->depth_stencil->flags & SFLAG_DISCARD)
5242 surface_modify_ds_location(device->depth_stencil, SFLAG_DS_DISCARDED,
5243 device->depth_stencil->resource.width,
5244 device->depth_stencil->resource.height);
5245 if (device->depth_stencil == device->onscreen_depth_stencil)
5247 wined3d_surface_decref(device->onscreen_depth_stencil);
5248 device->onscreen_depth_stencil = NULL;
5253 tmp = device->depth_stencil;
5254 device->depth_stencil = depth_stencil;
5255 if (device->depth_stencil)
5256 wined3d_surface_incref(device->depth_stencil);
5258 wined3d_surface_decref(tmp);
5260 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5262 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5263 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZENABLE));
5264 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILENABLE));
5265 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5266 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5268 else if (tmp && tmp->resource.format->depth_size != device->depth_stencil->resource.format->depth_size)
5270 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5276 HRESULT CDECL wined3d_device_set_cursor_properties(IWineD3DDevice *iface,
5277 UINT XHotSpot, UINT YHotSpot, struct wined3d_surface *cursor_image)
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 WINED3DLOCKED_RECT lockedRect;
5282 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5283 iface, XHotSpot, YHotSpot, cursor_image);
5285 /* some basic validation checks */
5286 if (This->cursorTexture)
5288 struct wined3d_context *context = context_acquire(This, NULL);
5290 glDeleteTextures(1, &This->cursorTexture);
5292 context_release(context);
5293 This->cursorTexture = 0;
5296 if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
5297 This->haveHardwareCursor = TRUE;
5299 This->haveHardwareCursor = FALSE;
5303 WINED3DLOCKED_RECT rect;
5305 /* MSDN: Cursor must be A8R8G8B8 */
5306 if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5308 WARN("surface %p has an invalid format.\n", cursor_image);
5309 return WINED3DERR_INVALIDCALL;
5312 /* MSDN: Cursor must be smaller than the display mode */
5313 if (cursor_image->resource.width > This->ddraw_width
5314 || cursor_image->resource.height > This->ddraw_height)
5316 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5317 cursor_image, cursor_image->resource.width, cursor_image->resource.height,
5318 This->ddraw_width, This->ddraw_height);
5319 return WINED3DERR_INVALIDCALL;
5322 if (!This->haveHardwareCursor) {
5323 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5325 /* Do not store the surface's pointer because the application may
5326 * release it after setting the cursor image. Windows doesn't
5327 * addref the set surface, so we can't do this either without
5328 * creating circular refcount dependencies. Copy out the gl texture
5330 This->cursorWidth = cursor_image->resource.width;
5331 This->cursorHeight = cursor_image->resource.height;
5332 if (SUCCEEDED(wined3d_surface_map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5334 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5335 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5336 struct wined3d_context *context;
5337 char *mem, *bits = rect.pBits;
5338 GLint intfmt = format->glInternal;
5339 GLint gl_format = format->glFormat;
5340 GLint type = format->glType;
5341 INT height = This->cursorHeight;
5342 INT width = This->cursorWidth;
5343 INT bpp = format->byte_count;
5347 /* Reformat the texture memory (pitch and width can be
5349 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5350 for(i = 0; i < height; i++)
5351 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5352 wined3d_surface_unmap(cursor_image);
5354 context = context_acquire(This, NULL);
5358 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5360 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5361 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5364 /* Make sure that a proper texture unit is selected */
5365 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5366 checkGLcall("glActiveTextureARB");
5367 sampler = This->rev_tex_unit_map[0];
5368 if (sampler != WINED3D_UNMAPPED_STAGE)
5370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5372 /* Create a new cursor texture */
5373 glGenTextures(1, &This->cursorTexture);
5374 checkGLcall("glGenTextures");
5375 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5376 checkGLcall("glBindTexture");
5377 /* Copy the bitmap memory into the cursor texture */
5378 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5379 checkGLcall("glTexImage2D");
5380 HeapFree(GetProcessHeap(), 0, mem);
5382 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5384 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5385 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5390 context_release(context);
5394 FIXME("A cursor texture was not returned.\n");
5395 This->cursorTexture = 0;
5400 /* Draw a hardware cursor */
5401 ICONINFO cursorInfo;
5403 /* Create and clear maskBits because it is not needed for
5404 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5406 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5407 (cursor_image->resource.width * cursor_image->resource.height / 8));
5408 wined3d_surface_map(cursor_image, &lockedRect, NULL,
5409 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5410 TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
5412 cursorInfo.fIcon = FALSE;
5413 cursorInfo.xHotspot = XHotSpot;
5414 cursorInfo.yHotspot = YHotSpot;
5415 cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
5417 cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
5418 1, 32, lockedRect.pBits);
5419 wined3d_surface_unmap(cursor_image);
5420 /* Create our cursor and clean up. */
5421 cursor = CreateIconIndirect(&cursorInfo);
5423 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5424 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5426 This->hardwareCursor = cursor;
5427 HeapFree(GetProcessHeap(), 0, maskBits);
5431 This->xHotSpot = XHotSpot;
5432 This->yHotSpot = YHotSpot;
5436 void CDECL wined3d_device_set_cursor_position(IWineD3DDevice *iface,
5437 int XScreenSpace, int YScreenSpace, DWORD flags)
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5441 TRACE("iface %p, x %d, y %d, flags %#x.\n",
5442 iface, XScreenSpace, YScreenSpace, flags);
5444 This->xScreenSpace = XScreenSpace;
5445 This->yScreenSpace = YScreenSpace;
5448 BOOL CDECL wined3d_device_show_cursor(IWineD3DDevice* iface, BOOL bShow)
5450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5451 BOOL oldVisible = This->bCursorVisible;
5454 TRACE("(%p) : visible(%d)\n", This, bShow);
5457 * When ShowCursor is first called it should make the cursor appear at the OS's last
5458 * known cursor position. Because of this, some applications just repetitively call
5459 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5462 This->xScreenSpace = pt.x;
5463 This->yScreenSpace = pt.y;
5465 if (This->haveHardwareCursor) {
5466 This->bCursorVisible = bShow;
5468 SetCursor(This->hardwareCursor);
5474 if (This->cursorTexture)
5475 This->bCursorVisible = bShow;
5481 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
5483 TRACE("checking resource %p for eviction\n", resource);
5485 if (resource->pool == WINED3DPOOL_MANAGED)
5487 TRACE("Evicting %p.\n", resource);
5488 resource->resource_ops->resource_unload(resource);
5494 HRESULT CDECL wined3d_device_evict_managed_resources(IWineD3DDevice *iface)
5496 TRACE("iface %p.\n", iface);
5498 wined3d_device_enum_resources(iface, evict_managed_resource, NULL);
5499 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5500 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
5505 static HRESULT updateSurfaceDesc(struct wined3d_surface *surface,
5506 const WINED3DPRESENT_PARAMETERS *pPresentationParameters)
5508 IWineD3DDeviceImpl *device = surface->resource.device;
5509 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5511 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5512 if (surface->flags & SFLAG_DIBSECTION)
5514 /* Release the DC */
5515 SelectObject(surface->hDC, surface->dib.holdbitmap);
5516 DeleteDC(surface->hDC);
5517 /* Release the DIB section */
5518 DeleteObject(surface->dib.DIBsection);
5519 surface->dib.bitmap_data = NULL;
5520 surface->resource.allocatedMemory = NULL;
5521 surface->flags &= ~SFLAG_DIBSECTION;
5523 surface->resource.width = pPresentationParameters->BackBufferWidth;
5524 surface->resource.height = pPresentationParameters->BackBufferHeight;
5525 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
5526 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
5528 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5529 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5531 surface->pow2Width = surface->pow2Height = 1;
5532 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5533 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5536 if (surface->texture_name)
5538 struct wined3d_context *context = context_acquire(device, NULL);
5540 glDeleteTextures(1, &surface->texture_name);
5542 context_release(context);
5543 surface->texture_name = 0;
5544 surface->flags &= ~SFLAG_CLIENT;
5546 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
5547 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
5549 surface->flags |= SFLAG_NONPOW2;
5553 surface->flags &= ~SFLAG_NONPOW2;
5555 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
5556 surface->resource.allocatedMemory = NULL;
5557 surface->resource.heapMemory = NULL;
5558 surface->resource.size = wined3d_surface_get_pitch(surface) * surface->pow2Width;
5560 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
5562 if (!surface_init_sysmem(surface))
5564 return E_OUTOFMEMORY;
5569 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
5572 WINED3DDISPLAYMODE m;
5575 /* All Windowed modes are supported, as is leaving the current mode */
5576 if(pp->Windowed) return TRUE;
5577 if(!pp->BackBufferWidth) return TRUE;
5578 if(!pp->BackBufferHeight) return TRUE;
5580 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
5581 for (i = 0; i < count; ++i)
5583 memset(&m, 0, sizeof(m));
5584 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
5586 ERR("Failed to enumerate adapter mode.\n");
5587 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
5588 /* Mode found, it is supported. */
5591 /* Mode not found -> not supported */
5595 /* Do not call while under the GL lock. */
5596 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
5598 const struct wined3d_gl_info *gl_info;
5599 struct wined3d_context *context;
5600 struct wined3d_shader *shader;
5602 context = context_acquire(device, NULL);
5603 gl_info = context->gl_info;
5605 wined3d_device_enum_resources(device, device_unload_resource, NULL);
5606 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
5608 device->shader_backend->shader_destroy(shader);
5612 if (device->depth_blt_texture)
5614 glDeleteTextures(1, &device->depth_blt_texture);
5615 device->depth_blt_texture = 0;
5617 if (device->depth_blt_rb)
5619 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
5620 device->depth_blt_rb = 0;
5621 device->depth_blt_rb_w = 0;
5622 device->depth_blt_rb_h = 0;
5626 device->blitter->free_private(device);
5627 device->frag_pipe->free_private(device);
5628 device->shader_backend->shader_free_private(device);
5629 destroy_dummy_textures(device, gl_info);
5631 context_release(context);
5633 while (device->context_count)
5635 context_destroy(device, device->contexts[0]);
5637 HeapFree(GetProcessHeap(), 0, swapchain->context);
5638 swapchain->context = NULL;
5639 swapchain->num_contexts = 0;
5642 /* Do not call while under the GL lock. */
5643 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
5645 struct wined3d_context *context;
5646 struct wined3d_surface *target;
5649 /* Recreate the primary swapchain's context */
5650 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
5651 if (!swapchain->context)
5653 ERR("Failed to allocate memory for swapchain context array.\n");
5654 return E_OUTOFMEMORY;
5657 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
5658 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
5660 WARN("Failed to create context.\n");
5661 HeapFree(GetProcessHeap(), 0, swapchain->context);
5665 swapchain->context[0] = context;
5666 swapchain->num_contexts = 1;
5667 create_dummy_textures(device);
5668 context_release(context);
5670 hr = device->shader_backend->shader_alloc_private(device);
5673 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
5677 hr = device->frag_pipe->alloc_private(device);
5680 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
5681 device->shader_backend->shader_free_private(device);
5685 hr = device->blitter->alloc_private(device);
5688 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
5689 device->frag_pipe->free_private(device);
5690 device->shader_backend->shader_free_private(device);
5697 context_acquire(device, NULL);
5698 destroy_dummy_textures(device, context->gl_info);
5699 context_release(context);
5700 context_destroy(device, context);
5701 HeapFree(GetProcessHeap(), 0, swapchain->context);
5702 swapchain->num_contexts = 0;
5706 /* Do not call while under the GL lock. */
5707 HRESULT CDECL wined3d_device_reset(IWineD3DDevice *iface,
5708 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5711 struct wined3d_swapchain *swapchain;
5713 BOOL DisplayModeChanged = FALSE;
5714 WINED3DDISPLAYMODE mode;
5715 TRACE("(%p)\n", This);
5717 hr = wined3d_device_get_swapchain(iface, 0, &swapchain);
5720 ERR("Failed to get the first implicit swapchain\n");
5724 if(!is_display_mode_supported(This, pPresentationParameters)) {
5725 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
5726 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
5727 pPresentationParameters->BackBufferHeight);
5728 wined3d_swapchain_decref(swapchain);
5729 return WINED3DERR_INVALIDCALL;
5732 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5733 * on an existing gl context, so there's no real need for recreation.
5735 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5737 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5739 TRACE("New params:\n");
5740 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5741 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5742 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5743 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5744 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5745 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5746 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5747 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5748 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5749 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5750 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5751 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5752 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5754 /* No special treatment of these parameters. Just store them */
5755 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5756 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5757 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5758 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5760 /* What to do about these? */
5761 if (pPresentationParameters->BackBufferCount
5762 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
5763 ERR("Cannot change the back buffer count yet\n");
5765 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5766 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5767 ERR("Cannot change the back buffer format yet\n");
5770 if (pPresentationParameters->hDeviceWindow
5771 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
5772 ERR("Cannot change the device window yet\n");
5774 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
5778 TRACE("Creating the depth stencil buffer\n");
5780 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
5781 pPresentationParameters->BackBufferWidth,
5782 pPresentationParameters->BackBufferHeight,
5783 pPresentationParameters->AutoDepthStencilFormat,
5784 pPresentationParameters->MultiSampleType,
5785 pPresentationParameters->MultiSampleQuality,
5787 &This->auto_depth_stencil);
5790 ERR("Failed to create the depth stencil buffer.\n");
5791 wined3d_swapchain_decref(swapchain);
5792 return WINED3DERR_INVALIDCALL;
5796 if (This->onscreen_depth_stencil)
5798 wined3d_surface_decref(This->onscreen_depth_stencil);
5799 This->onscreen_depth_stencil = NULL;
5802 /* Reset the depth stencil */
5803 if (pPresentationParameters->EnableAutoDepthStencil)
5804 wined3d_device_set_depth_stencil(iface, This->auto_depth_stencil);
5806 wined3d_device_set_depth_stencil(iface, NULL);
5808 TRACE("Resetting stateblock\n");
5809 wined3d_stateblock_decref(This->updateStateBlock);
5810 wined3d_stateblock_decref(This->stateBlock);
5812 delete_opengl_contexts(This, swapchain);
5814 if(pPresentationParameters->Windowed) {
5815 mode.Width = swapchain->orig_width;
5816 mode.Height = swapchain->orig_height;
5817 mode.RefreshRate = 0;
5818 mode.Format = swapchain->presentParms.BackBufferFormat;
5820 mode.Width = pPresentationParameters->BackBufferWidth;
5821 mode.Height = pPresentationParameters->BackBufferHeight;
5822 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5823 mode.Format = swapchain->presentParms.BackBufferFormat;
5826 /* Should Width == 800 && Height == 0 set 800x600? */
5827 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
5828 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
5829 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5833 if(!pPresentationParameters->Windowed) {
5834 DisplayModeChanged = TRUE;
5836 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5837 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5839 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
5842 wined3d_swapchain_decref(swapchain);
5846 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
5848 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
5851 wined3d_swapchain_decref(swapchain);
5855 if (This->auto_depth_stencil)
5857 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
5860 wined3d_swapchain_decref(swapchain);
5866 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
5867 || DisplayModeChanged)
5869 wined3d_device_set_display_mode(iface, 0, &mode);
5871 if (!pPresentationParameters->Windowed)
5873 if (swapchain->presentParms.Windowed)
5875 HWND focus_window = This->createParms.hFocusWindow;
5877 focus_window = pPresentationParameters->hDeviceWindow;
5878 if (FAILED(hr = wined3d_device_acquire_focus_window(iface, focus_window)))
5880 ERR("Failed to acquire focus window, hr %#x.\n", hr);
5881 wined3d_swapchain_decref(swapchain);
5885 /* switch from windowed to fs */
5886 wined3d_device_setup_fullscreen_window(iface, swapchain->device_window,
5887 pPresentationParameters->BackBufferWidth,
5888 pPresentationParameters->BackBufferHeight);
5892 /* Fullscreen -> fullscreen mode change */
5893 MoveWindow(swapchain->device_window, 0, 0,
5894 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
5898 else if (!swapchain->presentParms.Windowed)
5900 /* Fullscreen -> windowed switch */
5901 wined3d_device_restore_fullscreen_window(iface, swapchain->device_window);
5902 wined3d_device_release_focus_window(iface);
5904 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5906 else if (!pPresentationParameters->Windowed)
5908 DWORD style = This->style, exStyle = This->exStyle;
5909 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
5910 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
5911 * Reset to clear up their mess. Guild Wars also loses the device during that.
5915 wined3d_device_setup_fullscreen_window(iface, swapchain->device_window,
5916 pPresentationParameters->BackBufferWidth,
5917 pPresentationParameters->BackBufferHeight);
5918 This->style = style;
5919 This->exStyle = exStyle;
5922 /* Note: No parent needed for initial internal stateblock */
5923 hr = wined3d_stateblock_create(iface, WINED3DSBT_INIT, &This->stateBlock);
5924 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
5925 else TRACE("Created stateblock %p\n", This->stateBlock);
5926 This->updateStateBlock = This->stateBlock;
5927 wined3d_stateblock_incref(This->updateStateBlock);
5929 stateblock_init_default_state(This->stateBlock);
5931 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5934 GetClientRect(swapchain->win_handle, &client_rect);
5936 if(!swapchain->presentParms.BackBufferCount)
5938 TRACE("Single buffered rendering\n");
5939 swapchain->render_to_fbo = FALSE;
5941 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
5942 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
5944 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
5945 swapchain->presentParms.BackBufferWidth,
5946 swapchain->presentParms.BackBufferHeight,
5947 client_rect.right, client_rect.bottom);
5948 swapchain->render_to_fbo = TRUE;
5952 TRACE("Rendering directly to GL_BACK\n");
5953 swapchain->render_to_fbo = FALSE;
5957 hr = create_primary_opengl_context(This, swapchain);
5958 wined3d_swapchain_decref(swapchain);
5960 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
5966 HRESULT CDECL wined3d_device_set_dialog_box_mode(IWineD3DDevice *iface, BOOL enable_dialogs)
5968 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
5970 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
5976 HRESULT CDECL wined3d_device_get_creation_parameters(IWineD3DDevice *iface,
5977 WINED3DDEVICE_CREATION_PARAMETERS *pParameters)
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5980 TRACE("(%p) : pParameters %p\n", This, pParameters);
5982 *pParameters = This->createParms;
5986 void CDECL wined3d_device_set_gamma_ramp(IWineD3DDevice *iface,
5987 UINT swapchain_idx, DWORD flags, const WINED3DGAMMARAMP *ramp)
5989 struct wined3d_swapchain *swapchain;
5991 TRACE("iface %p, swapchain_idx %u, flags %#x, ramp %p.\n",
5992 iface, swapchain_idx, flags, ramp);
5994 if (SUCCEEDED(wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain)))
5996 wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp);
5997 wined3d_swapchain_decref(swapchain);
6001 void CDECL wined3d_device_get_gamma_ramp(IWineD3DDevice *iface, UINT swapchain_idx, WINED3DGAMMARAMP *ramp)
6003 struct wined3d_swapchain *swapchain;
6005 TRACE("iface %p, swapchain_idx %u, ramp %p.\n",
6006 iface, swapchain_idx, ramp);
6008 if (SUCCEEDED(wined3d_device_get_swapchain(iface, swapchain_idx, &swapchain)))
6010 wined3d_swapchain_get_gamma_ramp(swapchain, ramp);
6011 wined3d_swapchain_decref(swapchain);
6015 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource)
6017 TRACE("device %p, resource %p.\n", device, resource);
6019 list_add_head(&device->resources, &resource->resource_list_entry);
6022 static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource)
6024 TRACE("device %p, resource %p.\n", device, resource);
6026 list_remove(&resource->resource_list_entry);
6029 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource)
6031 WINED3DRESOURCETYPE type = resource->resourceType;
6034 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6036 context_resource_released(device, resource, type);
6040 case WINED3DRTYPE_SURFACE:
6042 struct wined3d_surface *surface = surface_from_resource(resource);
6044 if (!device->d3d_initialized) break;
6046 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6048 if (device->render_targets[i] == surface)
6050 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6051 device->render_targets[i] = NULL;
6055 if (device->depth_stencil == surface)
6057 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6058 device->depth_stencil = NULL;
6063 case WINED3DRTYPE_TEXTURE:
6064 case WINED3DRTYPE_CUBETEXTURE:
6065 case WINED3DRTYPE_VOLUMETEXTURE:
6066 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6068 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6070 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6072 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6073 texture, device->stateBlock, i);
6074 device->stateBlock->state.textures[i] = NULL;
6077 if (device->updateStateBlock != device->stateBlock
6078 && device->updateStateBlock->state.textures[i] == texture)
6080 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6081 texture, device->updateStateBlock, i);
6082 device->updateStateBlock->state.textures[i] = NULL;
6087 case WINED3DRTYPE_BUFFER:
6089 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6091 for (i = 0; i < MAX_STREAMS; ++i)
6093 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6095 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6096 buffer, device->stateBlock, i);
6097 device->stateBlock->state.streams[i].buffer = NULL;
6100 if (device->updateStateBlock != device->stateBlock
6101 && device->updateStateBlock->state.streams[i].buffer == buffer)
6103 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6104 buffer, device->updateStateBlock, i);
6105 device->updateStateBlock->state.streams[i].buffer = NULL;
6110 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6112 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6113 buffer, device->stateBlock);
6114 device->stateBlock->state.index_buffer = NULL;
6117 if (device->updateStateBlock != device->stateBlock
6118 && device->updateStateBlock->state.index_buffer == buffer)
6120 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6121 buffer, device->updateStateBlock);
6122 device->updateStateBlock->state.index_buffer = NULL;
6131 /* Remove the resource from the resourceStore */
6132 device_resource_remove(device, resource);
6134 TRACE("Resource released.\n");
6137 HRESULT CDECL wined3d_device_enum_resources(IWineD3DDevice *iface,
6138 D3DCB_ENUMRESOURCES callback, void *data)
6140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6141 struct wined3d_resource *resource, *cursor;
6143 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6145 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6147 TRACE("enumerating resource %p.\n", resource);
6148 if (callback(resource, data) == S_FALSE)
6150 TRACE("Canceling enumeration.\n");
6158 HRESULT CDECL wined3d_device_get_surface_from_dc(IWineD3DDevice *iface,
6159 HDC dc, struct wined3d_surface **surface)
6161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6162 struct wined3d_resource *resource;
6164 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6166 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6168 struct wined3d_surface *s = surface_from_resource(resource);
6172 TRACE("Found surface %p for dc %p.\n", s, dc);
6179 return WINED3DERR_INVALIDCALL;
6182 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6183 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6184 IWineD3DDeviceParent *device_parent)
6186 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6187 const struct fragment_pipeline *fragment_pipeline;
6188 struct shader_caps shader_caps;
6189 struct fragment_caps ffp_caps;
6190 WINED3DDISPLAYMODE mode;
6195 device->wined3d = wined3d;
6196 wined3d_incref(device->wined3d);
6197 device->adapter = wined3d->adapter_count ? adapter : NULL;
6198 device->device_parent = device_parent;
6199 list_init(&device->resources);
6200 list_init(&device->shaders);
6202 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6204 /* Get the initial screen setup for ddraw. */
6205 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
6208 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6209 wined3d_decref(device->wined3d);
6212 device->ddraw_width = mode.Width;
6213 device->ddraw_height = mode.Height;
6214 device->ddraw_format = mode.Format;
6216 /* Save the creation parameters. */
6217 device->createParms.AdapterOrdinal = adapter_idx;
6218 device->createParms.DeviceType = device_type;
6219 device->createParms.hFocusWindow = focus_window;
6220 device->createParms.BehaviorFlags = flags;
6222 device->devType = device_type;
6223 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6225 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6226 device->shader_backend = adapter->shader_backend;
6228 if (device->shader_backend)
6230 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6231 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6232 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6233 device->vs_clipping = shader_caps.VSClipping;
6235 fragment_pipeline = adapter->fragment_pipe;
6236 device->frag_pipe = fragment_pipeline;
6237 if (fragment_pipeline)
6239 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6240 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6242 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6243 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6246 ERR("Failed to compile state table, hr %#x.\n", hr);
6247 wined3d_decref(device->wined3d);
6251 device->blitter = adapter->blitter;
6257 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6258 DWORD rep = This->StateTable[state].representative;
6259 struct wined3d_context *context;
6264 for (i = 0; i < This->context_count; ++i)
6266 context = This->contexts[i];
6267 if(isStateDirty(context, rep)) continue;
6269 context->dirtyArray[context->numDirtyEntries++] = rep;
6270 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6271 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6272 context->isStateDirty[idx] |= (1 << shift);
6276 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6278 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6279 *width = context->current_rt->pow2Width;
6280 *height = context->current_rt->pow2Height;
6283 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6285 struct wined3d_swapchain *swapchain = context->swapchain;
6286 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6287 * current context's drawable, which is the size of the back buffer of the swapchain
6288 * the active context belongs to. */
6289 *width = swapchain->presentParms.BackBufferWidth;
6290 *height = swapchain->presentParms.BackBufferHeight;
6293 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
6294 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6296 if (device->filter_messages)
6298 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6299 window, message, wparam, lparam);
6301 return DefWindowProcW(window, message, wparam, lparam);
6303 return DefWindowProcA(window, message, wparam, lparam);
6306 if (message == WM_DESTROY)
6308 TRACE("unregister window %p.\n", window);
6309 wined3d_unregister_window(window);
6311 if (device->focus_window == window) device->focus_window = NULL;
6312 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6316 return CallWindowProcW(proc, window, message, wparam, lparam);
6318 return CallWindowProcA(proc, window, message, wparam, lparam);