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, IWineD3DSurfaceImpl *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 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
587 device->onscreen_depth_stencil = depth_stencil;
588 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
591 static BOOL is_full_clear(IWineD3DSurfaceImpl *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(IWineD3DSurfaceImpl *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, IWineD3DSurfaceImpl **rts,
655 IWineD3DSurfaceImpl *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 IWineD3DSurfaceImpl *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);
832 /**********************************************************
833 * IUnknown parts follows
834 **********************************************************/
836 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
838 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
840 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
841 || IsEqualGUID(riid, &IID_IUnknown))
843 IUnknown_AddRef(iface);
848 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
851 return E_NOINTERFACE;
854 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 ULONG refCount = InterlockedIncrement(&This->ref);
858 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
862 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
864 ULONG refCount = InterlockedDecrement(&This->ref);
866 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
871 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
872 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
873 This->multistate_funcs[i] = NULL;
876 /* TODO: Clean up all the surfaces and textures! */
877 /* NOTE: You must release the parent if the object was created via a callback
878 ** ***************************/
880 if (!list_empty(&This->resources))
882 struct wined3d_resource *resource;
883 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
885 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
887 FIXME("Leftover resource %p with type %s (%#x).\n",
888 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
892 if(This->contexts) ERR("Context array not freed!\n");
893 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
894 This->haveHardwareCursor = FALSE;
896 wined3d_decref(This->wined3d);
897 This->wined3d = NULL;
898 HeapFree(GetProcessHeap(), 0, This);
899 TRACE("Freed device %p\n", This);
905 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
906 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 struct wined3d_buffer *object;
912 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
917 ERR("Failed to allocate memory\n");
918 return E_OUTOFMEMORY;
921 FIXME("Ignoring access flags (pool)\n");
923 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
924 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
927 WARN("Failed to initialize buffer, hr %#x.\n", hr);
928 HeapFree(GetProcessHeap(), 0, object);
931 object->desc = *desc;
933 TRACE("Created buffer %p.\n", object);
940 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
941 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
944 struct wined3d_buffer *object;
947 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
948 iface, Size, Usage, Pool, parent, parent_ops, buffer);
950 if (Pool == WINED3DPOOL_SCRATCH)
952 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
953 * anyway, SCRATCH vertex buffers aren't usable anywhere
955 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
960 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
963 ERR("Out of memory\n");
965 return WINED3DERR_OUTOFVIDEOMEMORY;
968 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
969 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
972 WARN("Failed to initialize buffer, hr %#x.\n", hr);
973 HeapFree(GetProcessHeap(), 0, object);
977 TRACE("Created buffer %p.\n", object);
983 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
984 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
987 struct wined3d_buffer *object;
990 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
991 iface, Length, Usage, Pool, parent, parent_ops, buffer);
993 /* Allocate the storage for the device */
994 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
997 ERR("Out of memory\n");
999 return WINED3DERR_OUTOFVIDEOMEMORY;
1002 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
1003 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1004 parent, parent_ops);
1007 WARN("Failed to initialize buffer, hr %#x\n", hr);
1008 HeapFree(GetProcessHeap(), 0, object);
1012 TRACE("Created buffer %p.\n", object);
1019 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1020 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1023 struct wined3d_stateblock *object;
1026 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1029 ERR("Failed to allocate stateblock memory.\n");
1030 return E_OUTOFMEMORY;
1033 hr = stateblock_init(object, This, type);
1036 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1037 HeapFree(GetProcessHeap(), 0, object);
1041 TRACE("Created stateblock %p.\n", object);
1042 *stateblock = object;
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1048 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1049 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1050 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1053 IWineD3DSurfaceImpl *object;
1056 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1057 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1058 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1059 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1060 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1062 if (Impl == SURFACE_OPENGL && !This->adapter)
1064 ERR("OpenGL surfaces are not available without OpenGL.\n");
1065 return WINED3DERR_NOTAVAILABLE;
1068 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1071 ERR("Failed to allocate surface memory.\n");
1072 return WINED3DERR_OUTOFVIDEOMEMORY;
1075 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1076 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1079 WARN("Failed to initialize surface, returning %#x.\n", hr);
1080 HeapFree(GetProcessHeap(), 0, object);
1084 TRACE("(%p) : Created surface %p\n", This, object);
1086 *surface = (IWineD3DSurface *)object;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1092 struct wined3d_resource *resource, void *parent, struct wined3d_rendertarget_view **rendertarget_view)
1094 struct wined3d_rendertarget_view *object;
1096 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1097 iface, resource, parent, rendertarget_view);
1099 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1102 ERR("Failed to allocate memory\n");
1103 return E_OUTOFMEMORY;
1106 wined3d_rendertarget_view_init(object, resource, parent);
1108 TRACE("Created render target view %p.\n", object);
1109 *rendertarget_view = object;
1114 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1115 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1116 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1119 struct wined3d_texture *object;
1122 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1123 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1124 Format, debug_d3dformat(Format), Pool, texture, parent);
1126 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1129 ERR("Out of memory\n");
1131 return WINED3DERR_OUTOFVIDEOMEMORY;
1134 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1137 WARN("Failed to initialize texture, returning %#x\n", hr);
1138 HeapFree(GetProcessHeap(), 0, object);
1145 TRACE("(%p) : Created texture %p\n", This, object);
1150 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1151 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1152 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1155 struct wined3d_texture *object;
1158 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1159 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1161 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1164 ERR("Out of memory\n");
1166 return WINED3DERR_OUTOFVIDEOMEMORY;
1169 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1172 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1173 HeapFree(GetProcessHeap(), 0, object);
1178 TRACE("(%p) : Created volume texture %p.\n", This, object);
1184 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1185 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1186 const struct wined3d_parent_ops *parent_ops, struct wined3d_volume **volume)
1188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1189 struct wined3d_volume *object;
1192 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1193 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1195 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1198 ERR("Out of memory\n");
1200 return WINED3DERR_OUTOFVIDEOMEMORY;
1203 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1206 WARN("Failed to initialize volume, returning %#x.\n", hr);
1207 HeapFree(GetProcessHeap(), 0, object);
1211 TRACE("(%p) : Created volume %p.\n", This, object);
1217 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1218 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1219 const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 struct wined3d_texture *object;
1225 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1228 ERR("Out of memory\n");
1230 return WINED3DERR_OUTOFVIDEOMEMORY;
1233 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1236 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1237 HeapFree(GetProcessHeap(), 0, object);
1242 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1249 WINED3DQUERYTYPE type, struct wined3d_query **query)
1251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1252 struct wined3d_query *object;
1255 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1257 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1260 ERR("Failed to allocate query memory.\n");
1261 return E_OUTOFMEMORY;
1264 hr = query_init(object, This, type);
1267 WARN("Failed to initialize query, hr %#x.\n", hr);
1268 HeapFree(GetProcessHeap(), 0, object);
1272 TRACE("Created query %p.\n", object);
1278 /* Do not call while under the GL lock. */
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1280 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1281 void *parent, const struct wined3d_parent_ops *parent_ops,
1282 struct wined3d_swapchain **swapchain)
1284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1285 struct wined3d_swapchain *object;
1288 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1289 iface, present_parameters, swapchain, parent, surface_type);
1291 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1294 ERR("Failed to allocate swapchain memory.\n");
1295 return E_OUTOFMEMORY;
1298 hr = swapchain_init(object, surface_type, This, present_parameters, parent, parent_ops);
1301 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1302 HeapFree(GetProcessHeap(), 0, object);
1306 TRACE("Created swapchain %p.\n", object);
1307 *swapchain = object;
1312 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface)
1314 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1316 TRACE("iface %p.\n", iface);
1318 return device->swapchain_count;
1321 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface,
1322 UINT swapchain_idx, struct wined3d_swapchain **swapchain)
1324 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1326 TRACE("iface %p, swapchain_idx %u, swapchain %p.\n",
1327 iface, swapchain_idx, swapchain);
1329 if (swapchain_idx >= device->swapchain_count)
1331 WARN("swapchain_idx %u >= swapchain_count %u.\n",
1332 swapchain_idx, device->swapchain_count);
1335 return WINED3DERR_INVALIDCALL;
1338 *swapchain = device->swapchains[swapchain_idx];
1339 wined3d_swapchain_incref(*swapchain);
1340 TRACE("Returning %p.\n", *swapchain);
1345 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1346 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1347 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1350 struct wined3d_vertex_declaration *object;
1353 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1354 iface, elements, element_count, parent, parent_ops, declaration);
1356 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1359 ERR("Failed to allocate vertex declaration memory.\n");
1360 return E_OUTOFMEMORY;
1363 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1366 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1367 HeapFree(GetProcessHeap(), 0, object);
1371 TRACE("Created vertex declaration %p.\n", object);
1372 *declaration = object;
1377 struct wined3d_fvf_convert_state
1379 const struct wined3d_gl_info *gl_info;
1380 WINED3DVERTEXELEMENT *elements;
1385 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1386 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1388 WINED3DVERTEXELEMENT *elements = state->elements;
1389 const struct wined3d_format *format;
1390 UINT offset = state->offset;
1391 UINT idx = state->idx;
1393 elements[idx].format = format_id;
1394 elements[idx].input_slot = 0;
1395 elements[idx].offset = offset;
1396 elements[idx].output_slot = 0;
1397 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1398 elements[idx].usage = usage;
1399 elements[idx].usage_idx = usage_idx;
1401 format = wined3d_get_format(state->gl_info, format_id);
1402 state->offset += format->component_count * format->component_size;
1406 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1407 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1409 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1410 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1411 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1412 BOOL has_blend_idx = has_blend &&
1413 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1414 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1415 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1416 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1417 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1418 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1419 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1421 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1422 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1423 struct wined3d_fvf_convert_state state;
1426 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1427 if (has_blend_idx) num_blends--;
1429 /* Compute declaration size */
1430 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1431 has_psize + has_diffuse + has_specular + num_textures;
1433 state.gl_info = gl_info;
1434 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1435 if (!state.elements) return ~0U;
1441 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1443 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1444 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1449 if (has_blend && (num_blends > 0))
1451 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1452 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1461 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1464 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1467 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1470 ERR("Unexpected amount of blend values: %u\n", num_blends);
1477 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1478 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1479 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1480 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1481 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1483 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1486 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1487 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1488 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1489 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1491 for (idx = 0; idx < num_textures; ++idx)
1493 switch ((texcoords >> (idx * 2)) & 0x03)
1495 case WINED3DFVF_TEXTUREFORMAT1:
1496 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1498 case WINED3DFVF_TEXTUREFORMAT2:
1499 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1501 case WINED3DFVF_TEXTUREFORMAT3:
1502 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1504 case WINED3DFVF_TEXTUREFORMAT4:
1505 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1510 *ppVertexElements = state.elements;
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1515 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1516 struct wined3d_vertex_declaration **declaration)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1519 WINED3DVERTEXELEMENT *elements;
1523 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1524 iface, fvf, parent, parent_ops, declaration);
1526 size = ConvertFvfToDeclaration(This, fvf, &elements);
1527 if (size == ~0U) return E_OUTOFMEMORY;
1529 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1530 HeapFree(GetProcessHeap(), 0, elements);
1534 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1535 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1536 void *parent, const struct wined3d_parent_ops *parent_ops,
1537 struct wined3d_shader **shader)
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 struct wined3d_shader *object;
1543 if (This->vs_selected_mode == SHADER_NONE)
1544 return WINED3DERR_INVALIDCALL;
1546 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1549 ERR("Failed to allocate shader memory.\n");
1550 return E_OUTOFMEMORY;
1553 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1556 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1557 HeapFree(GetProcessHeap(), 0, object);
1561 TRACE("Created vertex shader %p.\n", object);
1567 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1568 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1569 void *parent, const struct wined3d_parent_ops *parent_ops,
1570 struct wined3d_shader **shader)
1572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1573 struct wined3d_shader *object;
1576 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1579 ERR("Failed to allocate shader memory.\n");
1580 return E_OUTOFMEMORY;
1583 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1586 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1587 HeapFree(GetProcessHeap(), 0, object);
1591 TRACE("Created geometry shader %p.\n", object);
1597 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1598 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1599 void *parent, const struct wined3d_parent_ops *parent_ops,
1600 struct wined3d_shader **shader)
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1603 struct wined3d_shader *object;
1606 if (This->ps_selected_mode == SHADER_NONE)
1607 return WINED3DERR_INVALIDCALL;
1609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1612 ERR("Failed to allocate shader memory.\n");
1613 return E_OUTOFMEMORY;
1616 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1619 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1620 HeapFree(GetProcessHeap(), 0, object);
1624 TRACE("Created pixel shader %p.\n", object);
1630 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1631 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1634 struct wined3d_palette *object;
1637 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1638 iface, flags, entries, palette, parent);
1640 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1643 ERR("Failed to allocate palette memory.\n");
1644 return E_OUTOFMEMORY;
1647 hr = wined3d_palette_init(object, This, flags, entries, parent);
1650 WARN("Failed to initialize palette, hr %#x.\n", hr);
1651 HeapFree(GetProcessHeap(), 0, object);
1655 TRACE("Created palette %p.\n", object);
1661 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1665 HDC dcb = NULL, dcs = NULL;
1666 WINEDDCOLORKEY colorkey;
1668 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1671 GetObjectA(hbm, sizeof(BITMAP), &bm);
1672 dcb = CreateCompatibleDC(NULL);
1674 SelectObject(dcb, hbm);
1678 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1679 * couldn't be loaded
1681 memset(&bm, 0, sizeof(bm));
1686 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1687 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1688 &wined3d_null_parent_ops, &This->logo_surface);
1691 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1696 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1697 if(FAILED(hr)) goto out;
1698 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1699 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1701 colorkey.dwColorSpaceLowValue = 0;
1702 colorkey.dwColorSpaceHighValue = 0;
1703 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1707 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1708 /* Fill the surface with a white color to show that wined3d is there */
1709 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1713 if (dcb) DeleteDC(dcb);
1714 if (hbm) DeleteObject(hbm);
1717 /* Context activation is done by the caller. */
1718 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1720 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1722 /* Under DirectX you can have texture stage operations even if no texture is
1723 bound, whereas opengl will only do texture operations when a valid texture is
1724 bound. We emulate this by creating dummy textures and binding them to each
1725 texture stage, but disable all stages by default. Hence if a stage is enabled
1726 then the default texture will kick in until replaced by a SetTexture call */
1729 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1731 /* The dummy texture does not have client storage backing */
1732 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1733 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1736 for (i = 0; i < gl_info->limits.textures; ++i)
1738 GLubyte white = 255;
1740 /* Make appropriate texture active */
1741 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1742 checkGLcall("glActiveTextureARB");
1744 /* Generate an opengl texture name */
1745 glGenTextures(1, &This->dummyTextureName[i]);
1746 checkGLcall("glGenTextures");
1747 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1749 /* Generate a dummy 2d texture (not using 1d because they cause many
1750 * DRI drivers fall back to sw) */
1751 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1752 checkGLcall("glBindTexture");
1754 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1755 checkGLcall("glTexImage2D");
1758 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1760 /* Reenable because if supported it is enabled by default */
1761 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1762 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1768 /* Context activation is done by the caller. */
1769 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1772 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1773 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1776 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1779 static LONG fullscreen_style(LONG style)
1781 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1782 style |= WS_POPUP | WS_SYSMENU;
1783 style &= ~(WS_CAPTION | WS_THICKFRAME);
1788 static LONG fullscreen_exstyle(LONG exstyle)
1790 /* Filter out window decorations. */
1791 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1796 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1798 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1799 BOOL filter_messages;
1800 LONG style, exstyle;
1802 TRACE("Setting up window %p for fullscreen mode.\n", window);
1804 if (device->style || device->exStyle)
1806 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1807 window, device->style, device->exStyle);
1810 device->style = GetWindowLongW(window, GWL_STYLE);
1811 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1813 style = fullscreen_style(device->style);
1814 exstyle = fullscreen_exstyle(device->exStyle);
1816 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1817 device->style, device->exStyle, style, exstyle);
1819 filter_messages = device->filter_messages;
1820 device->filter_messages = TRUE;
1822 SetWindowLongW(window, GWL_STYLE, style);
1823 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1824 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1826 device->filter_messages = filter_messages;
1829 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1831 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1832 BOOL filter_messages;
1833 LONG style, exstyle;
1835 if (!device->style && !device->exStyle) return;
1837 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1838 window, device->style, device->exStyle);
1840 style = GetWindowLongW(window, GWL_STYLE);
1841 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1843 filter_messages = device->filter_messages;
1844 device->filter_messages = TRUE;
1846 /* Only restore the style if the application didn't modify it during the
1847 * fullscreen phase. Some applications change it before calling Reset()
1848 * when switching between windowed and fullscreen modes (HL2), some
1849 * depend on the original style (Eve Online). */
1850 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1852 SetWindowLongW(window, GWL_STYLE, device->style);
1853 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1855 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1857 device->filter_messages = filter_messages;
1859 /* Delete the old values. */
1861 device->exStyle = 0;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1866 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1868 TRACE("iface %p, window %p.\n", iface, window);
1870 if (!wined3d_register_window(window, device))
1872 ERR("Failed to register window %p.\n", window);
1876 device->focus_window = window;
1877 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1882 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1884 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1886 TRACE("iface %p.\n", iface);
1888 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1889 device->focus_window = NULL;
1892 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1893 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1896 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1897 struct wined3d_swapchain *swapchain = NULL;
1898 struct wined3d_context *context;
1903 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1905 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1906 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1908 TRACE("(%p) : Creating stateblock\n", This);
1909 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1912 WARN("Failed to create stateblock\n");
1915 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1916 This->updateStateBlock = This->stateBlock;
1917 wined3d_stateblock_incref(This->updateStateBlock);
1919 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1920 sizeof(*This->render_targets) * gl_info->limits.buffers);
1922 This->palette_count = 1;
1923 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1924 if (!This->palettes || !This->render_targets)
1926 ERR("Out of memory!\n");
1930 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1931 if(!This->palettes[0]) {
1932 ERR("Out of memory!\n");
1936 for (i = 0; i < 256; ++i) {
1937 This->palettes[0][i].peRed = 0xFF;
1938 This->palettes[0][i].peGreen = 0xFF;
1939 This->palettes[0][i].peBlue = 0xFF;
1940 This->palettes[0][i].peFlags = 0xFF;
1942 This->currentPalette = 0;
1944 /* Initialize the texture unit mapping to a 1:1 mapping */
1945 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1947 if (state < gl_info->limits.fragment_samplers)
1949 This->texUnitMap[state] = state;
1950 This->rev_tex_unit_map[state] = state;
1952 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1953 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1957 /* Setup the implicit swapchain. This also initializes a context. */
1958 TRACE("Creating implicit swapchain\n");
1959 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1960 pPresentationParameters, &swapchain);
1963 WARN("Failed to create implicit swapchain\n");
1967 This->swapchain_count = 1;
1968 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->swapchain_count * sizeof(*This->swapchains));
1969 if (!This->swapchains)
1971 ERR("Out of memory!\n");
1974 This->swapchains[0] = swapchain;
1976 if (swapchain->back_buffers && swapchain->back_buffers[0])
1978 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1979 This->render_targets[0] = swapchain->back_buffers[0];
1983 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1984 This->render_targets[0] = swapchain->front_buffer;
1986 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1988 /* Depth Stencil support */
1989 This->depth_stencil = This->auto_depth_stencil;
1990 if (This->depth_stencil)
1991 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1993 hr = This->shader_backend->shader_alloc_private(This);
1995 TRACE("Shader private data couldn't be allocated\n");
1998 hr = This->frag_pipe->alloc_private(This);
2000 TRACE("Fragment pipeline private data couldn't be allocated\n");
2003 hr = This->blitter->alloc_private(This);
2005 TRACE("Blitter private data couldn't be allocated\n");
2009 /* Set up some starting GL setup */
2011 /* Setup all the devices defaults */
2012 stateblock_init_default_state(This->stateBlock);
2014 context = context_acquire(This, swapchain->front_buffer);
2016 create_dummy_textures(This);
2020 /* Initialize the current view state */
2021 This->view_ident = 1;
2022 This->contexts[0]->last_was_rhw = 0;
2023 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2024 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2026 switch(wined3d_settings.offscreen_rendering_mode) {
2028 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2031 case ORM_BACKBUFFER:
2033 if (context_get_current()->aux_buffers > 0)
2035 TRACE("Using auxilliary buffer for offscreen rendering\n");
2036 This->offscreenBuffer = GL_AUX0;
2038 TRACE("Using back buffer for offscreen rendering\n");
2039 This->offscreenBuffer = GL_BACK;
2044 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2047 context_release(context);
2049 /* Clear the screen */
2050 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2051 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2054 This->d3d_initialized = TRUE;
2056 if(wined3d_settings.logo) {
2057 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2059 This->highest_dirty_ps_const = 0;
2060 This->highest_dirty_vs_const = 0;
2064 HeapFree(GetProcessHeap(), 0, This->render_targets);
2065 HeapFree(GetProcessHeap(), 0, This->swapchains);
2066 This->swapchain_count = 0;
2069 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2070 HeapFree(GetProcessHeap(), 0, This->palettes);
2072 This->palette_count = 0;
2074 wined3d_swapchain_decref(swapchain);
2075 if (This->stateBlock)
2077 wined3d_stateblock_decref(This->stateBlock);
2078 This->stateBlock = NULL;
2080 if (This->blit_priv) {
2081 This->blitter->free_private(This);
2083 if (This->fragment_priv) {
2084 This->frag_pipe->free_private(This);
2086 if (This->shader_priv) {
2087 This->shader_backend->shader_free_private(This);
2092 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2093 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2096 struct wined3d_swapchain *swapchain = NULL;
2099 /* Setup the implicit swapchain */
2100 TRACE("Creating implicit swapchain\n");
2101 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2102 pPresentationParameters, &swapchain);
2105 WARN("Failed to create implicit swapchain\n");
2109 This->swapchain_count = 1;
2110 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->swapchain_count * sizeof(*This->swapchains));
2111 if (!This->swapchains)
2113 ERR("Out of memory!\n");
2116 This->swapchains[0] = swapchain;
2120 wined3d_swapchain_decref(swapchain);
2124 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2126 TRACE("Unloading resource %p.\n", resource);
2128 resource->resource_ops->resource_unload(resource);
2133 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface)
2135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2136 const struct wined3d_gl_info *gl_info;
2137 struct IWineD3DSurfaceImpl *surface;
2138 struct wined3d_context *context;
2141 TRACE("(%p)\n", This);
2143 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2145 /* Force making the context current again, to verify it is still valid
2146 * (workaround for broken drivers) */
2147 context_set_current(NULL);
2148 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2149 * it was created. Thus make sure a context is active for the glDelete* calls
2151 context = context_acquire(This, NULL);
2152 gl_info = context->gl_info;
2154 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2156 /* Unload resources */
2157 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2159 TRACE("Deleting high order patches\n");
2160 for(i = 0; i < PATCHMAP_SIZE; i++) {
2161 struct list *e1, *e2;
2162 struct WineD3DRectPatch *patch;
2163 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2164 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2165 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2169 /* Delete the mouse cursor texture */
2170 if(This->cursorTexture) {
2172 glDeleteTextures(1, &This->cursorTexture);
2174 This->cursorTexture = 0;
2177 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2178 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2180 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2181 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2184 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2185 * private data, it might contain opengl pointers
2187 if(This->depth_blt_texture) {
2189 glDeleteTextures(1, &This->depth_blt_texture);
2191 This->depth_blt_texture = 0;
2193 if (This->depth_blt_rb) {
2195 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2197 This->depth_blt_rb = 0;
2198 This->depth_blt_rb_w = 0;
2199 This->depth_blt_rb_h = 0;
2202 /* Release the update stateblock */
2203 if (wined3d_stateblock_decref(This->updateStateBlock))
2205 if (This->updateStateBlock != This->stateBlock)
2206 FIXME("Something's still holding the update stateblock.\n");
2208 This->updateStateBlock = NULL;
2211 struct wined3d_stateblock *stateblock = This->stateBlock;
2212 This->stateBlock = NULL;
2214 /* Release the stateblock */
2215 if (wined3d_stateblock_decref(stateblock))
2216 FIXME("Something's still holding the stateblock.\n");
2219 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2220 This->blitter->free_private(This);
2221 This->frag_pipe->free_private(This);
2222 This->shader_backend->shader_free_private(This);
2224 /* Release the buffers (with sanity checks)*/
2225 if (This->onscreen_depth_stencil)
2227 surface = This->onscreen_depth_stencil;
2228 This->onscreen_depth_stencil = NULL;
2229 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2232 if (This->depth_stencil)
2234 surface = This->depth_stencil;
2236 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2238 This->depth_stencil = NULL;
2239 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2240 && surface != This->auto_depth_stencil)
2242 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2246 if (This->auto_depth_stencil)
2248 surface = This->auto_depth_stencil;
2249 This->auto_depth_stencil = NULL;
2250 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2252 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2256 for (i = 1; i < gl_info->limits.buffers; ++i)
2258 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2261 surface = This->render_targets[0];
2262 TRACE("Setting rendertarget 0 to NULL\n");
2263 This->render_targets[0] = NULL;
2264 TRACE("Releasing the render target at %p\n", surface);
2265 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2267 context_release(context);
2269 for (i = 0; i < This->swapchain_count; ++i)
2271 TRACE("Releasing the implicit swapchain %u.\n", i);
2272 if (wined3d_swapchain_decref(This->swapchains[i]))
2273 FIXME("Something's still holding the implicit swapchain.\n");
2276 HeapFree(GetProcessHeap(), 0, This->swapchains);
2277 This->swapchains = NULL;
2278 This->swapchain_count = 0;
2280 for (i = 0; i < This->palette_count; ++i)
2281 HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2282 HeapFree(GetProcessHeap(), 0, This->palettes);
2283 This->palettes = NULL;
2284 This->palette_count = 0;
2286 HeapFree(GetProcessHeap(), 0, This->render_targets);
2287 This->render_targets = NULL;
2289 This->d3d_initialized = FALSE;
2294 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface)
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2299 for (i = 0; i < This->swapchain_count; ++i)
2301 TRACE("Releasing the implicit swapchain %u.\n", i);
2302 if (wined3d_swapchain_decref(This->swapchains[i]))
2303 FIXME("Something's still holding the implicit swapchain.\n");
2306 HeapFree(GetProcessHeap(), 0, This->swapchains);
2307 This->swapchains = NULL;
2308 This->swapchain_count = 0;
2312 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2313 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2314 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2316 * There is no way to deactivate thread safety once it is enabled.
2318 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2321 /*For now just store the flag(needed in case of ddraw) */
2322 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2325 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2326 const WINED3DDISPLAYMODE* pMode) {
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2333 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2335 /* Resize the screen even without a window:
2336 * The app could have unset it with SetCooperativeLevel, but not called
2337 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2338 * but we don't have any hwnd
2341 memset(&devmode, 0, sizeof(devmode));
2342 devmode.dmSize = sizeof(devmode);
2343 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2344 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2345 devmode.dmPelsWidth = pMode->Width;
2346 devmode.dmPelsHeight = pMode->Height;
2348 devmode.dmDisplayFrequency = pMode->RefreshRate;
2349 if (pMode->RefreshRate)
2350 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2352 /* Only change the mode if necessary */
2353 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2354 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2357 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2358 if (ret != DISP_CHANGE_SUCCESSFUL)
2360 if (devmode.dmDisplayFrequency)
2362 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2363 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2364 devmode.dmDisplayFrequency = 0;
2365 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2367 if(ret != DISP_CHANGE_SUCCESSFUL) {
2368 return WINED3DERR_NOTAVAILABLE;
2372 /* Store the new values */
2373 This->ddraw_width = pMode->Width;
2374 This->ddraw_height = pMode->Height;
2375 This->ddraw_format = pMode->Format;
2377 /* And finally clip mouse to our screen */
2378 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2379 ClipCursor(&clip_rc);
2384 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2386 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2388 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2390 *wined3d = device->wined3d;
2391 wined3d_incref(*wined3d);
2393 TRACE("Returning %p.\n", *wined3d);
2398 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2402 (This->adapter->TextureRam/(1024*1024)),
2403 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2404 /* return simulated texture memory left */
2405 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2408 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2409 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2412 struct wined3d_stream_state *stream;
2413 struct wined3d_buffer *prev_buffer;
2415 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2416 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2418 if (StreamNumber >= MAX_STREAMS) {
2419 WARN("Stream out of range %d\n", StreamNumber);
2420 return WINED3DERR_INVALIDCALL;
2421 } else if(OffsetInBytes & 0x3) {
2422 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2423 return WINED3DERR_INVALIDCALL;
2426 stream = &This->updateStateBlock->state.streams[StreamNumber];
2427 prev_buffer = stream->buffer;
2429 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2431 if (prev_buffer == buffer
2432 && stream->stride == Stride
2433 && stream->offset == OffsetInBytes)
2435 TRACE("Application is setting the old values over, nothing to do\n");
2439 stream->buffer = buffer;
2442 stream->stride = Stride;
2443 stream->offset = OffsetInBytes;
2446 /* Handle recording of state blocks */
2447 if (This->isRecordingState) {
2448 TRACE("Recording... not performing anything\n");
2450 wined3d_buffer_incref(buffer);
2452 wined3d_buffer_decref(prev_buffer);
2458 InterlockedIncrement(&buffer->bind_count);
2459 wined3d_buffer_incref(buffer);
2463 InterlockedDecrement(&prev_buffer->bind_count);
2464 wined3d_buffer_decref(prev_buffer);
2467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2472 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2473 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2476 struct wined3d_stream_state *stream;
2478 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2479 iface, StreamNumber, buffer, pOffset, pStride);
2481 if (StreamNumber >= MAX_STREAMS)
2483 WARN("Stream out of range %d\n", StreamNumber);
2484 return WINED3DERR_INVALIDCALL;
2487 stream = &This->stateBlock->state.streams[StreamNumber];
2488 *buffer = stream->buffer;
2489 *pStride = stream->stride;
2490 if (pOffset) *pOffset = stream->offset;
2493 wined3d_buffer_incref(*buffer);
2498 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 struct wined3d_stream_state *stream;
2501 UINT old_flags, oldFreq;
2503 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2505 /* Verify input at least in d3d9 this is invalid. */
2506 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2508 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2509 return WINED3DERR_INVALIDCALL;
2511 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2513 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2514 return WINED3DERR_INVALIDCALL;
2518 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2519 return WINED3DERR_INVALIDCALL;
2522 stream = &This->updateStateBlock->state.streams[StreamNumber];
2523 old_flags = stream->flags;
2524 oldFreq = stream->frequency;
2526 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2527 stream->frequency = Divider & 0x7FFFFF;
2529 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2531 if (stream->frequency != oldFreq || stream->flags != old_flags)
2532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2537 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 struct wined3d_stream_state *stream;
2541 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2543 stream = &This->updateStateBlock->state.streams[StreamNumber];
2544 *Divider = stream->flags | stream->frequency;
2546 TRACE("Returning %#x.\n", *Divider);
2552 * Get / Set & Multiply Transform
2554 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 /* Most of this routine, comments included copied from ddraw tree initially: */
2558 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2560 /* Handle recording of state blocks */
2561 if (This->isRecordingState) {
2562 TRACE("Recording... not performing anything\n");
2563 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2564 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2569 * If the new matrix is the same as the current one,
2570 * we cut off any further processing. this seems to be a reasonable
2571 * optimization because as was noticed, some apps (warcraft3 for example)
2572 * tend towards setting the same matrix repeatedly for some reason.
2574 * From here on we assume that the new matrix is different, wherever it matters.
2576 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2578 TRACE("The app is setting the same matrix over again\n");
2583 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2587 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2588 where ViewMat = Camera space, WorldMat = world space.
2590 In OpenGL, camera and world space is combined into GL_MODELVIEW
2591 matrix. The Projection matrix stay projection matrix.
2594 /* Capture the times we can just ignore the change for now */
2595 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2596 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2597 /* Handled by the state manager */
2600 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2607 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2608 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2610 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2612 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2614 *matrix = device->stateBlock->state.transforms[state];
2619 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2620 const WINED3DMATRIX *mat = NULL;
2623 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2624 * below means it will be recorded in a state block change, but it
2625 * works regardless where it is recorded.
2626 * If this is found to be wrong, change to StateBlock.
2628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2631 if (State <= HIGHEST_TRANSFORMSTATE)
2633 mat = &This->updateStateBlock->state.transforms[State];
2637 FIXME("Unhandled transform state!!\n");
2640 multiply_matrix(&temp, mat, pMatrix);
2642 /* Apply change via set transform - will reapply to eg. lights this way */
2643 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2649 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2650 you can reference any indexes you want as long as that number max are enabled at any
2651 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2652 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2653 but when recording, just build a chain pretty much of commands to be replayed. */
2655 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2657 struct wined3d_light_info *object = NULL;
2658 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2664 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2668 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2669 return WINED3DERR_INVALIDCALL;
2672 switch(pLight->Type) {
2673 case WINED3DLIGHT_POINT:
2674 case WINED3DLIGHT_SPOT:
2675 case WINED3DLIGHT_PARALLELPOINT:
2676 case WINED3DLIGHT_GLSPOT:
2677 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2680 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2682 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2683 return WINED3DERR_INVALIDCALL;
2687 case WINED3DLIGHT_DIRECTIONAL:
2688 /* Ignores attenuation */
2692 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2693 return WINED3DERR_INVALIDCALL;
2696 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2698 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2699 if(object->OriginalIndex == Index) break;
2704 TRACE("Adding new light\n");
2705 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2707 ERR("Out of memory error when allocating a light\n");
2708 return E_OUTOFMEMORY;
2710 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2711 object->glIndex = -1;
2712 object->OriginalIndex = Index;
2715 /* Initialize the object */
2716 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2717 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2718 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2719 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2720 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2721 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2722 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2724 /* Save away the information */
2725 object->OriginalParms = *pLight;
2727 switch (pLight->Type) {
2728 case WINED3DLIGHT_POINT:
2730 object->lightPosn[0] = pLight->Position.x;
2731 object->lightPosn[1] = pLight->Position.y;
2732 object->lightPosn[2] = pLight->Position.z;
2733 object->lightPosn[3] = 1.0f;
2734 object->cutoff = 180.0f;
2738 case WINED3DLIGHT_DIRECTIONAL:
2740 object->lightPosn[0] = -pLight->Direction.x;
2741 object->lightPosn[1] = -pLight->Direction.y;
2742 object->lightPosn[2] = -pLight->Direction.z;
2743 object->lightPosn[3] = 0.0f;
2744 object->exponent = 0.0f;
2745 object->cutoff = 180.0f;
2748 case WINED3DLIGHT_SPOT:
2750 object->lightPosn[0] = pLight->Position.x;
2751 object->lightPosn[1] = pLight->Position.y;
2752 object->lightPosn[2] = pLight->Position.z;
2753 object->lightPosn[3] = 1.0f;
2756 object->lightDirn[0] = pLight->Direction.x;
2757 object->lightDirn[1] = pLight->Direction.y;
2758 object->lightDirn[2] = pLight->Direction.z;
2759 object->lightDirn[3] = 1.0f;
2762 * opengl-ish and d3d-ish spot lights use too different models for the
2763 * light "intensity" as a function of the angle towards the main light direction,
2764 * so we only can approximate very roughly.
2765 * however spot lights are rather rarely used in games (if ever used at all).
2766 * furthermore if still used, probably nobody pays attention to such details.
2768 if (!pLight->Falloff)
2770 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2771 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2772 * will always be 1.0 for both of them, and we don't have to care for the
2773 * rest of the rather complex calculation
2775 object->exponent = 0.0f;
2777 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2778 if (rho < 0.0001f) rho = 0.0001f;
2779 object->exponent = -0.3f/logf(cosf(rho/2));
2781 if (object->exponent > 128.0f)
2783 object->exponent = 128.0f;
2785 object->cutoff = (float) (pLight->Phi*90/M_PI);
2791 FIXME("Unrecognized light type %d\n", pLight->Type);
2794 /* Update the live definitions if the light is currently assigned a glIndex */
2795 if (object->glIndex != -1 && !This->isRecordingState) {
2796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2803 struct wined3d_light_info *lightInfo = NULL;
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2807 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2809 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2811 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2812 if(lightInfo->OriginalIndex == Index) break;
2818 TRACE("Light information requested but light not defined\n");
2819 return WINED3DERR_INVALIDCALL;
2822 *pLight = lightInfo->OriginalParms;
2827 * Get / Set Light Enable
2828 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2830 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2832 struct wined3d_light_info *lightInfo = NULL;
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2836 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2838 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2840 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2841 if(lightInfo->OriginalIndex == Index) break;
2844 TRACE("Found light: %p\n", lightInfo);
2846 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2849 TRACE("Light enabled requested but light not defined, so defining one!\n");
2850 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2852 /* Search for it again! Should be fairly quick as near head of list */
2853 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2855 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2856 if(lightInfo->OriginalIndex == Index) break;
2861 FIXME("Adding default lights has failed dismally\n");
2862 return WINED3DERR_INVALIDCALL;
2867 if(lightInfo->glIndex != -1) {
2868 if(!This->isRecordingState) {
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2872 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2873 lightInfo->glIndex = -1;
2875 TRACE("Light already disabled, nothing to do\n");
2877 lightInfo->enabled = FALSE;
2879 lightInfo->enabled = TRUE;
2880 if (lightInfo->glIndex != -1) {
2882 TRACE("Nothing to do as light was enabled\n");
2885 /* Find a free gl light */
2886 for (i = 0; i < This->maxConcurrentLights; ++i)
2888 if (!This->updateStateBlock->state.lights[i])
2890 This->updateStateBlock->state.lights[i] = lightInfo;
2891 lightInfo->glIndex = i;
2895 if(lightInfo->glIndex == -1) {
2896 /* Our tests show that Windows returns D3D_OK in this situation, even with
2897 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2898 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2899 * as well for those lights.
2901 * TODO: Test how this affects rendering
2903 WARN("Too many concurrently active lights\n");
2907 /* i == lightInfo->glIndex */
2908 if(!This->isRecordingState) {
2909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2919 struct wined3d_light_info *lightInfo = NULL;
2920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2923 TRACE("(%p) : for idx(%d)\n", This, Index);
2925 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2927 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2928 if(lightInfo->OriginalIndex == Index) break;
2934 TRACE("Light enabled state requested but light not defined\n");
2935 return WINED3DERR_INVALIDCALL;
2937 /* true is 128 according to SetLightEnable */
2938 *pEnable = lightInfo->enabled ? 128 : 0;
2943 * Get / Set Clip Planes
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2949 /* Validate Index */
2950 if (Index >= This->adapter->gl_info.limits.clipplanes)
2952 TRACE("Application has requested clipplane this device doesn't support\n");
2953 return WINED3DERR_INVALIDCALL;
2956 This->updateStateBlock->changed.clipplane |= 1 << Index;
2958 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2959 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2960 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2961 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2963 TRACE("Application is setting old values over, nothing to do\n");
2967 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2968 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2969 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2970 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2972 /* Handle recording of state blocks */
2973 if (This->isRecordingState) {
2974 TRACE("Recording... not performing anything\n");
2978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2983 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 TRACE("(%p) : for idx %d\n", This, Index);
2987 /* Validate Index */
2988 if (Index >= This->adapter->gl_info.limits.clipplanes)
2990 TRACE("Application has requested clipplane this device doesn't support\n");
2991 return WINED3DERR_INVALIDCALL;
2994 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2995 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2996 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2997 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
3002 * Get / Set Clip Plane Status
3003 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3005 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 FIXME("(%p) : stub\n", This);
3010 return WINED3DERR_INVALIDCALL;
3012 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
3013 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3017 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 FIXME("(%p) : stub\n", This);
3022 return WINED3DERR_INVALIDCALL;
3024 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3025 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3030 * Get / Set Material
3032 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3035 This->updateStateBlock->changed.material = TRUE;
3036 This->updateStateBlock->state.material = *pMaterial;
3038 /* Handle recording of state blocks */
3039 if (This->isRecordingState) {
3040 TRACE("Recording... not performing anything\n");
3044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 *pMaterial = This->updateStateBlock->state.material;
3051 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3052 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3053 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3054 pMaterial->Ambient.b, pMaterial->Ambient.a);
3055 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3056 pMaterial->Specular.b, pMaterial->Specular.a);
3057 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3058 pMaterial->Emissive.b, pMaterial->Emissive.a);
3059 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3067 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3068 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 struct wined3d_buffer *prev_buffer;
3073 TRACE("iface %p, buffer %p, format %s.\n",
3074 iface, buffer, debug_d3dformat(fmt));
3076 prev_buffer = This->updateStateBlock->state.index_buffer;
3078 This->updateStateBlock->changed.indices = TRUE;
3079 This->updateStateBlock->state.index_buffer = buffer;
3080 This->updateStateBlock->state.index_format = fmt;
3082 /* Handle recording of state blocks */
3083 if (This->isRecordingState) {
3084 TRACE("Recording... not performing anything\n");
3086 wined3d_buffer_incref(buffer);
3088 wined3d_buffer_decref(prev_buffer);
3092 if (prev_buffer != buffer)
3094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3097 InterlockedIncrement(&buffer->bind_count);
3098 wined3d_buffer_incref(buffer);
3102 InterlockedDecrement(&prev_buffer->bind_count);
3103 wined3d_buffer_decref(prev_buffer);
3110 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3114 TRACE("iface %p, buffer %p.\n", iface, buffer);
3116 *buffer = This->stateBlock->state.index_buffer;
3119 wined3d_buffer_incref(*buffer);
3121 TRACE("Returning %p.\n", *buffer);
3126 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3127 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p)->(%d)\n", This, BaseIndex);
3131 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3133 TRACE("Application is setting the old value over, nothing to do\n");
3137 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3139 if (This->isRecordingState) {
3140 TRACE("Recording... not performing anything\n");
3143 /* The base vertex index affects the stream sources */
3144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 TRACE("(%p) : base_index %p\n", This, base_index);
3152 *base_index = This->stateBlock->state.base_vertex_index;
3154 TRACE("Returning %u\n", *base_index);
3160 * Get / Set Viewports
3162 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 TRACE("(%p)\n", This);
3166 This->updateStateBlock->changed.viewport = TRUE;
3167 This->updateStateBlock->state.viewport = *pViewport;
3169 /* Handle recording of state blocks */
3170 if (This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3175 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3176 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3183 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 TRACE("(%p)\n", This);
3186 *pViewport = This->stateBlock->state.viewport;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3191 WINED3DRENDERSTATETYPE State, DWORD Value)
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 DWORD oldValue = This->stateBlock->state.render_states[State];
3196 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3198 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3199 This->updateStateBlock->state.render_states[State] = Value;
3201 /* Handle recording of state blocks */
3202 if (This->isRecordingState) {
3203 TRACE("Recording... not performing anything\n");
3207 /* Compared here and not before the assignment to allow proper stateblock recording */
3208 if(Value == oldValue) {
3209 TRACE("Application is setting the old value over, nothing to do\n");
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3218 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3224 *pValue = This->stateBlock->state.render_states[State];
3229 * Get / Set Sampler States
3230 * TODO: Verify against dx9 definitions
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3238 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3240 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3241 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3244 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3246 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3247 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3250 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3251 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3252 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3254 /* Handle recording of state blocks */
3255 if (This->isRecordingState) {
3256 TRACE("Recording... not performing anything\n");
3260 if(oldValue == Value) {
3261 TRACE("Application is setting the old value over, nothing to do\n");
3265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3270 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3274 This, Sampler, debug_d3dsamplerstate(Type), Type);
3276 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3277 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3280 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3282 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3283 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3285 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3286 TRACE("(%p) : Returning %#x\n", This, *Value);
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 This->updateStateBlock->changed.scissorRect = TRUE;
3295 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3297 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3300 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3302 if(This->isRecordingState) {
3303 TRACE("Recording... not performing anything\n");
3307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 *pRect = This->updateStateBlock->state.scissor_rect;
3316 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3320 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3321 struct wined3d_vertex_declaration *pDecl)
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3324 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3326 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3329 wined3d_vertex_declaration_incref(pDecl);
3331 wined3d_vertex_declaration_decref(oldDecl);
3333 This->updateStateBlock->state.vertex_declaration = pDecl;
3334 This->updateStateBlock->changed.vertexDecl = TRUE;
3336 if (This->isRecordingState) {
3337 TRACE("Recording... not performing anything\n");
3339 } else if(pDecl == oldDecl) {
3340 /* Checked after the assignment to allow proper stateblock recording */
3341 TRACE("Application is setting the old declaration over, nothing to do\n");
3345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3349 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3350 struct wined3d_vertex_declaration **ppDecl)
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3356 *ppDecl = This->stateBlock->state.vertex_declaration;
3358 wined3d_vertex_declaration_incref(*ppDecl);
3363 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3365 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3366 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
3368 device->updateStateBlock->state.vertex_shader = shader;
3369 device->updateStateBlock->changed.vertexShader = TRUE;
3371 if (device->isRecordingState)
3374 wined3d_shader_incref(shader);
3376 wined3d_shader_decref(prev);
3377 TRACE("Recording... not performing anything.\n");
3380 else if(prev == shader)
3382 /* Checked here to allow proper stateblock recording */
3383 TRACE("App is setting the old shader over, nothing to do.\n");
3387 TRACE("(%p) : setting shader(%p)\n", device, shader);
3389 wined3d_shader_incref(shader);
3391 wined3d_shader_decref(prev);
3393 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
3398 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3400 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3401 struct wined3d_shader *shader;
3403 TRACE("iface %p.\n", iface);
3405 shader = device->stateBlock->state.vertex_shader;
3407 wined3d_shader_incref(shader);
3409 TRACE("Returning %p.\n", shader);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3414 IWineD3DDevice *iface,
3416 CONST BOOL *srcData,
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3422 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3423 iface, srcData, start, count);
3425 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3427 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3428 for (i = 0; i < cnt; i++)
3429 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3431 for (i = start; i < cnt + start; ++i) {
3432 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3435 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3440 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3441 IWineD3DDevice *iface,
3446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3447 int cnt = min(count, MAX_CONST_B - start);
3449 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3450 iface, dstData, start, count);
3452 if (!dstData || cnt < 0)
3453 return WINED3DERR_INVALIDCALL;
3455 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3459 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3460 IWineD3DDevice *iface,
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3468 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3469 iface, srcData, start, count);
3471 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3473 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3474 for (i = 0; i < cnt; i++)
3475 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3476 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3478 for (i = start; i < cnt + start; ++i) {
3479 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3482 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3487 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3488 IWineD3DDevice *iface,
3493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 int cnt = min(count, MAX_CONST_I - start);
3496 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3497 iface, dstData, start, count);
3499 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3500 return WINED3DERR_INVALIDCALL;
3502 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3506 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3507 IWineD3DDevice *iface,
3509 CONST float *srcData,
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3515 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3516 iface, srcData, start, count);
3518 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3519 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3520 return WINED3DERR_INVALIDCALL;
3522 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3524 for (i = 0; i < count; i++)
3525 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3526 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3529 if (!This->isRecordingState)
3531 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3535 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3536 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3541 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3542 IWineD3DDevice *iface,
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 int cnt = min(count, This->d3d_vshader_constantF - start);
3550 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3551 iface, dstData, start, count);
3553 if (!dstData || cnt < 0)
3554 return WINED3DERR_INVALIDCALL;
3556 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3560 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3562 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3568 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3570 DWORD i = This->rev_tex_unit_map[unit];
3571 DWORD j = This->texUnitMap[stage];
3573 This->texUnitMap[stage] = unit;
3574 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3576 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3579 This->rev_tex_unit_map[unit] = stage;
3580 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3582 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3586 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3589 This->fixed_function_usage_map = 0;
3590 for (i = 0; i < MAX_TEXTURES; ++i)
3592 const struct wined3d_state *state = &This->stateBlock->state;
3593 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3594 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3595 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3596 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3597 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3598 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3599 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3600 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3602 if (color_op == WINED3DTOP_DISABLE) {
3603 /* Not used, and disable higher stages */
3607 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3608 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3609 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3610 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3611 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3612 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3613 This->fixed_function_usage_map |= (1 << i);
3616 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3617 This->fixed_function_usage_map |= (1 << (i + 1));
3622 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3624 unsigned int i, tex;
3627 device_update_fixed_function_usage_map(This);
3628 ffu_map = This->fixed_function_usage_map;
3630 if (This->max_ffp_textures == gl_info->limits.texture_stages
3631 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3633 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3635 if (!(ffu_map & 1)) continue;
3637 if (This->texUnitMap[i] != i) {
3638 device_map_stage(This, i, i);
3639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3640 markTextureStagesDirty(This, i);
3646 /* Now work out the mapping */
3648 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3650 if (!(ffu_map & 1)) continue;
3652 if (This->texUnitMap[i] != tex) {
3653 device_map_stage(This, i, tex);
3654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3655 markTextureStagesDirty(This, i);
3662 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3664 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3665 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3668 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3669 if (sampler_type[i] && This->texUnitMap[i] != i)
3671 device_map_stage(This, i, i);
3672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3673 if (i < gl_info->limits.texture_stages)
3675 markTextureStagesDirty(This, i);
3681 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3682 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3684 DWORD current_mapping = This->rev_tex_unit_map[unit];
3686 /* Not currently used */
3687 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3689 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3690 /* Used by a fragment sampler */
3692 if (!pshader_sampler_tokens) {
3693 /* No pixel shader, check fixed function */
3694 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3697 /* Pixel shader, check the shader's sampler map */
3698 return !pshader_sampler_tokens[current_mapping];
3701 /* Used by a vertex sampler */
3702 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3705 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3707 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3708 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3709 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3710 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3715 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3716 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3717 pshader_sampler_type = This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3720 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3721 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3722 if (vshader_sampler_type[i])
3724 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3726 /* Already mapped somewhere */
3730 while (start >= 0) {
3731 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3733 device_map_stage(This, vsampler_idx, start);
3734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3746 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3748 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3749 const struct wined3d_state *state = &This->stateBlock->state;
3750 BOOL vs = use_vs(state);
3751 BOOL ps = use_ps(state);
3754 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3755 * that would be really messy and require shader recompilation
3756 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3757 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3759 if (ps) device_map_psamplers(This, gl_info);
3760 else device_map_fixed_function_samplers(This, gl_info);
3762 if (vs) device_map_vsamplers(This, ps, gl_info);
3765 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3767 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3768 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
3770 device->updateStateBlock->state.pixel_shader = shader;
3771 device->updateStateBlock->changed.pixelShader = TRUE;
3773 /* Handle recording of state blocks */
3774 if (device->isRecordingState)
3775 TRACE("Recording... not performing anything\n");
3777 if (device->isRecordingState)
3779 TRACE("Recording... not performing anything.\n");
3781 wined3d_shader_incref(shader);
3783 wined3d_shader_decref(prev);
3789 TRACE("App is setting the old pixel shader over, nothing to do.\n");
3794 wined3d_shader_incref(shader);
3796 wined3d_shader_decref(prev);
3798 TRACE("Setting shader %p.\n", shader);
3799 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3804 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3806 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3807 struct wined3d_shader *shader;
3809 TRACE("iface %p.\n", iface);
3811 shader = device->stateBlock->state.pixel_shader;
3813 wined3d_shader_incref(shader);
3815 TRACE("Returning %p.\n", shader);
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3820 IWineD3DDevice *iface,
3822 CONST BOOL *srcData,
3825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3826 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3828 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3829 iface, srcData, start, count);
3831 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3833 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3834 for (i = 0; i < cnt; i++)
3835 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3837 for (i = start; i < cnt + start; ++i) {
3838 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3841 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3846 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3847 IWineD3DDevice *iface,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 int cnt = min(count, MAX_CONST_B - start);
3855 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3856 iface, dstData, start, count);
3858 if (!dstData || cnt < 0)
3859 return WINED3DERR_INVALIDCALL;
3861 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3865 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3866 IWineD3DDevice *iface,
3871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3872 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3874 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3875 iface, srcData, start, count);
3877 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3879 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3880 for (i = 0; i < cnt; i++)
3881 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3882 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3884 for (i = start; i < cnt + start; ++i) {
3885 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3888 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3893 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3894 IWineD3DDevice *iface,
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3900 int cnt = min(count, MAX_CONST_I - start);
3902 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3903 iface, dstData, start, count);
3905 if (!dstData || cnt < 0)
3906 return WINED3DERR_INVALIDCALL;
3908 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3912 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3913 IWineD3DDevice *iface,
3915 CONST float *srcData,
3918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3921 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3922 iface, srcData, start, count);
3924 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3925 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3926 return WINED3DERR_INVALIDCALL;
3928 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3930 for (i = 0; i < count; i++)
3931 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3932 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3935 if (!This->isRecordingState)
3937 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3941 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3942 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3947 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3948 IWineD3DDevice *iface,
3953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3954 int cnt = min(count, This->d3d_pshader_constantF - start);
3956 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3957 iface, dstData, start, count);
3959 if (!dstData || cnt < 0)
3960 return WINED3DERR_INVALIDCALL;
3962 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3966 /* Context activation is done by the caller. */
3967 /* Do not call while under the GL lock. */
3968 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3969 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3970 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3973 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3974 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3977 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3981 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3983 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3986 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3988 ERR("Source has no position mask\n");
3989 return WINED3DERR_INVALIDCALL;
3992 if (!dest->resource.allocatedMemory)
3993 buffer_get_sysmem(dest, gl_info);
3995 /* Get a pointer into the destination vbo(create one if none exists) and
3996 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3998 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
4000 dest->flags |= WINED3D_BUFFER_CREATEBO;
4001 wined3d_buffer_preload(dest);
4004 if (dest->buffer_object)
4006 unsigned char extrabytes = 0;
4007 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4008 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4009 * this may write 4 extra bytes beyond the area that should be written
4011 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4012 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4013 if(!dest_conv_addr) {
4014 ERR("Out of memory\n");
4015 /* Continue without storing converted vertices */
4017 dest_conv = dest_conv_addr;
4020 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
4022 static BOOL warned = FALSE;
4024 * The clipping code is not quite correct. Some things need
4025 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4026 * so disable clipping for now.
4027 * (The graphics in Half-Life are broken, and my processvertices
4028 * test crashes with IDirect3DDevice3)
4034 FIXME("Clipping is broken and disabled for now\n");
4036 } else doClip = FALSE;
4037 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4039 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4042 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4043 WINED3DTS_PROJECTION,
4045 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4046 WINED3DTS_WORLDMATRIX(0),
4049 TRACE("View mat:\n");
4050 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);
4051 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);
4052 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);
4053 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);
4055 TRACE("Proj mat:\n");
4056 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);
4057 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);
4058 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);
4059 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);
4061 TRACE("World mat:\n");
4062 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);
4063 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);
4064 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);
4065 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);
4067 /* Get the viewport */
4068 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4069 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4070 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4072 multiply_matrix(&mat,&view_mat,&world_mat);
4073 multiply_matrix(&mat,&proj_mat,&mat);
4075 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4077 for (i = 0; i < dwCount; i+= 1) {
4078 unsigned int tex_index;
4080 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4081 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4082 /* The position first */
4083 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4084 const float *p = (const float *)(element->data + i * element->stride);
4086 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4088 /* Multiplication with world, view and projection matrix */
4089 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);
4090 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);
4091 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);
4092 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);
4094 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4096 /* WARNING: The following things are taken from d3d7 and were not yet checked
4097 * against d3d8 or d3d9!
4100 /* Clipping conditions: From msdn
4102 * A vertex is clipped if it does not match the following requirements
4106 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4108 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4109 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4114 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4115 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4118 /* "Normal" viewport transformation (not clipped)
4119 * 1) The values are divided by rhw
4120 * 2) The y axis is negative, so multiply it with -1
4121 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4122 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4123 * 4) Multiply x with Width/2 and add Width/2
4124 * 5) The same for the height
4125 * 6) Add the viewpoint X and Y to the 2D coordinates and
4126 * The minimum Z value to z
4127 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4129 * Well, basically it's simply a linear transformation into viewport
4141 z *= vp.MaxZ - vp.MinZ;
4143 x += vp.Width / 2 + vp.X;
4144 y += vp.Height / 2 + vp.Y;
4149 /* That vertex got clipped
4150 * Contrary to OpenGL it is not dropped completely, it just
4151 * undergoes a different calculation.
4153 TRACE("Vertex got clipped\n");
4160 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4161 * outside of the main vertex buffer memory. That needs some more
4166 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4169 ( (float *) dest_ptr)[0] = x;
4170 ( (float *) dest_ptr)[1] = y;
4171 ( (float *) dest_ptr)[2] = z;
4172 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4174 dest_ptr += 3 * sizeof(float);
4176 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4177 dest_ptr += sizeof(float);
4182 ( (float *) dest_conv)[0] = x * w;
4183 ( (float *) dest_conv)[1] = y * w;
4184 ( (float *) dest_conv)[2] = z * w;
4185 ( (float *) dest_conv)[3] = w;
4187 dest_conv += 3 * sizeof(float);
4189 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4190 dest_conv += sizeof(float);
4194 if (DestFVF & WINED3DFVF_PSIZE) {
4195 dest_ptr += sizeof(DWORD);
4196 if(dest_conv) dest_conv += sizeof(DWORD);
4198 if (DestFVF & WINED3DFVF_NORMAL) {
4199 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4200 const float *normal = (const float *)(element->data + i * element->stride);
4201 /* AFAIK this should go into the lighting information */
4202 FIXME("Didn't expect the destination to have a normal\n");
4203 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4205 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4209 if (DestFVF & WINED3DFVF_DIFFUSE) {
4210 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4211 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4212 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4214 static BOOL warned = FALSE;
4217 ERR("No diffuse color in source, but destination has one\n");
4221 *( (DWORD *) dest_ptr) = 0xffffffff;
4222 dest_ptr += sizeof(DWORD);
4225 *( (DWORD *) dest_conv) = 0xffffffff;
4226 dest_conv += sizeof(DWORD);
4230 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4232 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4233 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4234 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4235 dest_conv += sizeof(DWORD);
4240 if (DestFVF & WINED3DFVF_SPECULAR)
4242 /* What's the color value in the feedback buffer? */
4243 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4244 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4245 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4247 static BOOL warned = FALSE;
4250 ERR("No specular color in source, but destination has one\n");
4254 *( (DWORD *) dest_ptr) = 0xFF000000;
4255 dest_ptr += sizeof(DWORD);
4258 *( (DWORD *) dest_conv) = 0xFF000000;
4259 dest_conv += sizeof(DWORD);
4263 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4265 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4266 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4267 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4268 dest_conv += sizeof(DWORD);
4273 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4274 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4275 const float *tex_coord = (const float *)(element->data + i * element->stride);
4276 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4278 ERR("No source texture, but destination requests one\n");
4279 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4280 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4283 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4285 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4295 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4296 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4297 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4298 dwCount * get_flexible_vertex_size(DestFVF),
4300 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4304 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4309 #undef copy_and_next
4311 /* Do not call while under the GL lock. */
4312 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4313 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4314 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 struct wined3d_stream_info stream_info;
4318 const struct wined3d_gl_info *gl_info;
4319 struct wined3d_context *context;
4320 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4323 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4326 ERR("Output vertex declaration not implemented yet\n");
4329 /* Need any context to write to the vbo. */
4330 context = context_acquire(This, NULL);
4331 gl_info = context->gl_info;
4333 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4334 * control the streamIsUP flag, thus restore it afterwards.
4336 This->stateBlock->state.user_stream = FALSE;
4337 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4338 This->stateBlock->state.user_stream = streamWasUP;
4340 if(vbo || SrcStartIndex) {
4342 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4343 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4345 * Also get the start index in, but only loop over all elements if there's something to add at all.
4347 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4349 struct wined3d_stream_info_element *e;
4351 if (!(stream_info.use_map & (1 << i))) continue;
4353 e = &stream_info.elements[i];
4354 if (e->buffer_object)
4356 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4357 e->buffer_object = 0;
4358 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4360 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4361 vb->buffer_object = 0;
4364 if (e->data) e->data += e->stride * SrcStartIndex;
4368 hr = process_vertices_strided(This, DestIndex, VertexCount,
4369 &stream_info, dst_buffer, flags, DestFVF);
4371 context_release(context);
4377 * Get / Set Texture Stage States
4378 * TODO: Verify against dx9 definitions
4380 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4386 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4388 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4390 WARN("Invalid Type %d passed.\n", Type);
4394 if (Stage >= gl_info->limits.texture_stages)
4396 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4397 Stage, gl_info->limits.texture_stages - 1);
4401 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4402 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4403 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4405 if (This->isRecordingState) {
4406 TRACE("Recording... not performing anything\n");
4410 /* Checked after the assignments to allow proper stateblock recording */
4411 if(oldValue == Value) {
4412 TRACE("App is setting the old value over, nothing to do\n");
4416 if (Stage > This->stateBlock->state.lowest_disabled_stage
4417 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4418 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4420 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4421 * Changes in other states are important on disabled stages too
4426 if(Type == WINED3DTSS_COLOROP) {
4429 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4430 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4431 * they have to be disabled
4433 * The current stage is dirtified below.
4435 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4437 TRACE("Additionally dirtifying stage %u\n", i);
4438 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4440 This->stateBlock->state.lowest_disabled_stage = Stage;
4441 TRACE("New lowest disabled: %u\n", Stage);
4442 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4443 /* Previously disabled stage enabled. Stages above it may need enabling
4444 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4445 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4447 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4450 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4452 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4454 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4457 This->stateBlock->state.lowest_disabled_stage = i;
4458 TRACE("New lowest disabled: %u\n", i);
4462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4467 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4471 TRACE("iface %p, stage %u, state %s, value %p.\n",
4472 iface, Stage, debug_d3dtexturestate(Type), pValue);
4474 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4476 WARN("Invalid Type %d passed.\n", Type);
4480 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4481 TRACE("Returning %#x.\n", *pValue);
4486 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4487 DWORD stage, struct wined3d_texture *texture)
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4491 struct wined3d_texture *prev;
4493 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4495 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4496 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4498 /* Windows accepts overflowing this array... we do not. */
4499 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4501 WARN("Ignoring invalid stage %u.\n", stage);
4505 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4506 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4508 WARN("Rejecting attempt to set scratch texture.\n");
4509 return WINED3DERR_INVALIDCALL;
4512 This->updateStateBlock->changed.textures |= 1 << stage;
4514 prev = This->updateStateBlock->state.textures[stage];
4515 TRACE("Previous texture %p.\n", prev);
4517 if (texture == prev)
4519 TRACE("App is setting the same texture again, nothing to do.\n");
4523 TRACE("Setting new texture to %p.\n", texture);
4524 This->updateStateBlock->state.textures[stage] = texture;
4526 if (This->isRecordingState)
4528 TRACE("Recording... not performing anything\n");
4530 if (texture) wined3d_texture_incref(texture);
4531 if (prev) wined3d_texture_decref(prev);
4538 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4540 wined3d_texture_incref(texture);
4542 if (!prev || texture->target != prev->target)
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4545 if (!prev && stage < gl_info->limits.texture_stages)
4547 /* The source arguments for color and alpha ops have different
4548 * meanings when a NULL texture is bound, so the COLOROP and
4549 * ALPHAOP have to be dirtified. */
4550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4554 if (bind_count == 1)
4555 texture->sampler = stage;
4560 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4562 wined3d_texture_decref(prev);
4564 if (!texture && stage < gl_info->limits.texture_stages)
4566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4570 if (bind_count && prev->sampler == stage)
4574 /* Search for other stages the texture is bound to. Shouldn't
4575 * happen if applications bind textures to a single stage only. */
4576 TRACE("Searching for other stages the texture is bound to.\n");
4577 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4579 if (This->updateStateBlock->state.textures[i] == prev)
4581 TRACE("Texture is also bound to stage %u.\n", i);
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4594 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4595 DWORD stage, struct wined3d_texture **texture)
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4599 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4601 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4602 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4604 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4606 WARN("Current stage overflows textures array (stage %u).\n", stage);
4607 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4610 *texture = This->stateBlock->state.textures[stage];
4612 wined3d_texture_incref(*texture);
4614 TRACE("Returning %p.\n", *texture);
4622 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4623 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4625 struct wined3d_swapchain *swapchain;
4628 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4629 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4631 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4634 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4638 hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4639 wined3d_swapchain_decref(swapchain);
4642 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4649 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4651 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4653 TRACE("iface %p, caps %p.\n", iface, caps);
4655 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4658 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface,
4659 UINT swapchain_idx, WINED3DDISPLAYMODE *mode)
4661 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4662 struct wined3d_swapchain *swapchain;
4665 TRACE("iface %p, swapchain_idx %u, mode %p.\n", iface, swapchain_idx, mode);
4669 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4672 hr = wined3d_swapchain_get_display_mode(swapchain, mode);
4673 wined3d_swapchain_decref(swapchain);
4678 /* Don't read the real display mode, but return the stored mode
4679 * instead. X11 can't change the color depth, and some apps are
4680 * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out
4681 * that GetDisplayMode still returns 24 bpp.
4683 * Also don't relay to the swapchain because with ddraw it's possible
4684 * that there isn't a swapchain at all. */
4685 mode->Width = device->ddraw_width;
4686 mode->Height = device->ddraw_height;
4687 mode->Format = device->ddraw_format;
4688 mode->RefreshRate = 0;
4696 * Stateblock related functions
4699 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4702 struct wined3d_stateblock *stateblock;
4705 TRACE("(%p)\n", This);
4707 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4709 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4710 if (FAILED(hr)) return hr;
4712 wined3d_stateblock_decref(This->updateStateBlock);
4713 This->updateStateBlock = stateblock;
4714 This->isRecordingState = TRUE;
4716 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4721 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4722 struct wined3d_stateblock **stateblock)
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 struct wined3d_stateblock *object = This->updateStateBlock;
4727 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4729 if (!This->isRecordingState) {
4730 WARN("(%p) not recording! returning error\n", This);
4732 return WINED3DERR_INVALIDCALL;
4735 stateblock_init_contained_states(object);
4737 *stateblock = object;
4738 This->isRecordingState = FALSE;
4739 This->updateStateBlock = This->stateBlock;
4740 wined3d_stateblock_incref(This->updateStateBlock);
4742 TRACE("Returning stateblock %p.\n", *stateblock);
4748 * Scene related functions
4750 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4751 /* At the moment we have no need for any functionality at the beginning
4753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 TRACE("(%p)\n", This);
4757 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4758 return WINED3DERR_INVALIDCALL;
4760 This->inScene = TRUE;
4764 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 struct wined3d_context *context;
4769 TRACE("(%p)\n", This);
4771 if(!This->inScene) {
4772 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4773 return WINED3DERR_INVALIDCALL;
4776 context = context_acquire(This, NULL);
4777 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4779 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4781 context_release(context);
4783 This->inScene = FALSE;
4787 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface, const RECT *src_rect,
4788 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
4790 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4793 TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
4794 iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
4795 dst_window_override, dirty_region);
4797 for (i = 0; i < device->swapchain_count; ++i)
4799 wined3d_swapchain_present(device->swapchains[i], src_rect,
4800 dst_rect, dst_window_override, dirty_region, 0);
4806 /* Do not call while under the GL lock. */
4807 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4808 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4810 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4811 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4814 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4815 iface, rect_count, rects, flags, color, depth, stencil);
4817 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4819 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4822 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4823 /* TODO: What about depth stencil buffers without stencil bits? */
4824 return WINED3DERR_INVALIDCALL;
4826 else if (flags & WINED3DCLEAR_TARGET)
4828 if(ds->resource.width < device->render_targets[0]->resource.width ||
4829 ds->resource.height < device->render_targets[0]->resource.height)
4831 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4837 device_get_draw_rect(device, &draw_rect);
4839 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4840 device->render_targets, device->depth_stencil, rect_count, rects,
4841 &draw_rect, flags, &c, depth, stencil);
4848 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4849 WINED3DPRIMITIVETYPE primitive_type)
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4855 This->updateStateBlock->changed.primitive_type = TRUE;
4856 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4859 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4860 WINED3DPRIMITIVETYPE *primitive_type)
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4866 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4868 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4871 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4875 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4877 if (!This->stateBlock->state.vertex_declaration)
4879 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4880 return WINED3DERR_INVALIDCALL;
4883 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4884 if (This->stateBlock->state.user_stream)
4886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4887 This->stateBlock->state.user_stream = FALSE;
4890 if (This->stateBlock->state.load_base_vertex_index)
4892 This->stateBlock->state.load_base_vertex_index = 0;
4893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4895 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4896 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4900 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 struct wined3d_buffer *index_buffer;
4907 index_buffer = This->stateBlock->state.index_buffer;
4910 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4911 * without an index buffer set. (The first time at least...)
4912 * D3D8 simply dies, but I doubt it can do much harm to return
4913 * D3DERR_INVALIDCALL there as well. */
4914 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4915 return WINED3DERR_INVALIDCALL;
4918 if (!This->stateBlock->state.vertex_declaration)
4920 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4921 return WINED3DERR_INVALIDCALL;
4924 if (This->stateBlock->state.user_stream)
4926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4927 This->stateBlock->state.user_stream = FALSE;
4929 vbo = index_buffer->buffer_object;
4931 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4933 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4938 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4940 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4944 drawPrimitive(This, index_count, startIndex, idxStride,
4945 vbo ? NULL : index_buffer->resource.allocatedMemory);
4950 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4951 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 struct wined3d_stream_state *stream;
4955 struct wined3d_buffer *vb;
4957 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4958 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4960 if (!This->stateBlock->state.vertex_declaration)
4962 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4963 return WINED3DERR_INVALIDCALL;
4966 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4967 stream = &This->stateBlock->state.streams[0];
4968 vb = stream->buffer;
4969 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4971 wined3d_buffer_decref(vb);
4973 stream->stride = VertexStreamZeroStride;
4974 This->stateBlock->state.user_stream = TRUE;
4975 This->stateBlock->state.load_base_vertex_index = 0;
4977 /* TODO: Only mark dirty if drawing from a different UP address */
4978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4980 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4982 /* MSDN specifies stream zero settings must be set to NULL */
4983 stream->buffer = NULL;
4986 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4987 * the new stream sources or use UP drawing again
4992 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4993 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4994 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 struct wined3d_stream_state *stream;
4999 struct wined3d_buffer *vb, *ib;
5001 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
5002 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5004 if (!This->stateBlock->state.vertex_declaration)
5006 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5007 return WINED3DERR_INVALIDCALL;
5010 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5016 stream = &This->stateBlock->state.streams[0];
5017 vb = stream->buffer;
5018 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
5020 wined3d_buffer_decref(vb);
5022 stream->stride = VertexStreamZeroStride;
5023 This->stateBlock->state.user_stream = TRUE;
5025 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5026 This->stateBlock->state.base_vertex_index = 0;
5027 This->stateBlock->state.load_base_vertex_index = 0;
5028 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5032 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
5034 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5035 stream->buffer = NULL;
5037 ib = This->stateBlock->state.index_buffer;
5040 wined3d_buffer_decref(ib);
5041 This->stateBlock->state.index_buffer = NULL;
5043 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5044 * SetStreamSource to specify a vertex buffer
5050 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5051 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5055 /* Mark the state dirty until we have nicer tracking
5056 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5061 This->stateBlock->state.base_vertex_index = 0;
5062 This->up_strided = DrawPrimStrideData;
5063 drawPrimitive(This, vertex_count, 0, 0, NULL);
5064 This->up_strided = NULL;
5068 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5069 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5070 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5073 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5075 /* Mark the state dirty until we have nicer tracking
5076 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5081 This->stateBlock->state.user_stream = TRUE;
5082 This->stateBlock->state.base_vertex_index = 0;
5083 This->up_strided = DrawPrimStrideData;
5084 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5085 This->up_strided = NULL;
5089 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5090 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5091 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
5093 WINED3DLOCKED_BOX src;
5094 WINED3DLOCKED_BOX dst;
5097 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5098 iface, src_volume, dst_volume);
5100 /* TODO: Implement direct loading into the gl volume instead of using
5101 * memcpy and dirtification to improve loading performance. */
5102 hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY);
5103 if (FAILED(hr)) return hr;
5104 hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD);
5107 wined3d_volume_unmap(src_volume);
5111 memcpy(dst.pBits, src.pBits, dst_volume->resource.size);
5113 hr = wined3d_volume_unmap(dst_volume);
5115 wined3d_volume_unmap(src_volume);
5117 hr = wined3d_volume_unmap(src_volume);
5122 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5123 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5125 unsigned int level_count, i;
5126 WINED3DRESOURCETYPE type;
5129 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5131 /* Verify that the source and destination textures are non-NULL. */
5132 if (!src_texture || !dst_texture)
5134 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5135 return WINED3DERR_INVALIDCALL;
5138 if (src_texture == dst_texture)
5140 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5141 return WINED3DERR_INVALIDCALL;
5144 /* Verify that the source and destination textures are the same type. */
5145 type = wined3d_texture_get_type(src_texture);
5146 if (wined3d_texture_get_type(dst_texture) != type)
5148 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5149 return WINED3DERR_INVALIDCALL;
5152 /* Check that both textures have the identical numbers of levels. */
5153 level_count = wined3d_texture_get_level_count(src_texture);
5154 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5156 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5157 return WINED3DERR_INVALIDCALL;
5160 /* Make sure that the destination texture is loaded. */
5161 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5163 /* Update every surface level of the texture. */
5166 case WINED3DRTYPE_TEXTURE:
5168 IWineD3DSurface *src_surface;
5169 IWineD3DSurface *dst_surface;
5171 for (i = 0; i < level_count; ++i)
5173 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5175 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5177 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5180 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5187 case WINED3DRTYPE_CUBETEXTURE:
5189 IWineD3DSurface *src_surface;
5190 IWineD3DSurface *dst_surface;
5192 for (i = 0; i < level_count * 6; ++i)
5194 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5196 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5198 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5201 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5208 case WINED3DRTYPE_VOLUMETEXTURE:
5210 for (i = 0; i < level_count; ++i)
5212 hr = IWineD3DDeviceImpl_UpdateVolume(iface,
5213 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
5214 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
5217 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5225 FIXME("Unsupported texture type %#x.\n", type);
5226 return WINED3DERR_INVALIDCALL;
5232 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5233 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5235 struct wined3d_swapchain *swapchain;
5238 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5240 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5241 if (FAILED(hr)) return hr;
5243 hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
5244 wined3d_swapchain_decref(swapchain);
5249 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5252 const struct wined3d_state *state = &This->stateBlock->state;
5253 struct wined3d_texture *texture;
5256 TRACE("(%p) : %p\n", This, pNumPasses);
5258 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5260 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5262 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5263 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5265 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5267 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5268 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5271 texture = state->textures[i];
5272 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5274 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5276 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5279 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5281 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5284 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5285 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5287 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5292 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5293 state->render_states[WINED3DRS_STENCILENABLE])
5295 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5296 IWineD3DSurfaceImpl *target = This->render_targets[0];
5299 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5301 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5302 return WINED3DERR_CONFLICTINGRENDERSTATE;
5306 /* return a sensible default */
5309 TRACE("returning D3D_OK\n");
5313 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5317 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5319 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5320 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5321 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5323 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5328 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface,
5329 UINT PaletteNumber, const PALETTEENTRY *pEntries)
5331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5334 PALETTEENTRY **palettes;
5336 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5338 if (PaletteNumber >= MAX_PALETTES) {
5339 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5340 return WINED3DERR_INVALIDCALL;
5343 if (PaletteNumber >= This->palette_count)
5345 NewSize = This->palette_count;
5348 } while(PaletteNumber >= NewSize);
5349 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5351 ERR("Out of memory!\n");
5352 return E_OUTOFMEMORY;
5354 This->palettes = palettes;
5355 This->palette_count = NewSize;
5358 if (!This->palettes[PaletteNumber]) {
5359 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5360 if (!This->palettes[PaletteNumber]) {
5361 ERR("Out of memory!\n");
5362 return E_OUTOFMEMORY;
5366 for (j = 0; j < 256; ++j) {
5367 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5368 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5369 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5370 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5372 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5373 TRACE("(%p) : returning\n", This);
5377 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface,
5378 UINT PaletteNumber, PALETTEENTRY *pEntries)
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5382 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5384 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5386 /* What happens in such situation isn't documented; Native seems to silently abort
5387 on such conditions. Return Invalid Call. */
5388 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5389 return WINED3DERR_INVALIDCALL;
5391 for (j = 0; j < 256; ++j) {
5392 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5393 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5394 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5395 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5397 TRACE("(%p) : returning\n", This);
5401 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber)
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5405 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5406 (tested with reference rasterizer). Return Invalid Call. */
5407 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5409 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5410 return WINED3DERR_INVALIDCALL;
5412 /*TODO: stateblocks */
5413 if (This->currentPalette != PaletteNumber) {
5414 This->currentPalette = PaletteNumber;
5415 dirtify_p8_texture_samplers(This);
5417 TRACE("(%p) : returning\n", This);
5421 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5426 WARN("(%p) : returning Invalid Call\n", This);
5427 return WINED3DERR_INVALIDCALL;
5429 /*TODO: stateblocks */
5430 *PaletteNumber = This->currentPalette;
5431 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5435 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5440 FIXME("(%p) : stub\n", This);
5444 This->softwareVertexProcessing = bSoftware;
5449 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 FIXME("(%p) : stub\n", This);
5457 return This->softwareVertexProcessing;
5460 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5461 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5463 struct wined3d_swapchain *swapchain;
5466 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5467 iface, swapchain_idx, raster_status);
5469 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5472 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5476 hr = wined3d_swapchain_get_raster_status(swapchain, raster_status);
5477 wined3d_swapchain_decref(swapchain);
5480 WARN("Failed to get raster status, hr %#x.\n", hr);
5487 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5490 if(nSegments != 0.0f) {
5493 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5500 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5505 FIXME("iface %p stub!\n", iface);
5511 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5512 IWineD3DSurface *src_surface, const RECT *src_rect,
5513 IWineD3DSurface *dst_surface, const POINT *dst_point)
5515 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5516 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5518 const struct wined3d_format *src_format;
5519 const struct wined3d_format *dst_format;
5520 const struct wined3d_gl_info *gl_info;
5521 struct wined3d_context *context;
5522 const unsigned char *data;
5523 UINT update_w, update_h;
5524 CONVERT_TYPES convert;
5528 struct wined3d_format format;
5530 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5531 iface, src_surface, wine_dbgstr_rect(src_rect),
5532 dst_surface, wine_dbgstr_point(dst_point));
5534 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5536 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5537 src_surface, dst_surface);
5538 return WINED3DERR_INVALIDCALL;
5541 src_format = src_impl->resource.format;
5542 dst_format = dst_impl->resource.format;
5544 if (src_format->id != dst_format->id)
5546 WARN("Source and destination surfaces should have the same format.\n");
5547 return WINED3DERR_INVALIDCALL;
5550 dst_x = dst_point ? dst_point->x : 0;
5551 dst_y = dst_point ? dst_point->y : 0;
5553 /* This call loads the OpenGL surface directly, instead of copying the
5554 * surface to the destination's sysmem copy. If surface conversion is
5555 * needed, use BltFast instead to copy in sysmem and use regular surface
5557 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5558 if (convert != NO_CONVERSION || format.convert)
5559 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5561 context = context_acquire(This, NULL);
5562 gl_info = context->gl_info;
5565 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5566 checkGLcall("glActiveTextureARB");
5569 /* Make sure the surface is loaded and up to date */
5570 surface_internal_preload(dst_impl, SRGB_RGB);
5571 surface_bind(dst_impl, gl_info, FALSE);
5573 src_w = src_impl->resource.width;
5574 src_h = src_impl->resource.height;
5575 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5576 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5578 data = src_impl->resource.allocatedMemory;
5579 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5583 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5585 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5586 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5587 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5591 data += (src_rect->top / src_format->block_height) * src_pitch;
5592 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5595 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5596 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5597 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5599 if (row_length == src_pitch)
5601 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5602 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5608 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5609 * can't use the unpack row length like below. */
5610 for (row = 0, y = dst_y; row < row_count; ++row)
5612 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5613 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5614 y += src_format->block_height;
5618 checkGLcall("glCompressedTexSubImage2DARB");
5624 data += src_rect->top * src_w * src_format->byte_count;
5625 data += src_rect->left * src_format->byte_count;
5628 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5629 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5630 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5632 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5633 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5634 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5635 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5636 checkGLcall("glTexSubImage2D");
5640 context_release(context);
5642 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5643 sampler = This->rev_tex_unit_map[0];
5644 if (sampler != WINED3D_UNMAPPED_STAGE)
5646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5652 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5654 struct WineD3DRectPatch *patch;
5655 GLenum old_primitive_type;
5659 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5661 if(!(Handle || pRectPatchInfo)) {
5662 /* TODO: Write a test for the return value, thus the FIXME */
5663 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5664 return WINED3DERR_INVALIDCALL;
5668 i = PATCHMAP_HASHFUNC(Handle);
5670 LIST_FOR_EACH(e, &This->patches[i]) {
5671 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5672 if(patch->Handle == Handle) {
5679 TRACE("Patch does not exist. Creating a new one\n");
5680 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5681 patch->Handle = Handle;
5682 list_add_head(&This->patches[i], &patch->entry);
5684 TRACE("Found existing patch %p\n", patch);
5687 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5688 * attributes we have to tesselate, read back, and draw. This needs a patch
5689 * management structure instance. Create one.
5691 * A possible improvement is to check if a vertex shader is used, and if not directly
5694 FIXME("Drawing an uncached patch. This is slow\n");
5695 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5698 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5699 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5700 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5703 TRACE("Tesselation density or patch info changed, retesselating\n");
5705 if(pRectPatchInfo) {
5706 patch->RectPatchInfo = *pRectPatchInfo;
5708 patch->numSegs[0] = pNumSegs[0];
5709 patch->numSegs[1] = pNumSegs[1];
5710 patch->numSegs[2] = pNumSegs[2];
5711 patch->numSegs[3] = pNumSegs[3];
5713 hr = tesselate_rectpatch(This, patch);
5715 WARN("Patch tesselation failed\n");
5717 /* Do not release the handle to store the params of the patch */
5719 HeapFree(GetProcessHeap(), 0, patch);
5725 This->currentPatch = patch;
5726 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5727 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5728 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5729 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5730 This->currentPatch = NULL;
5732 /* Destroy uncached patches */
5734 HeapFree(GetProcessHeap(), 0, patch->mem);
5735 HeapFree(GetProcessHeap(), 0, patch);
5740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5741 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5743 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5744 iface, handle, segment_count, patch_info);
5749 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 struct WineD3DRectPatch *patch;
5754 TRACE("(%p) Handle(%d)\n", This, Handle);
5756 i = PATCHMAP_HASHFUNC(Handle);
5757 LIST_FOR_EACH(e, &This->patches[i]) {
5758 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5759 if(patch->Handle == Handle) {
5760 TRACE("Deleting patch %p\n", patch);
5761 list_remove(&patch->entry);
5762 HeapFree(GetProcessHeap(), 0, patch->mem);
5763 HeapFree(GetProcessHeap(), 0, patch);
5768 /* TODO: Write a test for the return value */
5769 FIXME("Attempt to destroy nonexistent patch\n");
5770 return WINED3DERR_INVALIDCALL;
5773 /* Do not call while under the GL lock. */
5774 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5775 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5777 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5779 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5780 iface, surface, wine_dbgstr_rect(rect),
5781 color->r, color->g, color->b, color->a);
5783 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5785 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5786 return WINED3DERR_INVALIDCALL;
5789 return surface_color_fill(s, rect, color);
5792 /* Do not call while under the GL lock. */
5793 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5794 struct wined3d_rendertarget_view *rendertarget_view, const WINED3DCOLORVALUE *color)
5796 struct wined3d_resource *resource;
5799 resource = rendertarget_view->resource;
5800 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5802 FIXME("Only supported on surface resources\n");
5806 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5807 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5810 /* rendertarget and depth stencil functions */
5811 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5812 DWORD render_target_idx, IWineD3DSurface **render_target)
5814 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5816 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5817 iface, render_target_idx, render_target);
5819 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5821 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5822 return WINED3DERR_INVALIDCALL;
5825 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5826 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5828 TRACE("Returning render target %p.\n", *render_target);
5833 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5835 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5837 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5839 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5840 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5841 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5842 IWineD3DSurface_AddRef(*depth_stencil);
5847 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5848 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5850 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5851 IWineD3DSurfaceImpl *prev;
5853 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5854 iface, render_target_idx, render_target, set_viewport);
5856 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5858 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5859 return WINED3DERR_INVALIDCALL;
5862 prev = device->render_targets[render_target_idx];
5863 if (render_target == (IWineD3DSurface *)prev)
5865 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5869 /* Render target 0 can't be set to NULL. */
5870 if (!render_target && !render_target_idx)
5872 WARN("Trying to set render target 0 to NULL.\n");
5873 return WINED3DERR_INVALIDCALL;
5876 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5878 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5879 return WINED3DERR_INVALIDCALL;
5882 if (render_target) IWineD3DSurface_AddRef(render_target);
5883 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5884 /* Release after the assignment, to prevent device_resource_released()
5885 * from seeing the surface as still in use. */
5886 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5888 /* Render target 0 is special. */
5889 if (!render_target_idx && set_viewport)
5891 /* Set the viewport and scissor rectangles, if requested. Tests show
5892 * that stateblock recording is ignored, the change goes directly
5893 * into the primary stateblock. */
5894 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5895 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5896 device->stateBlock->state.viewport.X = 0;
5897 device->stateBlock->state.viewport.Y = 0;
5898 device->stateBlock->state.viewport.MaxZ = 1.0f;
5899 device->stateBlock->state.viewport.MinZ = 0.0f;
5900 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5902 device->stateBlock->state.scissor_rect.top = 0;
5903 device->stateBlock->state.scissor_rect.left = 0;
5904 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5905 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5906 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5912 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5915 IWineD3DSurfaceImpl *tmp;
5917 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5919 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5921 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5925 if (This->depth_stencil)
5927 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5928 || This->depth_stencil->flags & SFLAG_DISCARD)
5930 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5931 This->depth_stencil->resource.width,
5932 This->depth_stencil->resource.height);
5933 if (This->depth_stencil == This->onscreen_depth_stencil)
5935 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5936 This->onscreen_depth_stencil = NULL;
5941 tmp = This->depth_stencil;
5942 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5943 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5944 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5946 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5948 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5957 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5958 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5961 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5962 WINED3DLOCKED_RECT lockedRect;
5964 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5965 iface, XHotSpot, YHotSpot, cursor_image);
5967 /* some basic validation checks */
5968 if (This->cursorTexture)
5970 struct wined3d_context *context = context_acquire(This, NULL);
5972 glDeleteTextures(1, &This->cursorTexture);
5974 context_release(context);
5975 This->cursorTexture = 0;
5978 if (s->resource.width == 32 && s->resource.height == 32)
5979 This->haveHardwareCursor = TRUE;
5981 This->haveHardwareCursor = FALSE;
5985 WINED3DLOCKED_RECT rect;
5987 /* MSDN: Cursor must be A8R8G8B8 */
5988 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5990 WARN("surface %p has an invalid format.\n", cursor_image);
5991 return WINED3DERR_INVALIDCALL;
5994 /* MSDN: Cursor must be smaller than the display mode */
5995 if (s->resource.width > This->ddraw_width
5996 || s->resource.height > This->ddraw_height)
5998 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5999 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
6000 return WINED3DERR_INVALIDCALL;
6003 if (!This->haveHardwareCursor) {
6004 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6006 /* Do not store the surface's pointer because the application may
6007 * release it after setting the cursor image. Windows doesn't
6008 * addref the set surface, so we can't do this either without
6009 * creating circular refcount dependencies. Copy out the gl texture
6012 This->cursorWidth = s->resource.width;
6013 This->cursorHeight = s->resource.height;
6014 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
6016 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6017 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
6018 struct wined3d_context *context;
6019 char *mem, *bits = rect.pBits;
6020 GLint intfmt = format->glInternal;
6021 GLint gl_format = format->glFormat;
6022 GLint type = format->glType;
6023 INT height = This->cursorHeight;
6024 INT width = This->cursorWidth;
6025 INT bpp = format->byte_count;
6029 /* Reformat the texture memory (pitch and width can be
6031 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6032 for(i = 0; i < height; i++)
6033 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6034 IWineD3DSurface_Unmap(cursor_image);
6036 context = context_acquire(This, NULL);
6040 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6042 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6043 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6046 /* Make sure that a proper texture unit is selected */
6047 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6048 checkGLcall("glActiveTextureARB");
6049 sampler = This->rev_tex_unit_map[0];
6050 if (sampler != WINED3D_UNMAPPED_STAGE)
6052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6054 /* Create a new cursor texture */
6055 glGenTextures(1, &This->cursorTexture);
6056 checkGLcall("glGenTextures");
6057 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6058 checkGLcall("glBindTexture");
6059 /* Copy the bitmap memory into the cursor texture */
6060 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6061 checkGLcall("glTexImage2D");
6062 HeapFree(GetProcessHeap(), 0, mem);
6064 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6066 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6067 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6072 context_release(context);
6076 FIXME("A cursor texture was not returned.\n");
6077 This->cursorTexture = 0;
6082 /* Draw a hardware cursor */
6083 ICONINFO cursorInfo;
6085 /* Create and clear maskBits because it is not needed for
6086 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6088 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6089 (s->resource.width * s->resource.height / 8));
6090 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6091 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6092 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6094 cursorInfo.fIcon = FALSE;
6095 cursorInfo.xHotspot = XHotSpot;
6096 cursorInfo.yHotspot = YHotSpot;
6097 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6098 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6099 IWineD3DSurface_Unmap(cursor_image);
6100 /* Create our cursor and clean up. */
6101 cursor = CreateIconIndirect(&cursorInfo);
6103 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6104 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6105 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6106 This->hardwareCursor = cursor;
6107 HeapFree(GetProcessHeap(), 0, maskBits);
6111 This->xHotSpot = XHotSpot;
6112 This->yHotSpot = YHotSpot;
6116 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6117 int XScreenSpace, int YScreenSpace, DWORD flags)
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6121 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6122 iface, XScreenSpace, YScreenSpace, flags);
6124 This->xScreenSpace = XScreenSpace;
6125 This->yScreenSpace = YScreenSpace;
6128 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6130 BOOL oldVisible = This->bCursorVisible;
6133 TRACE("(%p) : visible(%d)\n", This, bShow);
6136 * When ShowCursor is first called it should make the cursor appear at the OS's last
6137 * known cursor position. Because of this, some applications just repetitively call
6138 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6141 This->xScreenSpace = pt.x;
6142 This->yScreenSpace = pt.y;
6144 if (This->haveHardwareCursor) {
6145 This->bCursorVisible = bShow;
6147 SetCursor(This->hardwareCursor);
6153 if (This->cursorTexture)
6154 This->bCursorVisible = bShow;
6160 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6162 TRACE("checking resource %p for eviction\n", resource);
6164 if (resource->pool == WINED3DPOOL_MANAGED)
6166 TRACE("Evicting %p.\n", resource);
6167 resource->resource_ops->resource_unload(resource);
6173 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6175 TRACE("iface %p.\n", iface);
6177 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6178 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6179 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6184 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6186 IWineD3DDeviceImpl *device = surface->resource.device;
6187 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6189 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6190 if (surface->flags & SFLAG_DIBSECTION)
6192 /* Release the DC */
6193 SelectObject(surface->hDC, surface->dib.holdbitmap);
6194 DeleteDC(surface->hDC);
6195 /* Release the DIB section */
6196 DeleteObject(surface->dib.DIBsection);
6197 surface->dib.bitmap_data = NULL;
6198 surface->resource.allocatedMemory = NULL;
6199 surface->flags &= ~SFLAG_DIBSECTION;
6201 surface->resource.width = pPresentationParameters->BackBufferWidth;
6202 surface->resource.height = pPresentationParameters->BackBufferHeight;
6203 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6204 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6206 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6207 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6209 surface->pow2Width = surface->pow2Height = 1;
6210 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6211 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6214 if (surface->texture_name)
6216 struct wined3d_context *context = context_acquire(device, NULL);
6218 glDeleteTextures(1, &surface->texture_name);
6220 context_release(context);
6221 surface->texture_name = 0;
6222 surface->flags &= ~SFLAG_CLIENT;
6224 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6225 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6227 surface->flags |= SFLAG_NONPOW2;
6231 surface->flags &= ~SFLAG_NONPOW2;
6233 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6234 surface->resource.allocatedMemory = NULL;
6235 surface->resource.heapMemory = NULL;
6236 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6238 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6240 if (!surface_init_sysmem(surface))
6242 return E_OUTOFMEMORY;
6247 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6250 WINED3DDISPLAYMODE m;
6253 /* All Windowed modes are supported, as is leaving the current mode */
6254 if(pp->Windowed) return TRUE;
6255 if(!pp->BackBufferWidth) return TRUE;
6256 if(!pp->BackBufferHeight) return TRUE;
6258 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6259 for (i = 0; i < count; ++i)
6261 memset(&m, 0, sizeof(m));
6262 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6264 ERR("Failed to enumerate adapter mode.\n");
6265 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6266 /* Mode found, it is supported. */
6269 /* Mode not found -> not supported */
6273 /* Do not call while under the GL lock. */
6274 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6276 const struct wined3d_gl_info *gl_info;
6277 struct wined3d_context *context;
6278 struct wined3d_shader *shader;
6280 context = context_acquire(device, NULL);
6281 gl_info = context->gl_info;
6283 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6284 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
6286 device->shader_backend->shader_destroy(shader);
6290 if (device->depth_blt_texture)
6292 glDeleteTextures(1, &device->depth_blt_texture);
6293 device->depth_blt_texture = 0;
6295 if (device->depth_blt_rb)
6297 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6298 device->depth_blt_rb = 0;
6299 device->depth_blt_rb_w = 0;
6300 device->depth_blt_rb_h = 0;
6304 device->blitter->free_private(device);
6305 device->frag_pipe->free_private(device);
6306 device->shader_backend->shader_free_private(device);
6307 destroy_dummy_textures(device, gl_info);
6309 context_release(context);
6311 while (device->context_count)
6313 context_destroy(device, device->contexts[0]);
6315 HeapFree(GetProcessHeap(), 0, swapchain->context);
6316 swapchain->context = NULL;
6317 swapchain->num_contexts = 0;
6320 /* Do not call while under the GL lock. */
6321 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6323 struct wined3d_context *context;
6325 IWineD3DSurfaceImpl *target;
6327 /* Recreate the primary swapchain's context */
6328 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6329 if (!swapchain->context)
6331 ERR("Failed to allocate memory for swapchain context array.\n");
6332 return E_OUTOFMEMORY;
6335 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6336 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6338 WARN("Failed to create context.\n");
6339 HeapFree(GetProcessHeap(), 0, swapchain->context);
6343 swapchain->context[0] = context;
6344 swapchain->num_contexts = 1;
6345 create_dummy_textures(device);
6346 context_release(context);
6348 hr = device->shader_backend->shader_alloc_private(device);
6351 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6355 hr = device->frag_pipe->alloc_private(device);
6358 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6359 device->shader_backend->shader_free_private(device);
6363 hr = device->blitter->alloc_private(device);
6366 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6367 device->frag_pipe->free_private(device);
6368 device->shader_backend->shader_free_private(device);
6375 context_acquire(device, NULL);
6376 destroy_dummy_textures(device, context->gl_info);
6377 context_release(context);
6378 context_destroy(device, context);
6379 HeapFree(GetProcessHeap(), 0, swapchain->context);
6380 swapchain->num_contexts = 0;
6384 /* Do not call while under the GL lock. */
6385 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6386 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6389 struct wined3d_swapchain *swapchain;
6391 BOOL DisplayModeChanged = FALSE;
6392 WINED3DDISPLAYMODE mode;
6393 TRACE("(%p)\n", This);
6395 hr = IWineD3DDevice_GetSwapChain(iface, 0, &swapchain);
6398 ERR("Failed to get the first implicit swapchain\n");
6402 if(!is_display_mode_supported(This, pPresentationParameters)) {
6403 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6404 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6405 pPresentationParameters->BackBufferHeight);
6406 wined3d_swapchain_decref(swapchain);
6407 return WINED3DERR_INVALIDCALL;
6410 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6411 * on an existing gl context, so there's no real need for recreation.
6413 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6415 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6417 TRACE("New params:\n");
6418 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6419 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6420 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6421 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6422 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6423 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6424 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6425 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6426 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6427 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6428 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6429 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6430 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6432 /* No special treatment of these parameters. Just store them */
6433 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6434 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6435 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6436 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6438 /* What to do about these? */
6439 if (pPresentationParameters->BackBufferCount
6440 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6441 ERR("Cannot change the back buffer count yet\n");
6443 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6444 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6445 ERR("Cannot change the back buffer format yet\n");
6448 if (pPresentationParameters->hDeviceWindow
6449 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6450 ERR("Cannot change the device window yet\n");
6452 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6456 TRACE("Creating the depth stencil buffer\n");
6458 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6459 pPresentationParameters->BackBufferWidth,
6460 pPresentationParameters->BackBufferHeight,
6461 pPresentationParameters->AutoDepthStencilFormat,
6462 pPresentationParameters->MultiSampleType,
6463 pPresentationParameters->MultiSampleQuality,
6465 (IWineD3DSurface **)&This->auto_depth_stencil);
6468 ERR("Failed to create the depth stencil buffer.\n");
6469 wined3d_swapchain_decref(swapchain);
6470 return WINED3DERR_INVALIDCALL;
6474 if (This->onscreen_depth_stencil)
6476 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6477 This->onscreen_depth_stencil = NULL;
6480 /* Reset the depth stencil */
6481 if (pPresentationParameters->EnableAutoDepthStencil)
6482 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6484 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6486 TRACE("Resetting stateblock\n");
6487 wined3d_stateblock_decref(This->updateStateBlock);
6488 wined3d_stateblock_decref(This->stateBlock);
6490 delete_opengl_contexts(This, swapchain);
6492 if(pPresentationParameters->Windowed) {
6493 mode.Width = swapchain->orig_width;
6494 mode.Height = swapchain->orig_height;
6495 mode.RefreshRate = 0;
6496 mode.Format = swapchain->presentParms.BackBufferFormat;
6498 mode.Width = pPresentationParameters->BackBufferWidth;
6499 mode.Height = pPresentationParameters->BackBufferHeight;
6500 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6501 mode.Format = swapchain->presentParms.BackBufferFormat;
6504 /* Should Width == 800 && Height == 0 set 800x600? */
6505 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6506 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6507 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6511 if(!pPresentationParameters->Windowed) {
6512 DisplayModeChanged = TRUE;
6514 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6515 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6517 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6520 wined3d_swapchain_decref(swapchain);
6524 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6526 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6529 wined3d_swapchain_decref(swapchain);
6533 if (This->auto_depth_stencil)
6535 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6538 wined3d_swapchain_decref(swapchain);
6544 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6545 || DisplayModeChanged)
6547 BOOL filter = This->filter_messages;
6548 This->filter_messages = TRUE;
6550 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6552 if (!pPresentationParameters->Windowed)
6554 if (swapchain->presentParms.Windowed)
6556 HWND focus_window = This->createParms.hFocusWindow;
6557 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6558 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6560 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6561 wined3d_swapchain_decref(swapchain);
6565 /* switch from windowed to fs */
6566 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6567 pPresentationParameters->BackBufferWidth,
6568 pPresentationParameters->BackBufferHeight);
6572 /* Fullscreen -> fullscreen mode change */
6573 MoveWindow(swapchain->device_window, 0, 0,
6574 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6578 else if (!swapchain->presentParms.Windowed)
6580 /* Fullscreen -> windowed switch */
6581 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6582 IWineD3DDevice_ReleaseFocusWindow(iface);
6584 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6586 This->filter_messages = filter;
6588 else if (!pPresentationParameters->Windowed)
6590 DWORD style = This->style, exStyle = This->exStyle;
6591 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6592 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6593 * Reset to clear up their mess. Guild Wars also loses the device during that.
6597 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6598 pPresentationParameters->BackBufferWidth,
6599 pPresentationParameters->BackBufferHeight);
6600 This->style = style;
6601 This->exStyle = exStyle;
6604 /* Note: No parent needed for initial internal stateblock */
6605 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6606 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6607 else TRACE("Created stateblock %p\n", This->stateBlock);
6608 This->updateStateBlock = This->stateBlock;
6609 wined3d_stateblock_incref(This->updateStateBlock);
6611 stateblock_init_default_state(This->stateBlock);
6613 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6616 GetClientRect(swapchain->win_handle, &client_rect);
6618 if(!swapchain->presentParms.BackBufferCount)
6620 TRACE("Single buffered rendering\n");
6621 swapchain->render_to_fbo = FALSE;
6623 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6624 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6626 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6627 swapchain->presentParms.BackBufferWidth,
6628 swapchain->presentParms.BackBufferHeight,
6629 client_rect.right, client_rect.bottom);
6630 swapchain->render_to_fbo = TRUE;
6634 TRACE("Rendering directly to GL_BACK\n");
6635 swapchain->render_to_fbo = FALSE;
6639 hr = create_primary_opengl_context(This, swapchain);
6640 wined3d_swapchain_decref(swapchain);
6642 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6648 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6650 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6652 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6658 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6660 TRACE("(%p) : pParameters %p\n", This, pParameters);
6662 *pParameters = This->createParms;
6666 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6667 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6669 struct wined3d_swapchain *swapchain;
6671 TRACE("Relaying to swapchain\n");
6673 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6675 wined3d_swapchain_set_gamma_ramp(swapchain, flags, pRamp);
6676 wined3d_swapchain_decref(swapchain);
6680 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp)
6682 struct wined3d_swapchain *swapchain;
6684 TRACE("Relaying to swapchain\n");
6686 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6688 wined3d_swapchain_get_gamma_ramp(swapchain, pRamp);
6689 wined3d_swapchain_decref(swapchain);
6693 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6695 TRACE("device %p, resource %p.\n", device, resource);
6697 list_add_head(&device->resources, &resource->resource_list_entry);
6700 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6702 TRACE("device %p, resource %p.\n", device, resource);
6704 list_remove(&resource->resource_list_entry);
6707 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6709 WINED3DRESOURCETYPE type = resource->resourceType;
6712 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6714 context_resource_released(device, resource, type);
6718 case WINED3DRTYPE_SURFACE:
6720 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6722 if (!device->d3d_initialized) break;
6724 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6726 if (device->render_targets[i] == surface)
6728 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6729 device->render_targets[i] = NULL;
6733 if (device->depth_stencil == surface)
6735 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6736 device->depth_stencil = NULL;
6741 case WINED3DRTYPE_TEXTURE:
6742 case WINED3DRTYPE_CUBETEXTURE:
6743 case WINED3DRTYPE_VOLUMETEXTURE:
6744 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6746 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6748 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6750 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6751 texture, device->stateBlock, i);
6752 device->stateBlock->state.textures[i] = NULL;
6755 if (device->updateStateBlock != device->stateBlock
6756 && device->updateStateBlock->state.textures[i] == texture)
6758 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6759 texture, device->updateStateBlock, i);
6760 device->updateStateBlock->state.textures[i] = NULL;
6765 case WINED3DRTYPE_BUFFER:
6767 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6769 for (i = 0; i < MAX_STREAMS; ++i)
6771 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6773 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6774 buffer, device->stateBlock, i);
6775 device->stateBlock->state.streams[i].buffer = NULL;
6778 if (device->updateStateBlock != device->stateBlock
6779 && device->updateStateBlock->state.streams[i].buffer == buffer)
6781 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6782 buffer, device->updateStateBlock, i);
6783 device->updateStateBlock->state.streams[i].buffer = NULL;
6788 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6790 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6791 buffer, device->stateBlock);
6792 device->stateBlock->state.index_buffer = NULL;
6795 if (device->updateStateBlock != device->stateBlock
6796 && device->updateStateBlock->state.index_buffer == buffer)
6798 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6799 buffer, device->updateStateBlock);
6800 device->updateStateBlock->state.index_buffer = NULL;
6809 /* Remove the resource from the resourceStore */
6810 device_resource_remove(device, resource);
6812 TRACE("Resource released.\n");
6815 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6816 D3DCB_ENUMRESOURCES callback, void *data)
6818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6819 struct wined3d_resource *resource, *cursor;
6821 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6823 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6825 TRACE("enumerating resource %p.\n", resource);
6826 if (callback(resource, data) == S_FALSE)
6828 TRACE("Canceling enumeration.\n");
6836 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6839 struct wined3d_resource *resource;
6841 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6843 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6845 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6849 TRACE("Found surface %p for dc %p.\n", s, dc);
6850 *surface = (IWineD3DSurface *)s;
6856 return WINED3DERR_INVALIDCALL;
6859 /**********************************************************
6860 * IWineD3DDevice VTbl follows
6861 **********************************************************/
6863 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6865 /*** IUnknown methods ***/
6866 IWineD3DDeviceImpl_QueryInterface,
6867 IWineD3DDeviceImpl_AddRef,
6868 IWineD3DDeviceImpl_Release,
6869 /*** IWineD3DDevice methods ***/
6870 /*** Creation methods**/
6871 IWineD3DDeviceImpl_CreateBuffer,
6872 IWineD3DDeviceImpl_CreateVertexBuffer,
6873 IWineD3DDeviceImpl_CreateIndexBuffer,
6874 IWineD3DDeviceImpl_CreateStateBlock,
6875 IWineD3DDeviceImpl_CreateSurface,
6876 IWineD3DDeviceImpl_CreateRendertargetView,
6877 IWineD3DDeviceImpl_CreateTexture,
6878 IWineD3DDeviceImpl_CreateVolumeTexture,
6879 IWineD3DDeviceImpl_CreateVolume,
6880 IWineD3DDeviceImpl_CreateCubeTexture,
6881 IWineD3DDeviceImpl_CreateQuery,
6882 IWineD3DDeviceImpl_CreateSwapChain,
6883 IWineD3DDeviceImpl_CreateVertexDeclaration,
6884 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6885 IWineD3DDeviceImpl_CreateVertexShader,
6886 IWineD3DDeviceImpl_CreateGeometryShader,
6887 IWineD3DDeviceImpl_CreatePixelShader,
6888 IWineD3DDeviceImpl_CreatePalette,
6889 /*** Odd functions **/
6890 IWineD3DDeviceImpl_Init3D,
6891 IWineD3DDeviceImpl_InitGDI,
6892 IWineD3DDeviceImpl_Uninit3D,
6893 IWineD3DDeviceImpl_UninitGDI,
6894 IWineD3DDeviceImpl_SetMultithreaded,
6895 IWineD3DDeviceImpl_EvictManagedResources,
6896 IWineD3DDeviceImpl_GetAvailableTextureMem,
6897 IWineD3DDeviceImpl_GetBackBuffer,
6898 IWineD3DDeviceImpl_GetCreationParameters,
6899 IWineD3DDeviceImpl_GetDeviceCaps,
6900 IWineD3DDeviceImpl_GetDirect3D,
6901 IWineD3DDeviceImpl_GetDisplayMode,
6902 IWineD3DDeviceImpl_SetDisplayMode,
6903 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6904 IWineD3DDeviceImpl_GetRasterStatus,
6905 IWineD3DDeviceImpl_GetSwapChain,
6906 IWineD3DDeviceImpl_Reset,
6907 IWineD3DDeviceImpl_SetDialogBoxMode,
6908 IWineD3DDeviceImpl_SetCursorProperties,
6909 IWineD3DDeviceImpl_SetCursorPosition,
6910 IWineD3DDeviceImpl_ShowCursor,
6911 /*** Getters and setters **/
6912 IWineD3DDeviceImpl_SetClipPlane,
6913 IWineD3DDeviceImpl_GetClipPlane,
6914 IWineD3DDeviceImpl_SetClipStatus,
6915 IWineD3DDeviceImpl_GetClipStatus,
6916 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6917 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6918 IWineD3DDeviceImpl_SetDepthStencilSurface,
6919 IWineD3DDeviceImpl_GetDepthStencilSurface,
6920 IWineD3DDeviceImpl_SetGammaRamp,
6921 IWineD3DDeviceImpl_GetGammaRamp,
6922 IWineD3DDeviceImpl_SetIndexBuffer,
6923 IWineD3DDeviceImpl_GetIndexBuffer,
6924 IWineD3DDeviceImpl_SetBaseVertexIndex,
6925 IWineD3DDeviceImpl_GetBaseVertexIndex,
6926 IWineD3DDeviceImpl_SetLight,
6927 IWineD3DDeviceImpl_GetLight,
6928 IWineD3DDeviceImpl_SetLightEnable,
6929 IWineD3DDeviceImpl_GetLightEnable,
6930 IWineD3DDeviceImpl_SetMaterial,
6931 IWineD3DDeviceImpl_GetMaterial,
6932 IWineD3DDeviceImpl_SetNPatchMode,
6933 IWineD3DDeviceImpl_GetNPatchMode,
6934 IWineD3DDeviceImpl_SetPaletteEntries,
6935 IWineD3DDeviceImpl_GetPaletteEntries,
6936 IWineD3DDeviceImpl_SetPixelShader,
6937 IWineD3DDeviceImpl_GetPixelShader,
6938 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6939 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6940 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6941 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6942 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6943 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6944 IWineD3DDeviceImpl_SetRenderState,
6945 IWineD3DDeviceImpl_GetRenderState,
6946 IWineD3DDeviceImpl_SetRenderTarget,
6947 IWineD3DDeviceImpl_GetRenderTarget,
6948 IWineD3DDeviceImpl_SetSamplerState,
6949 IWineD3DDeviceImpl_GetSamplerState,
6950 IWineD3DDeviceImpl_SetScissorRect,
6951 IWineD3DDeviceImpl_GetScissorRect,
6952 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6953 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6954 IWineD3DDeviceImpl_SetStreamSource,
6955 IWineD3DDeviceImpl_GetStreamSource,
6956 IWineD3DDeviceImpl_SetStreamSourceFreq,
6957 IWineD3DDeviceImpl_GetStreamSourceFreq,
6958 IWineD3DDeviceImpl_SetTexture,
6959 IWineD3DDeviceImpl_GetTexture,
6960 IWineD3DDeviceImpl_SetTextureStageState,
6961 IWineD3DDeviceImpl_GetTextureStageState,
6962 IWineD3DDeviceImpl_SetTransform,
6963 IWineD3DDeviceImpl_GetTransform,
6964 IWineD3DDeviceImpl_SetVertexDeclaration,
6965 IWineD3DDeviceImpl_GetVertexDeclaration,
6966 IWineD3DDeviceImpl_SetVertexShader,
6967 IWineD3DDeviceImpl_GetVertexShader,
6968 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6969 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6970 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6971 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6972 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6973 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6974 IWineD3DDeviceImpl_SetViewport,
6975 IWineD3DDeviceImpl_GetViewport,
6976 IWineD3DDeviceImpl_MultiplyTransform,
6977 IWineD3DDeviceImpl_ValidateDevice,
6978 IWineD3DDeviceImpl_ProcessVertices,
6979 /*** State block ***/
6980 IWineD3DDeviceImpl_BeginStateBlock,
6981 IWineD3DDeviceImpl_EndStateBlock,
6982 /*** Scene management ***/
6983 IWineD3DDeviceImpl_BeginScene,
6984 IWineD3DDeviceImpl_EndScene,
6985 IWineD3DDeviceImpl_Present,
6986 IWineD3DDeviceImpl_Clear,
6987 IWineD3DDeviceImpl_ClearRendertargetView,
6989 IWineD3DDeviceImpl_SetPrimitiveType,
6990 IWineD3DDeviceImpl_GetPrimitiveType,
6991 IWineD3DDeviceImpl_DrawPrimitive,
6992 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6993 IWineD3DDeviceImpl_DrawPrimitiveUP,
6994 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6995 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6996 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6997 IWineD3DDeviceImpl_DrawRectPatch,
6998 IWineD3DDeviceImpl_DrawTriPatch,
6999 IWineD3DDeviceImpl_DeletePatch,
7000 IWineD3DDeviceImpl_ColorFill,
7001 IWineD3DDeviceImpl_UpdateTexture,
7002 IWineD3DDeviceImpl_UpdateSurface,
7003 IWineD3DDeviceImpl_GetFrontBufferData,
7004 /*** object tracking ***/
7005 IWineD3DDeviceImpl_EnumResources,
7006 IWineD3DDeviceImpl_GetSurfaceFromDC,
7007 IWineD3DDeviceImpl_AcquireFocusWindow,
7008 IWineD3DDeviceImpl_ReleaseFocusWindow,
7009 IWineD3DDeviceImpl_SetupFullscreenWindow,
7010 IWineD3DDeviceImpl_RestoreFullscreenWindow,
7013 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
7014 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7015 IWineD3DDeviceParent *device_parent)
7017 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7018 const struct fragment_pipeline *fragment_pipeline;
7019 struct shader_caps shader_caps;
7020 struct fragment_caps ffp_caps;
7021 WINED3DDISPLAYMODE mode;
7025 device->lpVtbl = &IWineD3DDevice_Vtbl;
7027 device->wined3d = wined3d;
7028 wined3d_incref(device->wined3d);
7029 device->adapter = wined3d->adapter_count ? adapter : NULL;
7030 device->device_parent = device_parent;
7031 list_init(&device->resources);
7032 list_init(&device->shaders);
7034 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7036 /* Get the initial screen setup for ddraw. */
7037 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7040 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7041 wined3d_decref(device->wined3d);
7044 device->ddraw_width = mode.Width;
7045 device->ddraw_height = mode.Height;
7046 device->ddraw_format = mode.Format;
7048 /* Save the creation parameters. */
7049 device->createParms.AdapterOrdinal = adapter_idx;
7050 device->createParms.DeviceType = device_type;
7051 device->createParms.hFocusWindow = focus_window;
7052 device->createParms.BehaviorFlags = flags;
7054 device->devType = device_type;
7055 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7057 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7058 device->shader_backend = adapter->shader_backend;
7060 if (device->shader_backend)
7062 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7063 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7064 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7065 device->vs_clipping = shader_caps.VSClipping;
7067 fragment_pipeline = adapter->fragment_pipe;
7068 device->frag_pipe = fragment_pipeline;
7069 if (fragment_pipeline)
7071 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7072 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7074 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7075 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7078 ERR("Failed to compile state table, hr %#x.\n", hr);
7079 wined3d_decref(device->wined3d);
7083 device->blitter = adapter->blitter;
7089 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7090 DWORD rep = This->StateTable[state].representative;
7091 struct wined3d_context *context;
7096 for (i = 0; i < This->context_count; ++i)
7098 context = This->contexts[i];
7099 if(isStateDirty(context, rep)) continue;
7101 context->dirtyArray[context->numDirtyEntries++] = rep;
7102 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7103 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7104 context->isStateDirty[idx] |= (1 << shift);
7108 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7110 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7111 *width = context->current_rt->pow2Width;
7112 *height = context->current_rt->pow2Height;
7115 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7117 struct wined3d_swapchain *swapchain = context->swapchain;
7118 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7119 * current context's drawable, which is the size of the back buffer of the swapchain
7120 * the active context belongs to. */
7121 *width = swapchain->presentParms.BackBufferWidth;
7122 *height = swapchain->presentParms.BackBufferHeight;
7125 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7126 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7128 if (device->filter_messages)
7130 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7131 window, message, wparam, lparam);
7133 return DefWindowProcW(window, message, wparam, lparam);
7135 return DefWindowProcA(window, message, wparam, lparam);
7138 if (message == WM_DESTROY)
7140 TRACE("unregister window %p.\n", window);
7141 wined3d_unregister_window(window);
7143 if (device->focus_window == window) device->focus_window = NULL;
7144 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7148 return CallWindowProcW(proc, window, message, wparam, lparam);
7150 return CallWindowProcA(proc, window, message, wparam, lparam);