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;
2140 TRACE("(%p)\n", This);
2142 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2144 /* Force making the context current again, to verify it is still valid
2145 * (workaround for broken drivers) */
2146 context_set_current(NULL);
2147 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2148 * it was created. Thus make sure a context is active for the glDelete* calls
2150 context = context_acquire(This, NULL);
2151 gl_info = context->gl_info;
2153 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2155 /* Unload resources */
2156 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2158 TRACE("Deleting high order patches\n");
2159 for(i = 0; i < PATCHMAP_SIZE; i++) {
2160 struct list *e1, *e2;
2161 struct WineD3DRectPatch *patch;
2162 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2163 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2164 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2168 /* Delete the mouse cursor texture */
2169 if(This->cursorTexture) {
2171 glDeleteTextures(1, &This->cursorTexture);
2173 This->cursorTexture = 0;
2176 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2177 * private data, it might contain opengl pointers
2179 if(This->depth_blt_texture) {
2181 glDeleteTextures(1, &This->depth_blt_texture);
2183 This->depth_blt_texture = 0;
2185 if (This->depth_blt_rb) {
2187 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2189 This->depth_blt_rb = 0;
2190 This->depth_blt_rb_w = 0;
2191 This->depth_blt_rb_h = 0;
2194 /* Release the update stateblock */
2195 if (wined3d_stateblock_decref(This->updateStateBlock))
2197 if (This->updateStateBlock != This->stateBlock)
2198 FIXME("Something's still holding the update stateblock.\n");
2200 This->updateStateBlock = NULL;
2203 struct wined3d_stateblock *stateblock = This->stateBlock;
2204 This->stateBlock = NULL;
2206 /* Release the stateblock */
2207 if (wined3d_stateblock_decref(stateblock))
2208 FIXME("Something's still holding the stateblock.\n");
2211 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2212 This->blitter->free_private(This);
2213 This->frag_pipe->free_private(This);
2214 This->shader_backend->shader_free_private(This);
2216 /* Release the buffers (with sanity checks)*/
2217 if (This->onscreen_depth_stencil)
2219 surface = This->onscreen_depth_stencil;
2220 This->onscreen_depth_stencil = NULL;
2221 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2224 if (This->depth_stencil)
2226 surface = This->depth_stencil;
2228 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2230 This->depth_stencil = NULL;
2231 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2232 && surface != This->auto_depth_stencil)
2234 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2238 if (This->auto_depth_stencil)
2240 surface = This->auto_depth_stencil;
2241 This->auto_depth_stencil = NULL;
2242 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2244 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2248 for (i = 1; i < gl_info->limits.buffers; ++i)
2250 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2253 surface = This->render_targets[0];
2254 TRACE("Setting rendertarget 0 to NULL\n");
2255 This->render_targets[0] = NULL;
2256 TRACE("Releasing the render target at %p\n", surface);
2257 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2259 context_release(context);
2261 for (i = 0; i < This->swapchain_count; ++i)
2263 TRACE("Releasing the implicit swapchain %u.\n", i);
2264 if (wined3d_swapchain_decref(This->swapchains[i]))
2265 FIXME("Something's still holding the implicit swapchain.\n");
2268 HeapFree(GetProcessHeap(), 0, This->swapchains);
2269 This->swapchains = NULL;
2270 This->swapchain_count = 0;
2272 for (i = 0; i < This->palette_count; ++i)
2273 HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2274 HeapFree(GetProcessHeap(), 0, This->palettes);
2275 This->palettes = NULL;
2276 This->palette_count = 0;
2278 HeapFree(GetProcessHeap(), 0, This->render_targets);
2279 This->render_targets = NULL;
2281 This->d3d_initialized = FALSE;
2286 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface)
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2291 for (i = 0; i < This->swapchain_count; ++i)
2293 TRACE("Releasing the implicit swapchain %u.\n", i);
2294 if (wined3d_swapchain_decref(This->swapchains[i]))
2295 FIXME("Something's still holding the implicit swapchain.\n");
2298 HeapFree(GetProcessHeap(), 0, This->swapchains);
2299 This->swapchains = NULL;
2300 This->swapchain_count = 0;
2304 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2305 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2306 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2308 * There is no way to deactivate thread safety once it is enabled.
2310 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2313 /*For now just store the flag(needed in case of ddraw) */
2314 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2318 const WINED3DDISPLAYMODE* pMode) {
2320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2321 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2325 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2327 /* Resize the screen even without a window:
2328 * The app could have unset it with SetCooperativeLevel, but not called
2329 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2330 * but we don't have any hwnd
2333 memset(&devmode, 0, sizeof(devmode));
2334 devmode.dmSize = sizeof(devmode);
2335 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2336 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2337 devmode.dmPelsWidth = pMode->Width;
2338 devmode.dmPelsHeight = pMode->Height;
2340 devmode.dmDisplayFrequency = pMode->RefreshRate;
2341 if (pMode->RefreshRate)
2342 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2344 /* Only change the mode if necessary */
2345 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2346 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2349 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2350 if (ret != DISP_CHANGE_SUCCESSFUL)
2352 if (devmode.dmDisplayFrequency)
2354 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2355 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2356 devmode.dmDisplayFrequency = 0;
2357 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2359 if(ret != DISP_CHANGE_SUCCESSFUL) {
2360 return WINED3DERR_NOTAVAILABLE;
2364 /* Store the new values */
2365 This->ddraw_width = pMode->Width;
2366 This->ddraw_height = pMode->Height;
2367 This->ddraw_format = pMode->Format;
2369 /* And finally clip mouse to our screen */
2370 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2371 ClipCursor(&clip_rc);
2376 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2378 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2380 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2382 *wined3d = device->wined3d;
2383 wined3d_incref(*wined3d);
2385 TRACE("Returning %p.\n", *wined3d);
2390 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2394 (This->adapter->TextureRam/(1024*1024)),
2395 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2396 /* return simulated texture memory left */
2397 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2400 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2401 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2404 struct wined3d_stream_state *stream;
2405 struct wined3d_buffer *prev_buffer;
2407 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2408 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2410 if (StreamNumber >= MAX_STREAMS) {
2411 WARN("Stream out of range %d\n", StreamNumber);
2412 return WINED3DERR_INVALIDCALL;
2413 } else if(OffsetInBytes & 0x3) {
2414 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2415 return WINED3DERR_INVALIDCALL;
2418 stream = &This->updateStateBlock->state.streams[StreamNumber];
2419 prev_buffer = stream->buffer;
2421 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2423 if (prev_buffer == buffer
2424 && stream->stride == Stride
2425 && stream->offset == OffsetInBytes)
2427 TRACE("Application is setting the old values over, nothing to do\n");
2431 stream->buffer = buffer;
2434 stream->stride = Stride;
2435 stream->offset = OffsetInBytes;
2438 /* Handle recording of state blocks */
2439 if (This->isRecordingState) {
2440 TRACE("Recording... not performing anything\n");
2442 wined3d_buffer_incref(buffer);
2444 wined3d_buffer_decref(prev_buffer);
2450 InterlockedIncrement(&buffer->bind_count);
2451 wined3d_buffer_incref(buffer);
2455 InterlockedDecrement(&prev_buffer->bind_count);
2456 wined3d_buffer_decref(prev_buffer);
2459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2464 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2465 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 struct wined3d_stream_state *stream;
2470 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2471 iface, StreamNumber, buffer, pOffset, pStride);
2473 if (StreamNumber >= MAX_STREAMS)
2475 WARN("Stream out of range %d\n", StreamNumber);
2476 return WINED3DERR_INVALIDCALL;
2479 stream = &This->stateBlock->state.streams[StreamNumber];
2480 *buffer = stream->buffer;
2481 *pStride = stream->stride;
2482 if (pOffset) *pOffset = stream->offset;
2485 wined3d_buffer_incref(*buffer);
2490 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 struct wined3d_stream_state *stream;
2493 UINT old_flags, oldFreq;
2495 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2497 /* Verify input at least in d3d9 this is invalid. */
2498 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2500 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2501 return WINED3DERR_INVALIDCALL;
2503 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2505 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2506 return WINED3DERR_INVALIDCALL;
2510 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2511 return WINED3DERR_INVALIDCALL;
2514 stream = &This->updateStateBlock->state.streams[StreamNumber];
2515 old_flags = stream->flags;
2516 oldFreq = stream->frequency;
2518 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2519 stream->frequency = Divider & 0x7FFFFF;
2521 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2523 if (stream->frequency != oldFreq || stream->flags != old_flags)
2524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2529 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 struct wined3d_stream_state *stream;
2533 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2535 stream = &This->updateStateBlock->state.streams[StreamNumber];
2536 *Divider = stream->flags | stream->frequency;
2538 TRACE("Returning %#x.\n", *Divider);
2544 * Get / Set & Multiply Transform
2546 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 /* Most of this routine, comments included copied from ddraw tree initially: */
2550 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2552 /* Handle recording of state blocks */
2553 if (This->isRecordingState) {
2554 TRACE("Recording... not performing anything\n");
2555 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2556 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2561 * If the new matrix is the same as the current one,
2562 * we cut off any further processing. this seems to be a reasonable
2563 * optimization because as was noticed, some apps (warcraft3 for example)
2564 * tend towards setting the same matrix repeatedly for some reason.
2566 * From here on we assume that the new matrix is different, wherever it matters.
2568 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2570 TRACE("The app is setting the same matrix over again\n");
2575 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2579 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2580 where ViewMat = Camera space, WorldMat = world space.
2582 In OpenGL, camera and world space is combined into GL_MODELVIEW
2583 matrix. The Projection matrix stay projection matrix.
2586 /* Capture the times we can just ignore the change for now */
2587 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2588 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2589 /* Handled by the state manager */
2592 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2599 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2600 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2602 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2604 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2606 *matrix = device->stateBlock->state.transforms[state];
2611 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2612 const WINED3DMATRIX *mat = NULL;
2615 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2616 * below means it will be recorded in a state block change, but it
2617 * works regardless where it is recorded.
2618 * If this is found to be wrong, change to StateBlock.
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2623 if (State <= HIGHEST_TRANSFORMSTATE)
2625 mat = &This->updateStateBlock->state.transforms[State];
2629 FIXME("Unhandled transform state!!\n");
2632 multiply_matrix(&temp, mat, pMatrix);
2634 /* Apply change via set transform - will reapply to eg. lights this way */
2635 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2641 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2642 you can reference any indexes you want as long as that number max are enabled at any
2643 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2644 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2645 but when recording, just build a chain pretty much of commands to be replayed. */
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2649 struct wined3d_light_info *object = NULL;
2650 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2654 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2656 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2660 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2661 return WINED3DERR_INVALIDCALL;
2664 switch(pLight->Type) {
2665 case WINED3DLIGHT_POINT:
2666 case WINED3DLIGHT_SPOT:
2667 case WINED3DLIGHT_PARALLELPOINT:
2668 case WINED3DLIGHT_GLSPOT:
2669 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2672 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2674 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2675 return WINED3DERR_INVALIDCALL;
2679 case WINED3DLIGHT_DIRECTIONAL:
2680 /* Ignores attenuation */
2684 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2685 return WINED3DERR_INVALIDCALL;
2688 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2690 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2691 if(object->OriginalIndex == Index) break;
2696 TRACE("Adding new light\n");
2697 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2699 ERR("Out of memory error when allocating a light\n");
2700 return E_OUTOFMEMORY;
2702 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2703 object->glIndex = -1;
2704 object->OriginalIndex = Index;
2707 /* Initialize the object */
2708 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,
2709 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2710 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2711 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2712 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2713 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2714 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2716 /* Save away the information */
2717 object->OriginalParms = *pLight;
2719 switch (pLight->Type) {
2720 case WINED3DLIGHT_POINT:
2722 object->lightPosn[0] = pLight->Position.x;
2723 object->lightPosn[1] = pLight->Position.y;
2724 object->lightPosn[2] = pLight->Position.z;
2725 object->lightPosn[3] = 1.0f;
2726 object->cutoff = 180.0f;
2730 case WINED3DLIGHT_DIRECTIONAL:
2732 object->lightPosn[0] = -pLight->Direction.x;
2733 object->lightPosn[1] = -pLight->Direction.y;
2734 object->lightPosn[2] = -pLight->Direction.z;
2735 object->lightPosn[3] = 0.0f;
2736 object->exponent = 0.0f;
2737 object->cutoff = 180.0f;
2740 case WINED3DLIGHT_SPOT:
2742 object->lightPosn[0] = pLight->Position.x;
2743 object->lightPosn[1] = pLight->Position.y;
2744 object->lightPosn[2] = pLight->Position.z;
2745 object->lightPosn[3] = 1.0f;
2748 object->lightDirn[0] = pLight->Direction.x;
2749 object->lightDirn[1] = pLight->Direction.y;
2750 object->lightDirn[2] = pLight->Direction.z;
2751 object->lightDirn[3] = 1.0f;
2754 * opengl-ish and d3d-ish spot lights use too different models for the
2755 * light "intensity" as a function of the angle towards the main light direction,
2756 * so we only can approximate very roughly.
2757 * however spot lights are rather rarely used in games (if ever used at all).
2758 * furthermore if still used, probably nobody pays attention to such details.
2760 if (!pLight->Falloff)
2762 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2763 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2764 * will always be 1.0 for both of them, and we don't have to care for the
2765 * rest of the rather complex calculation
2767 object->exponent = 0.0f;
2769 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2770 if (rho < 0.0001f) rho = 0.0001f;
2771 object->exponent = -0.3f/logf(cosf(rho/2));
2773 if (object->exponent > 128.0f)
2775 object->exponent = 128.0f;
2777 object->cutoff = (float) (pLight->Phi*90/M_PI);
2783 FIXME("Unrecognized light type %d\n", pLight->Type);
2786 /* Update the live definitions if the light is currently assigned a glIndex */
2787 if (object->glIndex != -1 && !This->isRecordingState) {
2788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2793 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2795 struct wined3d_light_info *lightInfo = NULL;
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2799 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2801 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2803 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2804 if(lightInfo->OriginalIndex == Index) break;
2810 TRACE("Light information requested but light not defined\n");
2811 return WINED3DERR_INVALIDCALL;
2814 *pLight = lightInfo->OriginalParms;
2819 * Get / Set Light Enable
2820 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2822 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2824 struct wined3d_light_info *lightInfo = NULL;
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2828 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2830 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2832 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2833 if(lightInfo->OriginalIndex == Index) break;
2836 TRACE("Found light: %p\n", lightInfo);
2838 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2841 TRACE("Light enabled requested but light not defined, so defining one!\n");
2842 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2844 /* Search for it again! Should be fairly quick as near head of list */
2845 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2847 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2848 if(lightInfo->OriginalIndex == Index) break;
2853 FIXME("Adding default lights has failed dismally\n");
2854 return WINED3DERR_INVALIDCALL;
2859 if(lightInfo->glIndex != -1) {
2860 if(!This->isRecordingState) {
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2864 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2865 lightInfo->glIndex = -1;
2867 TRACE("Light already disabled, nothing to do\n");
2869 lightInfo->enabled = FALSE;
2871 lightInfo->enabled = TRUE;
2872 if (lightInfo->glIndex != -1) {
2874 TRACE("Nothing to do as light was enabled\n");
2877 /* Find a free gl light */
2878 for (i = 0; i < This->maxConcurrentLights; ++i)
2880 if (!This->updateStateBlock->state.lights[i])
2882 This->updateStateBlock->state.lights[i] = lightInfo;
2883 lightInfo->glIndex = i;
2887 if(lightInfo->glIndex == -1) {
2888 /* Our tests show that Windows returns D3D_OK in this situation, even with
2889 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2890 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2891 * as well for those lights.
2893 * TODO: Test how this affects rendering
2895 WARN("Too many concurrently active lights\n");
2899 /* i == lightInfo->glIndex */
2900 if(!This->isRecordingState) {
2901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2909 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2911 struct wined3d_light_info *lightInfo = NULL;
2912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2915 TRACE("(%p) : for idx(%d)\n", This, Index);
2917 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2919 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2920 if(lightInfo->OriginalIndex == Index) break;
2926 TRACE("Light enabled state requested but light not defined\n");
2927 return WINED3DERR_INVALIDCALL;
2929 /* true is 128 according to SetLightEnable */
2930 *pEnable = lightInfo->enabled ? 128 : 0;
2935 * Get / Set Clip Planes
2937 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2941 /* Validate Index */
2942 if (Index >= This->adapter->gl_info.limits.clipplanes)
2944 TRACE("Application has requested clipplane this device doesn't support\n");
2945 return WINED3DERR_INVALIDCALL;
2948 This->updateStateBlock->changed.clipplane |= 1 << Index;
2950 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2951 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2952 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2953 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2955 TRACE("Application is setting old values over, nothing to do\n");
2959 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2960 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2961 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2962 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2964 /* Handle recording of state blocks */
2965 if (This->isRecordingState) {
2966 TRACE("Recording... not performing anything\n");
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2975 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 TRACE("(%p) : for idx %d\n", This, Index);
2979 /* Validate Index */
2980 if (Index >= This->adapter->gl_info.limits.clipplanes)
2982 TRACE("Application has requested clipplane this device doesn't support\n");
2983 return WINED3DERR_INVALIDCALL;
2986 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2987 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2988 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2989 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2994 * Get / Set Clip Plane Status
2995 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2997 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 FIXME("(%p) : stub\n", This);
3002 return WINED3DERR_INVALIDCALL;
3004 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
3005 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3009 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 FIXME("(%p) : stub\n", This);
3014 return WINED3DERR_INVALIDCALL;
3016 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3017 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3022 * Get / Set Material
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 This->updateStateBlock->changed.material = TRUE;
3028 This->updateStateBlock->state.material = *pMaterial;
3030 /* Handle recording of state blocks */
3031 if (This->isRecordingState) {
3032 TRACE("Recording... not performing anything\n");
3036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 *pMaterial = This->updateStateBlock->state.material;
3043 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3044 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3045 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3046 pMaterial->Ambient.b, pMaterial->Ambient.a);
3047 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3048 pMaterial->Specular.b, pMaterial->Specular.a);
3049 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3050 pMaterial->Emissive.b, pMaterial->Emissive.a);
3051 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3059 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3060 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 struct wined3d_buffer *prev_buffer;
3065 TRACE("iface %p, buffer %p, format %s.\n",
3066 iface, buffer, debug_d3dformat(fmt));
3068 prev_buffer = This->updateStateBlock->state.index_buffer;
3070 This->updateStateBlock->changed.indices = TRUE;
3071 This->updateStateBlock->state.index_buffer = buffer;
3072 This->updateStateBlock->state.index_format = fmt;
3074 /* Handle recording of state blocks */
3075 if (This->isRecordingState) {
3076 TRACE("Recording... not performing anything\n");
3078 wined3d_buffer_incref(buffer);
3080 wined3d_buffer_decref(prev_buffer);
3084 if (prev_buffer != buffer)
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3089 InterlockedIncrement(&buffer->bind_count);
3090 wined3d_buffer_incref(buffer);
3094 InterlockedDecrement(&prev_buffer->bind_count);
3095 wined3d_buffer_decref(prev_buffer);
3102 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 TRACE("iface %p, buffer %p.\n", iface, buffer);
3108 *buffer = This->stateBlock->state.index_buffer;
3111 wined3d_buffer_incref(*buffer);
3113 TRACE("Returning %p.\n", *buffer);
3118 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3119 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 TRACE("(%p)->(%d)\n", This, BaseIndex);
3123 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3125 TRACE("Application is setting the old value over, nothing to do\n");
3129 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3131 if (This->isRecordingState) {
3132 TRACE("Recording... not performing anything\n");
3135 /* The base vertex index affects the stream sources */
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3140 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 TRACE("(%p) : base_index %p\n", This, base_index);
3144 *base_index = This->stateBlock->state.base_vertex_index;
3146 TRACE("Returning %u\n", *base_index);
3152 * Get / Set Viewports
3154 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 TRACE("(%p)\n", This);
3158 This->updateStateBlock->changed.viewport = TRUE;
3159 This->updateStateBlock->state.viewport = *pViewport;
3161 /* Handle recording of state blocks */
3162 if (This->isRecordingState) {
3163 TRACE("Recording... not performing anything\n");
3167 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3168 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 TRACE("(%p)\n", This);
3178 *pViewport = This->stateBlock->state.viewport;
3182 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3183 WINED3DRENDERSTATETYPE State, DWORD Value)
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 DWORD oldValue = This->stateBlock->state.render_states[State];
3188 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3190 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3191 This->updateStateBlock->state.render_states[State] = Value;
3193 /* Handle recording of state blocks */
3194 if (This->isRecordingState) {
3195 TRACE("Recording... not performing anything\n");
3199 /* Compared here and not before the assignment to allow proper stateblock recording */
3200 if(Value == oldValue) {
3201 TRACE("Application is setting the old value over, nothing to do\n");
3203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3209 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3210 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3216 *pValue = This->stateBlock->state.render_states[State];
3221 * Get / Set Sampler States
3222 * TODO: Verify against dx9 definitions
3225 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3230 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3232 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3233 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3236 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3238 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3239 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3242 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3243 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3244 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3246 /* Handle recording of state blocks */
3247 if (This->isRecordingState) {
3248 TRACE("Recording... not performing anything\n");
3252 if(oldValue == Value) {
3253 TRACE("Application is setting the old value over, nothing to do\n");
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3262 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3266 This, Sampler, debug_d3dsamplerstate(Type), Type);
3268 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3269 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3272 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3274 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3275 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3277 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3278 TRACE("(%p) : Returning %#x\n", This, *Value);
3283 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 This->updateStateBlock->changed.scissorRect = TRUE;
3287 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3289 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3292 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3294 if(This->isRecordingState) {
3295 TRACE("Recording... not performing anything\n");
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 *pRect = This->updateStateBlock->state.scissor_rect;
3308 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3313 struct wined3d_vertex_declaration *pDecl)
3315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3316 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3318 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3321 wined3d_vertex_declaration_incref(pDecl);
3323 wined3d_vertex_declaration_decref(oldDecl);
3325 This->updateStateBlock->state.vertex_declaration = pDecl;
3326 This->updateStateBlock->changed.vertexDecl = TRUE;
3328 if (This->isRecordingState) {
3329 TRACE("Recording... not performing anything\n");
3331 } else if(pDecl == oldDecl) {
3332 /* Checked after the assignment to allow proper stateblock recording */
3333 TRACE("Application is setting the old declaration over, nothing to do\n");
3337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3341 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3342 struct wined3d_vertex_declaration **ppDecl)
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3348 *ppDecl = This->stateBlock->state.vertex_declaration;
3350 wined3d_vertex_declaration_incref(*ppDecl);
3355 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3357 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3358 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
3360 device->updateStateBlock->state.vertex_shader = shader;
3361 device->updateStateBlock->changed.vertexShader = TRUE;
3363 if (device->isRecordingState)
3366 wined3d_shader_incref(shader);
3368 wined3d_shader_decref(prev);
3369 TRACE("Recording... not performing anything.\n");
3372 else if(prev == shader)
3374 /* Checked here to allow proper stateblock recording */
3375 TRACE("App is setting the old shader over, nothing to do.\n");
3379 TRACE("(%p) : setting shader(%p)\n", device, shader);
3381 wined3d_shader_incref(shader);
3383 wined3d_shader_decref(prev);
3385 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
3390 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3392 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3393 struct wined3d_shader *shader;
3395 TRACE("iface %p.\n", iface);
3397 shader = device->stateBlock->state.vertex_shader;
3399 wined3d_shader_incref(shader);
3401 TRACE("Returning %p.\n", shader);
3405 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3406 IWineD3DDevice *iface,
3408 CONST BOOL *srcData,
3411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3412 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3414 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3415 iface, srcData, start, count);
3417 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3419 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3420 for (i = 0; i < cnt; i++)
3421 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3423 for (i = start; i < cnt + start; ++i) {
3424 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3427 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3432 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3433 IWineD3DDevice *iface,
3438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3439 int cnt = min(count, MAX_CONST_B - start);
3441 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3442 iface, dstData, start, count);
3444 if (!dstData || cnt < 0)
3445 return WINED3DERR_INVALIDCALL;
3447 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3451 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3452 IWineD3DDevice *iface,
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3460 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3461 iface, srcData, start, count);
3463 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3465 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3466 for (i = 0; i < cnt; i++)
3467 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3468 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3470 for (i = start; i < cnt + start; ++i) {
3471 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3474 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3479 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3480 IWineD3DDevice *iface,
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 int cnt = min(count, MAX_CONST_I - start);
3488 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3489 iface, dstData, start, count);
3491 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3492 return WINED3DERR_INVALIDCALL;
3494 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3499 IWineD3DDevice *iface,
3501 CONST float *srcData,
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3511 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3512 return WINED3DERR_INVALIDCALL;
3514 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3516 for (i = 0; i < count; i++)
3517 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3518 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3521 if (!This->isRecordingState)
3523 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3527 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3528 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3533 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3534 IWineD3DDevice *iface,
3539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 int cnt = min(count, This->d3d_vshader_constantF - start);
3542 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3543 iface, dstData, start, count);
3545 if (!dstData || cnt < 0)
3546 return WINED3DERR_INVALIDCALL;
3548 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3552 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3554 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3560 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3562 DWORD i = This->rev_tex_unit_map[unit];
3563 DWORD j = This->texUnitMap[stage];
3565 This->texUnitMap[stage] = unit;
3566 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3568 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3571 This->rev_tex_unit_map[unit] = stage;
3572 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3574 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3578 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3581 This->fixed_function_usage_map = 0;
3582 for (i = 0; i < MAX_TEXTURES; ++i)
3584 const struct wined3d_state *state = &This->stateBlock->state;
3585 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3586 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3587 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3588 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3589 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3590 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3591 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3592 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3594 if (color_op == WINED3DTOP_DISABLE) {
3595 /* Not used, and disable higher stages */
3599 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3600 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3601 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3602 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3603 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3604 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3605 This->fixed_function_usage_map |= (1 << i);
3608 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3609 This->fixed_function_usage_map |= (1 << (i + 1));
3614 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3616 unsigned int i, tex;
3619 device_update_fixed_function_usage_map(This);
3620 ffu_map = This->fixed_function_usage_map;
3622 if (This->max_ffp_textures == gl_info->limits.texture_stages
3623 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3625 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3627 if (!(ffu_map & 1)) continue;
3629 if (This->texUnitMap[i] != i) {
3630 device_map_stage(This, i, i);
3631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3632 markTextureStagesDirty(This, i);
3638 /* Now work out the mapping */
3640 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3642 if (!(ffu_map & 1)) continue;
3644 if (This->texUnitMap[i] != tex) {
3645 device_map_stage(This, i, tex);
3646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3647 markTextureStagesDirty(This, i);
3654 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3656 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3657 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3660 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3661 if (sampler_type[i] && This->texUnitMap[i] != i)
3663 device_map_stage(This, i, i);
3664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3665 if (i < gl_info->limits.texture_stages)
3667 markTextureStagesDirty(This, i);
3673 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3674 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3676 DWORD current_mapping = This->rev_tex_unit_map[unit];
3678 /* Not currently used */
3679 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3681 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3682 /* Used by a fragment sampler */
3684 if (!pshader_sampler_tokens) {
3685 /* No pixel shader, check fixed function */
3686 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3689 /* Pixel shader, check the shader's sampler map */
3690 return !pshader_sampler_tokens[current_mapping];
3693 /* Used by a vertex sampler */
3694 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3697 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3699 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3700 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3701 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3702 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3707 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3708 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3709 pshader_sampler_type = This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3712 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3713 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3714 if (vshader_sampler_type[i])
3716 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3718 /* Already mapped somewhere */
3722 while (start >= 0) {
3723 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3725 device_map_stage(This, vsampler_idx, start);
3726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3738 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3740 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3741 const struct wined3d_state *state = &This->stateBlock->state;
3742 BOOL vs = use_vs(state);
3743 BOOL ps = use_ps(state);
3746 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3747 * that would be really messy and require shader recompilation
3748 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3749 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3751 if (ps) device_map_psamplers(This, gl_info);
3752 else device_map_fixed_function_samplers(This, gl_info);
3754 if (vs) device_map_vsamplers(This, ps, gl_info);
3757 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3759 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3760 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
3762 device->updateStateBlock->state.pixel_shader = shader;
3763 device->updateStateBlock->changed.pixelShader = TRUE;
3765 /* Handle recording of state blocks */
3766 if (device->isRecordingState)
3767 TRACE("Recording... not performing anything\n");
3769 if (device->isRecordingState)
3771 TRACE("Recording... not performing anything.\n");
3773 wined3d_shader_incref(shader);
3775 wined3d_shader_decref(prev);
3781 TRACE("App is setting the old pixel shader over, nothing to do.\n");
3786 wined3d_shader_incref(shader);
3788 wined3d_shader_decref(prev);
3790 TRACE("Setting shader %p.\n", shader);
3791 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3796 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3798 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3799 struct wined3d_shader *shader;
3801 TRACE("iface %p.\n", iface);
3803 shader = device->stateBlock->state.pixel_shader;
3805 wined3d_shader_incref(shader);
3807 TRACE("Returning %p.\n", shader);
3811 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3812 IWineD3DDevice *iface,
3814 CONST BOOL *srcData,
3817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3818 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3820 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3821 iface, srcData, start, count);
3823 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3825 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3826 for (i = 0; i < cnt; i++)
3827 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3829 for (i = start; i < cnt + start; ++i) {
3830 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3833 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3838 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3839 IWineD3DDevice *iface,
3844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3845 int cnt = min(count, MAX_CONST_B - start);
3847 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3848 iface, dstData, start, count);
3850 if (!dstData || cnt < 0)
3851 return WINED3DERR_INVALIDCALL;
3853 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3857 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3858 IWineD3DDevice *iface,
3863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3864 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3866 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3867 iface, srcData, start, count);
3869 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3871 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3872 for (i = 0; i < cnt; i++)
3873 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3874 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3876 for (i = start; i < cnt + start; ++i) {
3877 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3880 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3885 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3886 IWineD3DDevice *iface,
3891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3892 int cnt = min(count, MAX_CONST_I - start);
3894 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3895 iface, dstData, start, count);
3897 if (!dstData || cnt < 0)
3898 return WINED3DERR_INVALIDCALL;
3900 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3904 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3905 IWineD3DDevice *iface,
3907 CONST float *srcData,
3910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3914 iface, srcData, start, count);
3916 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3917 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3918 return WINED3DERR_INVALIDCALL;
3920 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3922 for (i = 0; i < count; i++)
3923 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3924 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3927 if (!This->isRecordingState)
3929 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3933 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3934 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3939 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3940 IWineD3DDevice *iface,
3945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3946 int cnt = min(count, This->d3d_pshader_constantF - start);
3948 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3949 iface, dstData, start, count);
3951 if (!dstData || cnt < 0)
3952 return WINED3DERR_INVALIDCALL;
3954 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3958 /* Context activation is done by the caller. */
3959 /* Do not call while under the GL lock. */
3960 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3961 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3962 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3965 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3966 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3969 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3973 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3975 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3978 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3980 ERR("Source has no position mask\n");
3981 return WINED3DERR_INVALIDCALL;
3984 if (!dest->resource.allocatedMemory)
3985 buffer_get_sysmem(dest, gl_info);
3987 /* Get a pointer into the destination vbo(create one if none exists) and
3988 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3990 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3992 dest->flags |= WINED3D_BUFFER_CREATEBO;
3993 wined3d_buffer_preload(dest);
3996 if (dest->buffer_object)
3998 unsigned char extrabytes = 0;
3999 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4000 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4001 * this may write 4 extra bytes beyond the area that should be written
4003 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4004 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4005 if(!dest_conv_addr) {
4006 ERR("Out of memory\n");
4007 /* Continue without storing converted vertices */
4009 dest_conv = dest_conv_addr;
4012 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
4014 static BOOL warned = FALSE;
4016 * The clipping code is not quite correct. Some things need
4017 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4018 * so disable clipping for now.
4019 * (The graphics in Half-Life are broken, and my processvertices
4020 * test crashes with IDirect3DDevice3)
4026 FIXME("Clipping is broken and disabled for now\n");
4028 } else doClip = FALSE;
4029 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4031 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4034 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4035 WINED3DTS_PROJECTION,
4037 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4038 WINED3DTS_WORLDMATRIX(0),
4041 TRACE("View mat:\n");
4042 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);
4043 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);
4044 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);
4045 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);
4047 TRACE("Proj mat:\n");
4048 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);
4049 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);
4050 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);
4051 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);
4053 TRACE("World mat:\n");
4054 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);
4055 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);
4056 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);
4057 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);
4059 /* Get the viewport */
4060 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4061 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4062 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4064 multiply_matrix(&mat,&view_mat,&world_mat);
4065 multiply_matrix(&mat,&proj_mat,&mat);
4067 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4069 for (i = 0; i < dwCount; i+= 1) {
4070 unsigned int tex_index;
4072 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4073 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4074 /* The position first */
4075 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4076 const float *p = (const float *)(element->data + i * element->stride);
4078 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4080 /* Multiplication with world, view and projection matrix */
4081 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);
4082 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);
4083 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);
4084 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);
4086 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4088 /* WARNING: The following things are taken from d3d7 and were not yet checked
4089 * against d3d8 or d3d9!
4092 /* Clipping conditions: From msdn
4094 * A vertex is clipped if it does not match the following requirements
4098 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4100 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4101 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4106 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4107 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4110 /* "Normal" viewport transformation (not clipped)
4111 * 1) The values are divided by rhw
4112 * 2) The y axis is negative, so multiply it with -1
4113 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4114 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4115 * 4) Multiply x with Width/2 and add Width/2
4116 * 5) The same for the height
4117 * 6) Add the viewpoint X and Y to the 2D coordinates and
4118 * The minimum Z value to z
4119 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4121 * Well, basically it's simply a linear transformation into viewport
4133 z *= vp.MaxZ - vp.MinZ;
4135 x += vp.Width / 2 + vp.X;
4136 y += vp.Height / 2 + vp.Y;
4141 /* That vertex got clipped
4142 * Contrary to OpenGL it is not dropped completely, it just
4143 * undergoes a different calculation.
4145 TRACE("Vertex got clipped\n");
4152 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4153 * outside of the main vertex buffer memory. That needs some more
4158 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4161 ( (float *) dest_ptr)[0] = x;
4162 ( (float *) dest_ptr)[1] = y;
4163 ( (float *) dest_ptr)[2] = z;
4164 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4166 dest_ptr += 3 * sizeof(float);
4168 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4169 dest_ptr += sizeof(float);
4174 ( (float *) dest_conv)[0] = x * w;
4175 ( (float *) dest_conv)[1] = y * w;
4176 ( (float *) dest_conv)[2] = z * w;
4177 ( (float *) dest_conv)[3] = w;
4179 dest_conv += 3 * sizeof(float);
4181 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4182 dest_conv += sizeof(float);
4186 if (DestFVF & WINED3DFVF_PSIZE) {
4187 dest_ptr += sizeof(DWORD);
4188 if(dest_conv) dest_conv += sizeof(DWORD);
4190 if (DestFVF & WINED3DFVF_NORMAL) {
4191 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4192 const float *normal = (const float *)(element->data + i * element->stride);
4193 /* AFAIK this should go into the lighting information */
4194 FIXME("Didn't expect the destination to have a normal\n");
4195 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4197 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4201 if (DestFVF & WINED3DFVF_DIFFUSE) {
4202 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4203 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4204 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4206 static BOOL warned = FALSE;
4209 ERR("No diffuse color in source, but destination has one\n");
4213 *( (DWORD *) dest_ptr) = 0xffffffff;
4214 dest_ptr += sizeof(DWORD);
4217 *( (DWORD *) dest_conv) = 0xffffffff;
4218 dest_conv += sizeof(DWORD);
4222 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4224 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4225 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4226 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4227 dest_conv += sizeof(DWORD);
4232 if (DestFVF & WINED3DFVF_SPECULAR)
4234 /* What's the color value in the feedback buffer? */
4235 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4236 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4237 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4239 static BOOL warned = FALSE;
4242 ERR("No specular color in source, but destination has one\n");
4246 *( (DWORD *) dest_ptr) = 0xFF000000;
4247 dest_ptr += sizeof(DWORD);
4250 *( (DWORD *) dest_conv) = 0xFF000000;
4251 dest_conv += sizeof(DWORD);
4255 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4257 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4258 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4259 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4260 dest_conv += sizeof(DWORD);
4265 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4266 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4267 const float *tex_coord = (const float *)(element->data + i * element->stride);
4268 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4270 ERR("No source texture, but destination requests one\n");
4271 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4272 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4275 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4277 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4287 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4288 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4289 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4290 dwCount * get_flexible_vertex_size(DestFVF),
4292 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4296 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4301 #undef copy_and_next
4303 /* Do not call while under the GL lock. */
4304 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4305 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4306 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4309 struct wined3d_stream_info stream_info;
4310 const struct wined3d_gl_info *gl_info;
4311 struct wined3d_context *context;
4312 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4315 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4318 ERR("Output vertex declaration not implemented yet\n");
4321 /* Need any context to write to the vbo. */
4322 context = context_acquire(This, NULL);
4323 gl_info = context->gl_info;
4325 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4326 * control the streamIsUP flag, thus restore it afterwards.
4328 This->stateBlock->state.user_stream = FALSE;
4329 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4330 This->stateBlock->state.user_stream = streamWasUP;
4332 if(vbo || SrcStartIndex) {
4334 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4335 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4337 * Also get the start index in, but only loop over all elements if there's something to add at all.
4339 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4341 struct wined3d_stream_info_element *e;
4343 if (!(stream_info.use_map & (1 << i))) continue;
4345 e = &stream_info.elements[i];
4346 if (e->buffer_object)
4348 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4349 e->buffer_object = 0;
4350 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4352 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4353 vb->buffer_object = 0;
4356 if (e->data) e->data += e->stride * SrcStartIndex;
4360 hr = process_vertices_strided(This, DestIndex, VertexCount,
4361 &stream_info, dst_buffer, flags, DestFVF);
4363 context_release(context);
4369 * Get / Set Texture Stage States
4370 * TODO: Verify against dx9 definitions
4372 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4375 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4378 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4380 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4382 WARN("Invalid Type %d passed.\n", Type);
4386 if (Stage >= gl_info->limits.texture_stages)
4388 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4389 Stage, gl_info->limits.texture_stages - 1);
4393 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4394 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4395 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4397 if (This->isRecordingState) {
4398 TRACE("Recording... not performing anything\n");
4402 /* Checked after the assignments to allow proper stateblock recording */
4403 if(oldValue == Value) {
4404 TRACE("App is setting the old value over, nothing to do\n");
4408 if (Stage > This->stateBlock->state.lowest_disabled_stage
4409 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4410 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4412 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4413 * Changes in other states are important on disabled stages too
4418 if(Type == WINED3DTSS_COLOROP) {
4421 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4422 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4423 * they have to be disabled
4425 * The current stage is dirtified below.
4427 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4429 TRACE("Additionally dirtifying stage %u\n", i);
4430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4432 This->stateBlock->state.lowest_disabled_stage = Stage;
4433 TRACE("New lowest disabled: %u\n", Stage);
4434 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4435 /* Previously disabled stage enabled. Stages above it may need enabling
4436 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4437 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4439 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4442 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4444 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4446 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4449 This->stateBlock->state.lowest_disabled_stage = i;
4450 TRACE("New lowest disabled: %u\n", i);
4454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4459 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4463 TRACE("iface %p, stage %u, state %s, value %p.\n",
4464 iface, Stage, debug_d3dtexturestate(Type), pValue);
4466 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4468 WARN("Invalid Type %d passed.\n", Type);
4472 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4473 TRACE("Returning %#x.\n", *pValue);
4478 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4479 DWORD stage, struct wined3d_texture *texture)
4481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4482 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4483 struct wined3d_texture *prev;
4485 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4487 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4488 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4490 /* Windows accepts overflowing this array... we do not. */
4491 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4493 WARN("Ignoring invalid stage %u.\n", stage);
4497 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4498 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4500 WARN("Rejecting attempt to set scratch texture.\n");
4501 return WINED3DERR_INVALIDCALL;
4504 This->updateStateBlock->changed.textures |= 1 << stage;
4506 prev = This->updateStateBlock->state.textures[stage];
4507 TRACE("Previous texture %p.\n", prev);
4509 if (texture == prev)
4511 TRACE("App is setting the same texture again, nothing to do.\n");
4515 TRACE("Setting new texture to %p.\n", texture);
4516 This->updateStateBlock->state.textures[stage] = texture;
4518 if (This->isRecordingState)
4520 TRACE("Recording... not performing anything\n");
4522 if (texture) wined3d_texture_incref(texture);
4523 if (prev) wined3d_texture_decref(prev);
4530 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4532 wined3d_texture_incref(texture);
4534 if (!prev || texture->target != prev->target)
4535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4537 if (!prev && stage < gl_info->limits.texture_stages)
4539 /* The source arguments for color and alpha ops have different
4540 * meanings when a NULL texture is bound, so the COLOROP and
4541 * ALPHAOP have to be dirtified. */
4542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4546 if (bind_count == 1)
4547 texture->sampler = stage;
4552 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4554 wined3d_texture_decref(prev);
4556 if (!texture && stage < gl_info->limits.texture_stages)
4558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4562 if (bind_count && prev->sampler == stage)
4566 /* Search for other stages the texture is bound to. Shouldn't
4567 * happen if applications bind textures to a single stage only. */
4568 TRACE("Searching for other stages the texture is bound to.\n");
4569 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4571 if (This->updateStateBlock->state.textures[i] == prev)
4573 TRACE("Texture is also bound to stage %u.\n", i);
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4586 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4587 DWORD stage, struct wined3d_texture **texture)
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4591 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4593 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4594 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4596 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4598 WARN("Current stage overflows textures array (stage %u).\n", stage);
4599 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4602 *texture = This->stateBlock->state.textures[stage];
4604 wined3d_texture_incref(*texture);
4606 TRACE("Returning %p.\n", *texture);
4614 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4615 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4617 struct wined3d_swapchain *swapchain;
4620 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4621 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4623 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4626 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4630 hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4631 wined3d_swapchain_decref(swapchain);
4634 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4641 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4643 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4645 TRACE("iface %p, caps %p.\n", iface, caps);
4647 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4650 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface,
4651 UINT swapchain_idx, WINED3DDISPLAYMODE *mode)
4653 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4654 struct wined3d_swapchain *swapchain;
4657 TRACE("iface %p, swapchain_idx %u, mode %p.\n", iface, swapchain_idx, mode);
4661 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4664 hr = wined3d_swapchain_get_display_mode(swapchain, mode);
4665 wined3d_swapchain_decref(swapchain);
4670 /* Don't read the real display mode, but return the stored mode
4671 * instead. X11 can't change the color depth, and some apps are
4672 * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out
4673 * that GetDisplayMode still returns 24 bpp.
4675 * Also don't relay to the swapchain because with ddraw it's possible
4676 * that there isn't a swapchain at all. */
4677 mode->Width = device->ddraw_width;
4678 mode->Height = device->ddraw_height;
4679 mode->Format = device->ddraw_format;
4680 mode->RefreshRate = 0;
4688 * Stateblock related functions
4691 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4694 struct wined3d_stateblock *stateblock;
4697 TRACE("(%p)\n", This);
4699 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4701 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4702 if (FAILED(hr)) return hr;
4704 wined3d_stateblock_decref(This->updateStateBlock);
4705 This->updateStateBlock = stateblock;
4706 This->isRecordingState = TRUE;
4708 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4713 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4714 struct wined3d_stateblock **stateblock)
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 struct wined3d_stateblock *object = This->updateStateBlock;
4719 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4721 if (!This->isRecordingState) {
4722 WARN("(%p) not recording! returning error\n", This);
4724 return WINED3DERR_INVALIDCALL;
4727 stateblock_init_contained_states(object);
4729 *stateblock = object;
4730 This->isRecordingState = FALSE;
4731 This->updateStateBlock = This->stateBlock;
4732 wined3d_stateblock_incref(This->updateStateBlock);
4734 TRACE("Returning stateblock %p.\n", *stateblock);
4740 * Scene related functions
4742 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4743 /* At the moment we have no need for any functionality at the beginning
4745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4746 TRACE("(%p)\n", This);
4749 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4750 return WINED3DERR_INVALIDCALL;
4752 This->inScene = TRUE;
4756 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759 struct wined3d_context *context;
4761 TRACE("(%p)\n", This);
4763 if(!This->inScene) {
4764 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4765 return WINED3DERR_INVALIDCALL;
4768 context = context_acquire(This, NULL);
4769 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4771 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4773 context_release(context);
4775 This->inScene = FALSE;
4779 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface, const RECT *src_rect,
4780 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
4782 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4785 TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
4786 iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
4787 dst_window_override, dirty_region);
4789 for (i = 0; i < device->swapchain_count; ++i)
4791 wined3d_swapchain_present(device->swapchains[i], src_rect,
4792 dst_rect, dst_window_override, dirty_region, 0);
4798 /* Do not call while under the GL lock. */
4799 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4800 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4802 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4803 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4806 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4807 iface, rect_count, rects, flags, color, depth, stencil);
4809 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4811 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4814 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4815 /* TODO: What about depth stencil buffers without stencil bits? */
4816 return WINED3DERR_INVALIDCALL;
4818 else if (flags & WINED3DCLEAR_TARGET)
4820 if(ds->resource.width < device->render_targets[0]->resource.width ||
4821 ds->resource.height < device->render_targets[0]->resource.height)
4823 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4829 device_get_draw_rect(device, &draw_rect);
4831 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4832 device->render_targets, device->depth_stencil, rect_count, rects,
4833 &draw_rect, flags, &c, depth, stencil);
4840 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4841 WINED3DPRIMITIVETYPE primitive_type)
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4845 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4847 This->updateStateBlock->changed.primitive_type = TRUE;
4848 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4851 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4852 WINED3DPRIMITIVETYPE *primitive_type)
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4858 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4860 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4863 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4869 if (!This->stateBlock->state.vertex_declaration)
4871 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4872 return WINED3DERR_INVALIDCALL;
4875 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4876 if (This->stateBlock->state.user_stream)
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4879 This->stateBlock->state.user_stream = FALSE;
4882 if (This->stateBlock->state.load_base_vertex_index)
4884 This->stateBlock->state.load_base_vertex_index = 0;
4885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4887 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4888 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4892 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 struct wined3d_buffer *index_buffer;
4899 index_buffer = This->stateBlock->state.index_buffer;
4902 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4903 * without an index buffer set. (The first time at least...)
4904 * D3D8 simply dies, but I doubt it can do much harm to return
4905 * D3DERR_INVALIDCALL there as well. */
4906 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4907 return WINED3DERR_INVALIDCALL;
4910 if (!This->stateBlock->state.vertex_declaration)
4912 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4913 return WINED3DERR_INVALIDCALL;
4916 if (This->stateBlock->state.user_stream)
4918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4919 This->stateBlock->state.user_stream = FALSE;
4921 vbo = index_buffer->buffer_object;
4923 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4925 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4930 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4932 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4936 drawPrimitive(This, index_count, startIndex, idxStride,
4937 vbo ? NULL : index_buffer->resource.allocatedMemory);
4942 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4943 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 struct wined3d_stream_state *stream;
4947 struct wined3d_buffer *vb;
4949 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4950 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4952 if (!This->stateBlock->state.vertex_declaration)
4954 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4955 return WINED3DERR_INVALIDCALL;
4958 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4959 stream = &This->stateBlock->state.streams[0];
4960 vb = stream->buffer;
4961 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4963 wined3d_buffer_decref(vb);
4965 stream->stride = VertexStreamZeroStride;
4966 This->stateBlock->state.user_stream = TRUE;
4967 This->stateBlock->state.load_base_vertex_index = 0;
4969 /* TODO: Only mark dirty if drawing from a different UP address */
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4972 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4974 /* MSDN specifies stream zero settings must be set to NULL */
4975 stream->buffer = NULL;
4978 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4979 * the new stream sources or use UP drawing again
4984 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4985 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4986 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4990 struct wined3d_stream_state *stream;
4991 struct wined3d_buffer *vb, *ib;
4993 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4994 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4996 if (!This->stateBlock->state.vertex_declaration)
4998 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4999 return WINED3DERR_INVALIDCALL;
5002 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5008 stream = &This->stateBlock->state.streams[0];
5009 vb = stream->buffer;
5010 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
5012 wined3d_buffer_decref(vb);
5014 stream->stride = VertexStreamZeroStride;
5015 This->stateBlock->state.user_stream = TRUE;
5017 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5018 This->stateBlock->state.base_vertex_index = 0;
5019 This->stateBlock->state.load_base_vertex_index = 0;
5020 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5024 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
5026 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5027 stream->buffer = NULL;
5029 ib = This->stateBlock->state.index_buffer;
5032 wined3d_buffer_decref(ib);
5033 This->stateBlock->state.index_buffer = NULL;
5035 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5036 * SetStreamSource to specify a vertex buffer
5042 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5043 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5047 /* Mark the state dirty until we have nicer tracking
5048 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5053 This->stateBlock->state.base_vertex_index = 0;
5054 This->up_strided = DrawPrimStrideData;
5055 drawPrimitive(This, vertex_count, 0, 0, NULL);
5056 This->up_strided = NULL;
5060 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5061 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5062 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5065 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5067 /* Mark the state dirty until we have nicer tracking
5068 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5073 This->stateBlock->state.user_stream = TRUE;
5074 This->stateBlock->state.base_vertex_index = 0;
5075 This->up_strided = DrawPrimStrideData;
5076 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5077 This->up_strided = NULL;
5081 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5082 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5083 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
5085 WINED3DLOCKED_BOX src;
5086 WINED3DLOCKED_BOX dst;
5089 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5090 iface, src_volume, dst_volume);
5092 /* TODO: Implement direct loading into the gl volume instead of using
5093 * memcpy and dirtification to improve loading performance. */
5094 hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY);
5095 if (FAILED(hr)) return hr;
5096 hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD);
5099 wined3d_volume_unmap(src_volume);
5103 memcpy(dst.pBits, src.pBits, dst_volume->resource.size);
5105 hr = wined3d_volume_unmap(dst_volume);
5107 wined3d_volume_unmap(src_volume);
5109 hr = wined3d_volume_unmap(src_volume);
5114 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5115 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5117 unsigned int level_count, i;
5118 WINED3DRESOURCETYPE type;
5121 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5123 /* Verify that the source and destination textures are non-NULL. */
5124 if (!src_texture || !dst_texture)
5126 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5127 return WINED3DERR_INVALIDCALL;
5130 if (src_texture == dst_texture)
5132 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5133 return WINED3DERR_INVALIDCALL;
5136 /* Verify that the source and destination textures are the same type. */
5137 type = wined3d_texture_get_type(src_texture);
5138 if (wined3d_texture_get_type(dst_texture) != type)
5140 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5141 return WINED3DERR_INVALIDCALL;
5144 /* Check that both textures have the identical numbers of levels. */
5145 level_count = wined3d_texture_get_level_count(src_texture);
5146 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5148 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5149 return WINED3DERR_INVALIDCALL;
5152 /* Make sure that the destination texture is loaded. */
5153 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5155 /* Update every surface level of the texture. */
5158 case WINED3DRTYPE_TEXTURE:
5160 IWineD3DSurface *src_surface;
5161 IWineD3DSurface *dst_surface;
5163 for (i = 0; i < level_count; ++i)
5165 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5167 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5169 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5172 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5179 case WINED3DRTYPE_CUBETEXTURE:
5181 IWineD3DSurface *src_surface;
5182 IWineD3DSurface *dst_surface;
5184 for (i = 0; i < level_count * 6; ++i)
5186 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5188 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5190 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5193 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5200 case WINED3DRTYPE_VOLUMETEXTURE:
5202 for (i = 0; i < level_count; ++i)
5204 hr = IWineD3DDeviceImpl_UpdateVolume(iface,
5205 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
5206 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
5209 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5217 FIXME("Unsupported texture type %#x.\n", type);
5218 return WINED3DERR_INVALIDCALL;
5224 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5225 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5227 struct wined3d_swapchain *swapchain;
5230 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5232 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5233 if (FAILED(hr)) return hr;
5235 hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
5236 wined3d_swapchain_decref(swapchain);
5241 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5244 const struct wined3d_state *state = &This->stateBlock->state;
5245 struct wined3d_texture *texture;
5248 TRACE("(%p) : %p\n", This, pNumPasses);
5250 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5252 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5254 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5255 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5257 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5259 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5260 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5263 texture = state->textures[i];
5264 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5266 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5268 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5271 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5273 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5276 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5277 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5279 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5284 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5285 state->render_states[WINED3DRS_STENCILENABLE])
5287 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5288 IWineD3DSurfaceImpl *target = This->render_targets[0];
5291 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5293 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5294 return WINED3DERR_CONFLICTINGRENDERSTATE;
5298 /* return a sensible default */
5301 TRACE("returning D3D_OK\n");
5305 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5309 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5311 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5312 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5313 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5315 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5320 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface,
5321 UINT PaletteNumber, const PALETTEENTRY *pEntries)
5323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5326 PALETTEENTRY **palettes;
5328 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5330 if (PaletteNumber >= MAX_PALETTES) {
5331 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5332 return WINED3DERR_INVALIDCALL;
5335 if (PaletteNumber >= This->palette_count)
5337 NewSize = This->palette_count;
5340 } while(PaletteNumber >= NewSize);
5341 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5343 ERR("Out of memory!\n");
5344 return E_OUTOFMEMORY;
5346 This->palettes = palettes;
5347 This->palette_count = NewSize;
5350 if (!This->palettes[PaletteNumber]) {
5351 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5352 if (!This->palettes[PaletteNumber]) {
5353 ERR("Out of memory!\n");
5354 return E_OUTOFMEMORY;
5358 for (j = 0; j < 256; ++j) {
5359 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5360 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5361 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5362 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5364 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5365 TRACE("(%p) : returning\n", This);
5369 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface,
5370 UINT PaletteNumber, PALETTEENTRY *pEntries)
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5376 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5378 /* What happens in such situation isn't documented; Native seems to silently abort
5379 on such conditions. Return Invalid Call. */
5380 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5381 return WINED3DERR_INVALIDCALL;
5383 for (j = 0; j < 256; ++j) {
5384 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5385 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5386 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5387 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5389 TRACE("(%p) : returning\n", This);
5393 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber)
5395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5396 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5397 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5398 (tested with reference rasterizer). Return Invalid Call. */
5399 if (PaletteNumber >= This->palette_count || !This->palettes[PaletteNumber])
5401 ERR("(%p) : (%u) Nonexistent palette. Palette count %u.\n", This, PaletteNumber, This->palette_count);
5402 return WINED3DERR_INVALIDCALL;
5404 /*TODO: stateblocks */
5405 if (This->currentPalette != PaletteNumber) {
5406 This->currentPalette = PaletteNumber;
5407 dirtify_p8_texture_samplers(This);
5409 TRACE("(%p) : returning\n", This);
5413 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5418 WARN("(%p) : returning Invalid Call\n", This);
5419 return WINED3DERR_INVALIDCALL;
5421 /*TODO: stateblocks */
5422 *PaletteNumber = This->currentPalette;
5423 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5427 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5432 FIXME("(%p) : stub\n", This);
5436 This->softwareVertexProcessing = bSoftware;
5441 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5446 FIXME("(%p) : stub\n", This);
5449 return This->softwareVertexProcessing;
5452 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5453 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5455 struct wined3d_swapchain *swapchain;
5458 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5459 iface, swapchain_idx, raster_status);
5461 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5464 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5468 hr = wined3d_swapchain_get_raster_status(swapchain, raster_status);
5469 wined3d_swapchain_decref(swapchain);
5472 WARN("Failed to get raster status, hr %#x.\n", hr);
5479 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5482 if(nSegments != 0.0f) {
5485 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5492 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5497 FIXME("iface %p stub!\n", iface);
5503 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5504 IWineD3DSurface *src_surface, const RECT *src_rect,
5505 IWineD3DSurface *dst_surface, const POINT *dst_point)
5507 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5508 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5510 const struct wined3d_format *src_format;
5511 const struct wined3d_format *dst_format;
5512 const struct wined3d_gl_info *gl_info;
5513 struct wined3d_context *context;
5514 const unsigned char *data;
5515 UINT update_w, update_h;
5516 CONVERT_TYPES convert;
5520 struct wined3d_format format;
5522 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5523 iface, src_surface, wine_dbgstr_rect(src_rect),
5524 dst_surface, wine_dbgstr_point(dst_point));
5526 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5528 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5529 src_surface, dst_surface);
5530 return WINED3DERR_INVALIDCALL;
5533 src_format = src_impl->resource.format;
5534 dst_format = dst_impl->resource.format;
5536 if (src_format->id != dst_format->id)
5538 WARN("Source and destination surfaces should have the same format.\n");
5539 return WINED3DERR_INVALIDCALL;
5542 dst_x = dst_point ? dst_point->x : 0;
5543 dst_y = dst_point ? dst_point->y : 0;
5545 /* This call loads the OpenGL surface directly, instead of copying the
5546 * surface to the destination's sysmem copy. If surface conversion is
5547 * needed, use BltFast instead to copy in sysmem and use regular surface
5549 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5550 if (convert != NO_CONVERSION || format.convert)
5551 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5553 context = context_acquire(This, NULL);
5554 gl_info = context->gl_info;
5557 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5558 checkGLcall("glActiveTextureARB");
5561 /* Make sure the surface is loaded and up to date */
5562 surface_internal_preload(dst_impl, SRGB_RGB);
5563 surface_bind(dst_impl, gl_info, FALSE);
5565 src_w = src_impl->resource.width;
5566 src_h = src_impl->resource.height;
5567 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5568 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5570 data = src_impl->resource.allocatedMemory;
5571 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5575 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5577 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5578 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5579 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5583 data += (src_rect->top / src_format->block_height) * src_pitch;
5584 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5587 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5588 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5589 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5591 if (row_length == src_pitch)
5593 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5594 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5600 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5601 * can't use the unpack row length like below. */
5602 for (row = 0, y = dst_y; row < row_count; ++row)
5604 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5605 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5606 y += src_format->block_height;
5610 checkGLcall("glCompressedTexSubImage2DARB");
5616 data += src_rect->top * src_w * src_format->byte_count;
5617 data += src_rect->left * src_format->byte_count;
5620 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5621 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5622 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5624 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5625 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5626 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5627 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5628 checkGLcall("glTexSubImage2D");
5632 context_release(context);
5634 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5635 sampler = This->rev_tex_unit_map[0];
5636 if (sampler != WINED3D_UNMAPPED_STAGE)
5638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5644 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 struct WineD3DRectPatch *patch;
5647 GLenum old_primitive_type;
5651 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5653 if(!(Handle || pRectPatchInfo)) {
5654 /* TODO: Write a test for the return value, thus the FIXME */
5655 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5656 return WINED3DERR_INVALIDCALL;
5660 i = PATCHMAP_HASHFUNC(Handle);
5662 LIST_FOR_EACH(e, &This->patches[i]) {
5663 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5664 if(patch->Handle == Handle) {
5671 TRACE("Patch does not exist. Creating a new one\n");
5672 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5673 patch->Handle = Handle;
5674 list_add_head(&This->patches[i], &patch->entry);
5676 TRACE("Found existing patch %p\n", patch);
5679 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5680 * attributes we have to tesselate, read back, and draw. This needs a patch
5681 * management structure instance. Create one.
5683 * A possible improvement is to check if a vertex shader is used, and if not directly
5686 FIXME("Drawing an uncached patch. This is slow\n");
5687 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5690 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5691 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5692 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5695 TRACE("Tesselation density or patch info changed, retesselating\n");
5697 if(pRectPatchInfo) {
5698 patch->RectPatchInfo = *pRectPatchInfo;
5700 patch->numSegs[0] = pNumSegs[0];
5701 patch->numSegs[1] = pNumSegs[1];
5702 patch->numSegs[2] = pNumSegs[2];
5703 patch->numSegs[3] = pNumSegs[3];
5705 hr = tesselate_rectpatch(This, patch);
5707 WARN("Patch tesselation failed\n");
5709 /* Do not release the handle to store the params of the patch */
5711 HeapFree(GetProcessHeap(), 0, patch);
5717 This->currentPatch = patch;
5718 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5719 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5720 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5721 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5722 This->currentPatch = NULL;
5724 /* Destroy uncached patches */
5726 HeapFree(GetProcessHeap(), 0, patch->mem);
5727 HeapFree(GetProcessHeap(), 0, patch);
5732 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5733 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5735 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5736 iface, handle, segment_count, patch_info);
5741 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 struct WineD3DRectPatch *patch;
5746 TRACE("(%p) Handle(%d)\n", This, Handle);
5748 i = PATCHMAP_HASHFUNC(Handle);
5749 LIST_FOR_EACH(e, &This->patches[i]) {
5750 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5751 if(patch->Handle == Handle) {
5752 TRACE("Deleting patch %p\n", patch);
5753 list_remove(&patch->entry);
5754 HeapFree(GetProcessHeap(), 0, patch->mem);
5755 HeapFree(GetProcessHeap(), 0, patch);
5760 /* TODO: Write a test for the return value */
5761 FIXME("Attempt to destroy nonexistent patch\n");
5762 return WINED3DERR_INVALIDCALL;
5765 /* Do not call while under the GL lock. */
5766 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5767 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5769 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5771 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5772 iface, surface, wine_dbgstr_rect(rect),
5773 color->r, color->g, color->b, color->a);
5775 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5777 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5778 return WINED3DERR_INVALIDCALL;
5781 return surface_color_fill(s, rect, color);
5784 /* Do not call while under the GL lock. */
5785 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5786 struct wined3d_rendertarget_view *rendertarget_view, const WINED3DCOLORVALUE *color)
5788 struct wined3d_resource *resource;
5791 resource = rendertarget_view->resource;
5792 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5794 FIXME("Only supported on surface resources\n");
5798 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5799 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5802 /* rendertarget and depth stencil functions */
5803 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5804 DWORD render_target_idx, IWineD3DSurface **render_target)
5806 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5808 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5809 iface, render_target_idx, render_target);
5811 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5813 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5814 return WINED3DERR_INVALIDCALL;
5817 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5818 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5820 TRACE("Returning render target %p.\n", *render_target);
5825 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5827 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5829 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5831 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5832 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5833 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5834 IWineD3DSurface_AddRef(*depth_stencil);
5839 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5840 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5842 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5843 IWineD3DSurfaceImpl *prev;
5845 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5846 iface, render_target_idx, render_target, set_viewport);
5848 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5850 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5851 return WINED3DERR_INVALIDCALL;
5854 prev = device->render_targets[render_target_idx];
5855 if (render_target == (IWineD3DSurface *)prev)
5857 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5861 /* Render target 0 can't be set to NULL. */
5862 if (!render_target && !render_target_idx)
5864 WARN("Trying to set render target 0 to NULL.\n");
5865 return WINED3DERR_INVALIDCALL;
5868 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5870 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5871 return WINED3DERR_INVALIDCALL;
5874 if (render_target) IWineD3DSurface_AddRef(render_target);
5875 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5876 /* Release after the assignment, to prevent device_resource_released()
5877 * from seeing the surface as still in use. */
5878 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5880 /* Render target 0 is special. */
5881 if (!render_target_idx && set_viewport)
5883 /* Set the viewport and scissor rectangles, if requested. Tests show
5884 * that stateblock recording is ignored, the change goes directly
5885 * into the primary stateblock. */
5886 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5887 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5888 device->stateBlock->state.viewport.X = 0;
5889 device->stateBlock->state.viewport.Y = 0;
5890 device->stateBlock->state.viewport.MaxZ = 1.0f;
5891 device->stateBlock->state.viewport.MinZ = 0.0f;
5892 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5894 device->stateBlock->state.scissor_rect.top = 0;
5895 device->stateBlock->state.scissor_rect.left = 0;
5896 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5897 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5898 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5904 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5907 IWineD3DSurfaceImpl *tmp;
5909 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5911 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5913 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5917 if (This->depth_stencil)
5919 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5920 || This->depth_stencil->flags & SFLAG_DISCARD)
5922 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5923 This->depth_stencil->resource.width,
5924 This->depth_stencil->resource.height);
5925 if (This->depth_stencil == This->onscreen_depth_stencil)
5927 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5928 This->onscreen_depth_stencil = NULL;
5933 tmp = This->depth_stencil;
5934 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5935 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5936 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5938 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5940 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5946 else if (tmp && tmp->resource.format->depth_size != This->depth_stencil->resource.format->depth_size)
5948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_DEPTHBIAS));
5954 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5955 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5958 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5959 WINED3DLOCKED_RECT lockedRect;
5961 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5962 iface, XHotSpot, YHotSpot, cursor_image);
5964 /* some basic validation checks */
5965 if (This->cursorTexture)
5967 struct wined3d_context *context = context_acquire(This, NULL);
5969 glDeleteTextures(1, &This->cursorTexture);
5971 context_release(context);
5972 This->cursorTexture = 0;
5975 if (s->resource.width == 32 && s->resource.height == 32)
5976 This->haveHardwareCursor = TRUE;
5978 This->haveHardwareCursor = FALSE;
5982 WINED3DLOCKED_RECT rect;
5984 /* MSDN: Cursor must be A8R8G8B8 */
5985 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5987 WARN("surface %p has an invalid format.\n", cursor_image);
5988 return WINED3DERR_INVALIDCALL;
5991 /* MSDN: Cursor must be smaller than the display mode */
5992 if (s->resource.width > This->ddraw_width
5993 || s->resource.height > This->ddraw_height)
5995 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5996 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5997 return WINED3DERR_INVALIDCALL;
6000 if (!This->haveHardwareCursor) {
6001 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6003 /* Do not store the surface's pointer because the application may
6004 * release it after setting the cursor image. Windows doesn't
6005 * addref the set surface, so we can't do this either without
6006 * creating circular refcount dependencies. Copy out the gl texture
6009 This->cursorWidth = s->resource.width;
6010 This->cursorHeight = s->resource.height;
6011 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
6013 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6014 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
6015 struct wined3d_context *context;
6016 char *mem, *bits = rect.pBits;
6017 GLint intfmt = format->glInternal;
6018 GLint gl_format = format->glFormat;
6019 GLint type = format->glType;
6020 INT height = This->cursorHeight;
6021 INT width = This->cursorWidth;
6022 INT bpp = format->byte_count;
6026 /* Reformat the texture memory (pitch and width can be
6028 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6029 for(i = 0; i < height; i++)
6030 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6031 IWineD3DSurface_Unmap(cursor_image);
6033 context = context_acquire(This, NULL);
6037 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6040 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6043 /* Make sure that a proper texture unit is selected */
6044 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6045 checkGLcall("glActiveTextureARB");
6046 sampler = This->rev_tex_unit_map[0];
6047 if (sampler != WINED3D_UNMAPPED_STAGE)
6049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6051 /* Create a new cursor texture */
6052 glGenTextures(1, &This->cursorTexture);
6053 checkGLcall("glGenTextures");
6054 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6055 checkGLcall("glBindTexture");
6056 /* Copy the bitmap memory into the cursor texture */
6057 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6058 checkGLcall("glTexImage2D");
6059 HeapFree(GetProcessHeap(), 0, mem);
6061 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6063 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6064 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6069 context_release(context);
6073 FIXME("A cursor texture was not returned.\n");
6074 This->cursorTexture = 0;
6079 /* Draw a hardware cursor */
6080 ICONINFO cursorInfo;
6082 /* Create and clear maskBits because it is not needed for
6083 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6085 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6086 (s->resource.width * s->resource.height / 8));
6087 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6088 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6089 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6091 cursorInfo.fIcon = FALSE;
6092 cursorInfo.xHotspot = XHotSpot;
6093 cursorInfo.yHotspot = YHotSpot;
6094 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6095 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6096 IWineD3DSurface_Unmap(cursor_image);
6097 /* Create our cursor and clean up. */
6098 cursor = CreateIconIndirect(&cursorInfo);
6100 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6101 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6102 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6103 This->hardwareCursor = cursor;
6104 HeapFree(GetProcessHeap(), 0, maskBits);
6108 This->xHotSpot = XHotSpot;
6109 This->yHotSpot = YHotSpot;
6113 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6114 int XScreenSpace, int YScreenSpace, DWORD flags)
6116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6118 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6119 iface, XScreenSpace, YScreenSpace, flags);
6121 This->xScreenSpace = XScreenSpace;
6122 This->yScreenSpace = YScreenSpace;
6125 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6127 BOOL oldVisible = This->bCursorVisible;
6130 TRACE("(%p) : visible(%d)\n", This, bShow);
6133 * When ShowCursor is first called it should make the cursor appear at the OS's last
6134 * known cursor position. Because of this, some applications just repetitively call
6135 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6138 This->xScreenSpace = pt.x;
6139 This->yScreenSpace = pt.y;
6141 if (This->haveHardwareCursor) {
6142 This->bCursorVisible = bShow;
6144 SetCursor(This->hardwareCursor);
6150 if (This->cursorTexture)
6151 This->bCursorVisible = bShow;
6157 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6159 TRACE("checking resource %p for eviction\n", resource);
6161 if (resource->pool == WINED3DPOOL_MANAGED)
6163 TRACE("Evicting %p.\n", resource);
6164 resource->resource_ops->resource_unload(resource);
6170 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6172 TRACE("iface %p.\n", iface);
6174 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6175 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6176 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6181 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6183 IWineD3DDeviceImpl *device = surface->resource.device;
6184 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6186 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6187 if (surface->flags & SFLAG_DIBSECTION)
6189 /* Release the DC */
6190 SelectObject(surface->hDC, surface->dib.holdbitmap);
6191 DeleteDC(surface->hDC);
6192 /* Release the DIB section */
6193 DeleteObject(surface->dib.DIBsection);
6194 surface->dib.bitmap_data = NULL;
6195 surface->resource.allocatedMemory = NULL;
6196 surface->flags &= ~SFLAG_DIBSECTION;
6198 surface->resource.width = pPresentationParameters->BackBufferWidth;
6199 surface->resource.height = pPresentationParameters->BackBufferHeight;
6200 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6201 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6203 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6204 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6206 surface->pow2Width = surface->pow2Height = 1;
6207 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6208 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6211 if (surface->texture_name)
6213 struct wined3d_context *context = context_acquire(device, NULL);
6215 glDeleteTextures(1, &surface->texture_name);
6217 context_release(context);
6218 surface->texture_name = 0;
6219 surface->flags &= ~SFLAG_CLIENT;
6221 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6222 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6224 surface->flags |= SFLAG_NONPOW2;
6228 surface->flags &= ~SFLAG_NONPOW2;
6230 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6231 surface->resource.allocatedMemory = NULL;
6232 surface->resource.heapMemory = NULL;
6233 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6235 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6237 if (!surface_init_sysmem(surface))
6239 return E_OUTOFMEMORY;
6244 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6247 WINED3DDISPLAYMODE m;
6250 /* All Windowed modes are supported, as is leaving the current mode */
6251 if(pp->Windowed) return TRUE;
6252 if(!pp->BackBufferWidth) return TRUE;
6253 if(!pp->BackBufferHeight) return TRUE;
6255 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6256 for (i = 0; i < count; ++i)
6258 memset(&m, 0, sizeof(m));
6259 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6261 ERR("Failed to enumerate adapter mode.\n");
6262 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6263 /* Mode found, it is supported. */
6266 /* Mode not found -> not supported */
6270 /* Do not call while under the GL lock. */
6271 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6273 const struct wined3d_gl_info *gl_info;
6274 struct wined3d_context *context;
6275 struct wined3d_shader *shader;
6277 context = context_acquire(device, NULL);
6278 gl_info = context->gl_info;
6280 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6281 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
6283 device->shader_backend->shader_destroy(shader);
6287 if (device->depth_blt_texture)
6289 glDeleteTextures(1, &device->depth_blt_texture);
6290 device->depth_blt_texture = 0;
6292 if (device->depth_blt_rb)
6294 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6295 device->depth_blt_rb = 0;
6296 device->depth_blt_rb_w = 0;
6297 device->depth_blt_rb_h = 0;
6301 device->blitter->free_private(device);
6302 device->frag_pipe->free_private(device);
6303 device->shader_backend->shader_free_private(device);
6304 destroy_dummy_textures(device, gl_info);
6306 context_release(context);
6308 while (device->context_count)
6310 context_destroy(device, device->contexts[0]);
6312 HeapFree(GetProcessHeap(), 0, swapchain->context);
6313 swapchain->context = NULL;
6314 swapchain->num_contexts = 0;
6317 /* Do not call while under the GL lock. */
6318 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, struct wined3d_swapchain *swapchain)
6320 struct wined3d_context *context;
6322 IWineD3DSurfaceImpl *target;
6324 /* Recreate the primary swapchain's context */
6325 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6326 if (!swapchain->context)
6328 ERR("Failed to allocate memory for swapchain context array.\n");
6329 return E_OUTOFMEMORY;
6332 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6333 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6335 WARN("Failed to create context.\n");
6336 HeapFree(GetProcessHeap(), 0, swapchain->context);
6340 swapchain->context[0] = context;
6341 swapchain->num_contexts = 1;
6342 create_dummy_textures(device);
6343 context_release(context);
6345 hr = device->shader_backend->shader_alloc_private(device);
6348 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6352 hr = device->frag_pipe->alloc_private(device);
6355 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6356 device->shader_backend->shader_free_private(device);
6360 hr = device->blitter->alloc_private(device);
6363 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6364 device->frag_pipe->free_private(device);
6365 device->shader_backend->shader_free_private(device);
6372 context_acquire(device, NULL);
6373 destroy_dummy_textures(device, context->gl_info);
6374 context_release(context);
6375 context_destroy(device, context);
6376 HeapFree(GetProcessHeap(), 0, swapchain->context);
6377 swapchain->num_contexts = 0;
6381 /* Do not call while under the GL lock. */
6382 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6383 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6386 struct wined3d_swapchain *swapchain;
6388 BOOL DisplayModeChanged = FALSE;
6389 WINED3DDISPLAYMODE mode;
6390 TRACE("(%p)\n", This);
6392 hr = IWineD3DDevice_GetSwapChain(iface, 0, &swapchain);
6395 ERR("Failed to get the first implicit swapchain\n");
6399 if(!is_display_mode_supported(This, pPresentationParameters)) {
6400 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6401 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6402 pPresentationParameters->BackBufferHeight);
6403 wined3d_swapchain_decref(swapchain);
6404 return WINED3DERR_INVALIDCALL;
6407 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6408 * on an existing gl context, so there's no real need for recreation.
6410 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6412 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6414 TRACE("New params:\n");
6415 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6416 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6417 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6418 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6419 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6420 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6421 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6422 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6423 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6424 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6425 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6426 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6427 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6429 /* No special treatment of these parameters. Just store them */
6430 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6431 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6432 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6433 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6435 /* What to do about these? */
6436 if (pPresentationParameters->BackBufferCount
6437 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6438 ERR("Cannot change the back buffer count yet\n");
6440 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6441 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6442 ERR("Cannot change the back buffer format yet\n");
6445 if (pPresentationParameters->hDeviceWindow
6446 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6447 ERR("Cannot change the device window yet\n");
6449 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6453 TRACE("Creating the depth stencil buffer\n");
6455 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6456 pPresentationParameters->BackBufferWidth,
6457 pPresentationParameters->BackBufferHeight,
6458 pPresentationParameters->AutoDepthStencilFormat,
6459 pPresentationParameters->MultiSampleType,
6460 pPresentationParameters->MultiSampleQuality,
6462 (IWineD3DSurface **)&This->auto_depth_stencil);
6465 ERR("Failed to create the depth stencil buffer.\n");
6466 wined3d_swapchain_decref(swapchain);
6467 return WINED3DERR_INVALIDCALL;
6471 if (This->onscreen_depth_stencil)
6473 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6474 This->onscreen_depth_stencil = NULL;
6477 /* Reset the depth stencil */
6478 if (pPresentationParameters->EnableAutoDepthStencil)
6479 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6481 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6483 TRACE("Resetting stateblock\n");
6484 wined3d_stateblock_decref(This->updateStateBlock);
6485 wined3d_stateblock_decref(This->stateBlock);
6487 delete_opengl_contexts(This, swapchain);
6489 if(pPresentationParameters->Windowed) {
6490 mode.Width = swapchain->orig_width;
6491 mode.Height = swapchain->orig_height;
6492 mode.RefreshRate = 0;
6493 mode.Format = swapchain->presentParms.BackBufferFormat;
6495 mode.Width = pPresentationParameters->BackBufferWidth;
6496 mode.Height = pPresentationParameters->BackBufferHeight;
6497 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6498 mode.Format = swapchain->presentParms.BackBufferFormat;
6501 /* Should Width == 800 && Height == 0 set 800x600? */
6502 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6503 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6504 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6508 if(!pPresentationParameters->Windowed) {
6509 DisplayModeChanged = TRUE;
6511 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6512 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6514 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6517 wined3d_swapchain_decref(swapchain);
6521 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6523 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6526 wined3d_swapchain_decref(swapchain);
6530 if (This->auto_depth_stencil)
6532 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6535 wined3d_swapchain_decref(swapchain);
6541 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6542 || DisplayModeChanged)
6544 BOOL filter = This->filter_messages;
6545 This->filter_messages = TRUE;
6547 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6549 if (!pPresentationParameters->Windowed)
6551 if (swapchain->presentParms.Windowed)
6553 HWND focus_window = This->createParms.hFocusWindow;
6554 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6555 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6557 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6558 wined3d_swapchain_decref(swapchain);
6562 /* switch from windowed to fs */
6563 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6564 pPresentationParameters->BackBufferWidth,
6565 pPresentationParameters->BackBufferHeight);
6569 /* Fullscreen -> fullscreen mode change */
6570 MoveWindow(swapchain->device_window, 0, 0,
6571 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6575 else if (!swapchain->presentParms.Windowed)
6577 /* Fullscreen -> windowed switch */
6578 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6579 IWineD3DDevice_ReleaseFocusWindow(iface);
6581 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6583 This->filter_messages = filter;
6585 else if (!pPresentationParameters->Windowed)
6587 DWORD style = This->style, exStyle = This->exStyle;
6588 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6589 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6590 * Reset to clear up their mess. Guild Wars also loses the device during that.
6594 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6595 pPresentationParameters->BackBufferWidth,
6596 pPresentationParameters->BackBufferHeight);
6597 This->style = style;
6598 This->exStyle = exStyle;
6601 /* Note: No parent needed for initial internal stateblock */
6602 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6603 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6604 else TRACE("Created stateblock %p\n", This->stateBlock);
6605 This->updateStateBlock = This->stateBlock;
6606 wined3d_stateblock_incref(This->updateStateBlock);
6608 stateblock_init_default_state(This->stateBlock);
6610 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6613 GetClientRect(swapchain->win_handle, &client_rect);
6615 if(!swapchain->presentParms.BackBufferCount)
6617 TRACE("Single buffered rendering\n");
6618 swapchain->render_to_fbo = FALSE;
6620 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6621 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6623 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6624 swapchain->presentParms.BackBufferWidth,
6625 swapchain->presentParms.BackBufferHeight,
6626 client_rect.right, client_rect.bottom);
6627 swapchain->render_to_fbo = TRUE;
6631 TRACE("Rendering directly to GL_BACK\n");
6632 swapchain->render_to_fbo = FALSE;
6636 hr = create_primary_opengl_context(This, swapchain);
6637 wined3d_swapchain_decref(swapchain);
6639 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6645 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6647 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6649 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6655 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6657 TRACE("(%p) : pParameters %p\n", This, pParameters);
6659 *pParameters = This->createParms;
6663 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6664 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6666 struct wined3d_swapchain *swapchain;
6668 TRACE("Relaying to swapchain\n");
6670 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6672 wined3d_swapchain_set_gamma_ramp(swapchain, flags, pRamp);
6673 wined3d_swapchain_decref(swapchain);
6677 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp)
6679 struct wined3d_swapchain *swapchain;
6681 TRACE("Relaying to swapchain\n");
6683 if (SUCCEEDED(IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)))
6685 wined3d_swapchain_get_gamma_ramp(swapchain, pRamp);
6686 wined3d_swapchain_decref(swapchain);
6690 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6692 TRACE("device %p, resource %p.\n", device, resource);
6694 list_add_head(&device->resources, &resource->resource_list_entry);
6697 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6699 TRACE("device %p, resource %p.\n", device, resource);
6701 list_remove(&resource->resource_list_entry);
6704 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6706 WINED3DRESOURCETYPE type = resource->resourceType;
6709 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6711 context_resource_released(device, resource, type);
6715 case WINED3DRTYPE_SURFACE:
6717 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6719 if (!device->d3d_initialized) break;
6721 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6723 if (device->render_targets[i] == surface)
6725 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6726 device->render_targets[i] = NULL;
6730 if (device->depth_stencil == surface)
6732 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6733 device->depth_stencil = NULL;
6738 case WINED3DRTYPE_TEXTURE:
6739 case WINED3DRTYPE_CUBETEXTURE:
6740 case WINED3DRTYPE_VOLUMETEXTURE:
6741 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6743 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6745 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6747 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6748 texture, device->stateBlock, i);
6749 device->stateBlock->state.textures[i] = NULL;
6752 if (device->updateStateBlock != device->stateBlock
6753 && device->updateStateBlock->state.textures[i] == texture)
6755 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6756 texture, device->updateStateBlock, i);
6757 device->updateStateBlock->state.textures[i] = NULL;
6762 case WINED3DRTYPE_BUFFER:
6764 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6766 for (i = 0; i < MAX_STREAMS; ++i)
6768 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6770 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6771 buffer, device->stateBlock, i);
6772 device->stateBlock->state.streams[i].buffer = NULL;
6775 if (device->updateStateBlock != device->stateBlock
6776 && device->updateStateBlock->state.streams[i].buffer == buffer)
6778 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6779 buffer, device->updateStateBlock, i);
6780 device->updateStateBlock->state.streams[i].buffer = NULL;
6785 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6787 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6788 buffer, device->stateBlock);
6789 device->stateBlock->state.index_buffer = NULL;
6792 if (device->updateStateBlock != device->stateBlock
6793 && device->updateStateBlock->state.index_buffer == buffer)
6795 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6796 buffer, device->updateStateBlock);
6797 device->updateStateBlock->state.index_buffer = NULL;
6806 /* Remove the resource from the resourceStore */
6807 device_resource_remove(device, resource);
6809 TRACE("Resource released.\n");
6812 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6813 D3DCB_ENUMRESOURCES callback, void *data)
6815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6816 struct wined3d_resource *resource, *cursor;
6818 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6820 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6822 TRACE("enumerating resource %p.\n", resource);
6823 if (callback(resource, data) == S_FALSE)
6825 TRACE("Canceling enumeration.\n");
6833 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6836 struct wined3d_resource *resource;
6838 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6840 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6842 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6846 TRACE("Found surface %p for dc %p.\n", s, dc);
6847 *surface = (IWineD3DSurface *)s;
6853 return WINED3DERR_INVALIDCALL;
6856 /**********************************************************
6857 * IWineD3DDevice VTbl follows
6858 **********************************************************/
6860 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6862 /*** IUnknown methods ***/
6863 IWineD3DDeviceImpl_QueryInterface,
6864 IWineD3DDeviceImpl_AddRef,
6865 IWineD3DDeviceImpl_Release,
6866 /*** IWineD3DDevice methods ***/
6867 /*** Creation methods**/
6868 IWineD3DDeviceImpl_CreateBuffer,
6869 IWineD3DDeviceImpl_CreateVertexBuffer,
6870 IWineD3DDeviceImpl_CreateIndexBuffer,
6871 IWineD3DDeviceImpl_CreateStateBlock,
6872 IWineD3DDeviceImpl_CreateSurface,
6873 IWineD3DDeviceImpl_CreateRendertargetView,
6874 IWineD3DDeviceImpl_CreateTexture,
6875 IWineD3DDeviceImpl_CreateVolumeTexture,
6876 IWineD3DDeviceImpl_CreateVolume,
6877 IWineD3DDeviceImpl_CreateCubeTexture,
6878 IWineD3DDeviceImpl_CreateQuery,
6879 IWineD3DDeviceImpl_CreateSwapChain,
6880 IWineD3DDeviceImpl_CreateVertexDeclaration,
6881 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6882 IWineD3DDeviceImpl_CreateVertexShader,
6883 IWineD3DDeviceImpl_CreateGeometryShader,
6884 IWineD3DDeviceImpl_CreatePixelShader,
6885 IWineD3DDeviceImpl_CreatePalette,
6886 /*** Odd functions **/
6887 IWineD3DDeviceImpl_Init3D,
6888 IWineD3DDeviceImpl_InitGDI,
6889 IWineD3DDeviceImpl_Uninit3D,
6890 IWineD3DDeviceImpl_UninitGDI,
6891 IWineD3DDeviceImpl_SetMultithreaded,
6892 IWineD3DDeviceImpl_EvictManagedResources,
6893 IWineD3DDeviceImpl_GetAvailableTextureMem,
6894 IWineD3DDeviceImpl_GetBackBuffer,
6895 IWineD3DDeviceImpl_GetCreationParameters,
6896 IWineD3DDeviceImpl_GetDeviceCaps,
6897 IWineD3DDeviceImpl_GetDirect3D,
6898 IWineD3DDeviceImpl_GetDisplayMode,
6899 IWineD3DDeviceImpl_SetDisplayMode,
6900 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6901 IWineD3DDeviceImpl_GetRasterStatus,
6902 IWineD3DDeviceImpl_GetSwapChain,
6903 IWineD3DDeviceImpl_Reset,
6904 IWineD3DDeviceImpl_SetDialogBoxMode,
6905 IWineD3DDeviceImpl_SetCursorProperties,
6906 IWineD3DDeviceImpl_SetCursorPosition,
6907 IWineD3DDeviceImpl_ShowCursor,
6908 /*** Getters and setters **/
6909 IWineD3DDeviceImpl_SetClipPlane,
6910 IWineD3DDeviceImpl_GetClipPlane,
6911 IWineD3DDeviceImpl_SetClipStatus,
6912 IWineD3DDeviceImpl_GetClipStatus,
6913 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6914 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6915 IWineD3DDeviceImpl_SetDepthStencilSurface,
6916 IWineD3DDeviceImpl_GetDepthStencilSurface,
6917 IWineD3DDeviceImpl_SetGammaRamp,
6918 IWineD3DDeviceImpl_GetGammaRamp,
6919 IWineD3DDeviceImpl_SetIndexBuffer,
6920 IWineD3DDeviceImpl_GetIndexBuffer,
6921 IWineD3DDeviceImpl_SetBaseVertexIndex,
6922 IWineD3DDeviceImpl_GetBaseVertexIndex,
6923 IWineD3DDeviceImpl_SetLight,
6924 IWineD3DDeviceImpl_GetLight,
6925 IWineD3DDeviceImpl_SetLightEnable,
6926 IWineD3DDeviceImpl_GetLightEnable,
6927 IWineD3DDeviceImpl_SetMaterial,
6928 IWineD3DDeviceImpl_GetMaterial,
6929 IWineD3DDeviceImpl_SetNPatchMode,
6930 IWineD3DDeviceImpl_GetNPatchMode,
6931 IWineD3DDeviceImpl_SetPaletteEntries,
6932 IWineD3DDeviceImpl_GetPaletteEntries,
6933 IWineD3DDeviceImpl_SetPixelShader,
6934 IWineD3DDeviceImpl_GetPixelShader,
6935 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6936 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6937 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6938 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6939 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6940 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6941 IWineD3DDeviceImpl_SetRenderState,
6942 IWineD3DDeviceImpl_GetRenderState,
6943 IWineD3DDeviceImpl_SetRenderTarget,
6944 IWineD3DDeviceImpl_GetRenderTarget,
6945 IWineD3DDeviceImpl_SetSamplerState,
6946 IWineD3DDeviceImpl_GetSamplerState,
6947 IWineD3DDeviceImpl_SetScissorRect,
6948 IWineD3DDeviceImpl_GetScissorRect,
6949 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6950 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6951 IWineD3DDeviceImpl_SetStreamSource,
6952 IWineD3DDeviceImpl_GetStreamSource,
6953 IWineD3DDeviceImpl_SetStreamSourceFreq,
6954 IWineD3DDeviceImpl_GetStreamSourceFreq,
6955 IWineD3DDeviceImpl_SetTexture,
6956 IWineD3DDeviceImpl_GetTexture,
6957 IWineD3DDeviceImpl_SetTextureStageState,
6958 IWineD3DDeviceImpl_GetTextureStageState,
6959 IWineD3DDeviceImpl_SetTransform,
6960 IWineD3DDeviceImpl_GetTransform,
6961 IWineD3DDeviceImpl_SetVertexDeclaration,
6962 IWineD3DDeviceImpl_GetVertexDeclaration,
6963 IWineD3DDeviceImpl_SetVertexShader,
6964 IWineD3DDeviceImpl_GetVertexShader,
6965 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6966 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6967 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6968 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6969 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6970 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6971 IWineD3DDeviceImpl_SetViewport,
6972 IWineD3DDeviceImpl_GetViewport,
6973 IWineD3DDeviceImpl_MultiplyTransform,
6974 IWineD3DDeviceImpl_ValidateDevice,
6975 IWineD3DDeviceImpl_ProcessVertices,
6976 /*** State block ***/
6977 IWineD3DDeviceImpl_BeginStateBlock,
6978 IWineD3DDeviceImpl_EndStateBlock,
6979 /*** Scene management ***/
6980 IWineD3DDeviceImpl_BeginScene,
6981 IWineD3DDeviceImpl_EndScene,
6982 IWineD3DDeviceImpl_Present,
6983 IWineD3DDeviceImpl_Clear,
6984 IWineD3DDeviceImpl_ClearRendertargetView,
6986 IWineD3DDeviceImpl_SetPrimitiveType,
6987 IWineD3DDeviceImpl_GetPrimitiveType,
6988 IWineD3DDeviceImpl_DrawPrimitive,
6989 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6990 IWineD3DDeviceImpl_DrawPrimitiveUP,
6991 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6992 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6993 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6994 IWineD3DDeviceImpl_DrawRectPatch,
6995 IWineD3DDeviceImpl_DrawTriPatch,
6996 IWineD3DDeviceImpl_DeletePatch,
6997 IWineD3DDeviceImpl_ColorFill,
6998 IWineD3DDeviceImpl_UpdateTexture,
6999 IWineD3DDeviceImpl_UpdateSurface,
7000 IWineD3DDeviceImpl_GetFrontBufferData,
7001 /*** object tracking ***/
7002 IWineD3DDeviceImpl_EnumResources,
7003 IWineD3DDeviceImpl_GetSurfaceFromDC,
7004 IWineD3DDeviceImpl_AcquireFocusWindow,
7005 IWineD3DDeviceImpl_ReleaseFocusWindow,
7006 IWineD3DDeviceImpl_SetupFullscreenWindow,
7007 IWineD3DDeviceImpl_RestoreFullscreenWindow,
7010 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
7011 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7012 IWineD3DDeviceParent *device_parent)
7014 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7015 const struct fragment_pipeline *fragment_pipeline;
7016 struct shader_caps shader_caps;
7017 struct fragment_caps ffp_caps;
7018 WINED3DDISPLAYMODE mode;
7022 device->lpVtbl = &IWineD3DDevice_Vtbl;
7024 device->wined3d = wined3d;
7025 wined3d_incref(device->wined3d);
7026 device->adapter = wined3d->adapter_count ? adapter : NULL;
7027 device->device_parent = device_parent;
7028 list_init(&device->resources);
7029 list_init(&device->shaders);
7031 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7033 /* Get the initial screen setup for ddraw. */
7034 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7037 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7038 wined3d_decref(device->wined3d);
7041 device->ddraw_width = mode.Width;
7042 device->ddraw_height = mode.Height;
7043 device->ddraw_format = mode.Format;
7045 /* Save the creation parameters. */
7046 device->createParms.AdapterOrdinal = adapter_idx;
7047 device->createParms.DeviceType = device_type;
7048 device->createParms.hFocusWindow = focus_window;
7049 device->createParms.BehaviorFlags = flags;
7051 device->devType = device_type;
7052 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7054 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7055 device->shader_backend = adapter->shader_backend;
7057 if (device->shader_backend)
7059 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7060 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7061 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7062 device->vs_clipping = shader_caps.VSClipping;
7064 fragment_pipeline = adapter->fragment_pipe;
7065 device->frag_pipe = fragment_pipeline;
7066 if (fragment_pipeline)
7068 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7069 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7071 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7072 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7075 ERR("Failed to compile state table, hr %#x.\n", hr);
7076 wined3d_decref(device->wined3d);
7080 device->blitter = adapter->blitter;
7086 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7087 DWORD rep = This->StateTable[state].representative;
7088 struct wined3d_context *context;
7093 for (i = 0; i < This->context_count; ++i)
7095 context = This->contexts[i];
7096 if(isStateDirty(context, rep)) continue;
7098 context->dirtyArray[context->numDirtyEntries++] = rep;
7099 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7100 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7101 context->isStateDirty[idx] |= (1 << shift);
7105 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7107 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7108 *width = context->current_rt->pow2Width;
7109 *height = context->current_rt->pow2Height;
7112 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7114 struct wined3d_swapchain *swapchain = context->swapchain;
7115 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7116 * current context's drawable, which is the size of the back buffer of the swapchain
7117 * the active context belongs to. */
7118 *width = swapchain->presentParms.BackBufferWidth;
7119 *height = swapchain->presentParms.BackBufferHeight;
7122 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7123 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7125 if (device->filter_messages)
7127 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7128 window, message, wparam, lparam);
7130 return DefWindowProcW(window, message, wparam, lparam);
7132 return DefWindowProcA(window, message, wparam, lparam);
7135 if (message == WM_DESTROY)
7137 TRACE("unregister window %p.\n", window);
7138 wined3d_unregister_window(window);
7140 if (device->focus_window == window) device->focus_window = NULL;
7141 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7145 return CallWindowProcW(proc, window, message, wparam, lparam);
7147 return CallWindowProcA(proc, window, message, wparam, lparam);