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 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
656 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
658 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
659 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
660 IWineD3DSurfaceImpl *target = rts[0];
661 UINT drawable_width, drawable_height;
662 struct wined3d_context *context;
663 GLbitfield clear_mask = 0;
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");
697 target->get_drawable_size(context, &drawable_width, &drawable_height);
701 /* Only set the values up once, as they are not changing. */
702 if (flags & WINED3DCLEAR_STENCIL)
704 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
706 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
707 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
710 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
711 glClearStencil(stencil);
712 checkGLcall("glClearStencil");
713 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
716 if (flags & WINED3DCLEAR_ZBUFFER)
718 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
720 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
723 device_switch_onscreen_ds(device, context, depth_stencil);
726 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
727 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
729 glDepthMask(GL_TRUE);
730 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
732 checkGLcall("glClearDepth");
733 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
736 if (flags & WINED3DCLEAR_TARGET)
738 for (i = 0; i < rt_count; ++i)
740 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
743 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
747 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
748 glClearColor(color->r, color->g, color->b, color->a);
749 checkGLcall("glClearColor");
750 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
755 if (context->render_offscreen)
757 glScissor(draw_rect->left, draw_rect->top,
758 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
762 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
763 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
765 checkGLcall("glScissor");
767 checkGLcall("glClear");
773 /* Now process each rect in turn. */
774 for (i = 0; i < rect_count; ++i)
776 /* Note that GL uses lower left, width/height. */
777 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
779 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
780 wine_dbgstr_rect(&clear_rect[i]),
781 wine_dbgstr_rect(¤t_rect));
783 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
784 * The rectangle is not cleared, no error is returned, but further rectanlges are
785 * still cleared if they are valid. */
786 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
788 TRACE("Rectangle with negative dimensions, ignoring.\n");
792 if (context->render_offscreen)
794 glScissor(current_rect.left, current_rect.top,
795 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
799 glScissor(current_rect.left, drawable_height - current_rect.bottom,
800 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
802 checkGLcall("glScissor");
805 checkGLcall("glClear");
811 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
812 && target->container.u.swapchain->front_buffer == target))
813 wglFlush(); /* Flush to ensure ordering across contexts. */
815 context_release(context);
821 /**********************************************************
822 * IUnknown parts follows
823 **********************************************************/
825 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
827 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
829 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
830 || IsEqualGUID(riid, &IID_IUnknown))
832 IUnknown_AddRef(iface);
837 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
840 return E_NOINTERFACE;
843 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
845 ULONG refCount = InterlockedIncrement(&This->ref);
847 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
851 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
853 ULONG refCount = InterlockedDecrement(&This->ref);
855 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
860 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
861 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
862 This->multistate_funcs[i] = NULL;
865 /* TODO: Clean up all the surfaces and textures! */
866 /* NOTE: You must release the parent if the object was created via a callback
867 ** ***************************/
869 if (!list_empty(&This->resources))
871 struct wined3d_resource *resource;
872 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
874 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
881 if(This->contexts) ERR("Context array not freed!\n");
882 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
883 This->haveHardwareCursor = FALSE;
885 wined3d_decref(This->wined3d);
886 This->wined3d = NULL;
887 HeapFree(GetProcessHeap(), 0, This);
888 TRACE("Freed device %p\n", This);
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
895 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 struct wined3d_buffer *object;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY;
910 FIXME("Ignoring access flags (pool)\n");
912 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
913 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
916 WARN("Failed to initialize buffer, hr %#x.\n", hr);
917 HeapFree(GetProcessHeap(), 0, object);
920 object->desc = *desc;
922 TRACE("Created buffer %p.\n", object);
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
930 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
933 struct wined3d_buffer *object;
936 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
937 iface, Size, Usage, Pool, parent, parent_ops, buffer);
939 if (Pool == WINED3DPOOL_SCRATCH)
941 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
942 * anyway, SCRATCH vertex buffers aren't usable anywhere
944 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 return WINED3DERR_INVALIDCALL;
949 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
952 ERR("Out of memory\n");
954 return WINED3DERR_OUTOFVIDEOMEMORY;
957 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
958 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
961 WARN("Failed to initialize buffer, hr %#x.\n", hr);
962 HeapFree(GetProcessHeap(), 0, object);
966 TRACE("Created buffer %p.\n", object);
972 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
973 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 struct wined3d_buffer *object;
979 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
980 iface, Length, Usage, Pool, parent, parent_ops, buffer);
982 /* Allocate the storage for the device */
983 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
986 ERR("Out of memory\n");
988 return WINED3DERR_OUTOFVIDEOMEMORY;
991 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
992 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
996 WARN("Failed to initialize buffer, hr %#x\n", hr);
997 HeapFree(GetProcessHeap(), 0, object);
1001 TRACE("Created buffer %p.\n", object);
1008 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1009 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1012 struct wined3d_stateblock *object;
1015 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1018 ERR("Failed to allocate stateblock memory.\n");
1019 return E_OUTOFMEMORY;
1022 hr = stateblock_init(object, This, type);
1025 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1026 HeapFree(GetProcessHeap(), 0, object);
1030 TRACE("Created stateblock %p.\n", object);
1031 *stateblock = object;
1036 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1037 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1038 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1039 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1042 IWineD3DSurfaceImpl *object;
1045 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1046 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1047 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1048 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1049 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1051 if (Impl == SURFACE_OPENGL && !This->adapter)
1053 ERR("OpenGL surfaces are not available without OpenGL.\n");
1054 return WINED3DERR_NOTAVAILABLE;
1057 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1060 ERR("Failed to allocate surface memory.\n");
1061 return WINED3DERR_OUTOFVIDEOMEMORY;
1064 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1065 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1068 WARN("Failed to initialize surface, returning %#x.\n", hr);
1069 HeapFree(GetProcessHeap(), 0, object);
1073 TRACE("(%p) : Created surface %p\n", This, object);
1075 *surface = (IWineD3DSurface *)object;
1080 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1081 struct wined3d_resource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1083 struct wined3d_rendertarget_view *object;
1085 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1086 iface, resource, parent, rendertarget_view);
1088 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1091 ERR("Failed to allocate memory\n");
1092 return E_OUTOFMEMORY;
1095 wined3d_rendertarget_view_init(object, resource, parent);
1097 TRACE("Created render target view %p.\n", object);
1098 *rendertarget_view = (IWineD3DRendertargetView *)object;
1103 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1104 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1105 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1108 struct wined3d_texture *object;
1111 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1112 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1113 Format, debug_d3dformat(Format), Pool, texture, parent);
1115 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1118 ERR("Out of memory\n");
1120 return WINED3DERR_OUTOFVIDEOMEMORY;
1123 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1126 WARN("Failed to initialize texture, returning %#x\n", hr);
1127 HeapFree(GetProcessHeap(), 0, object);
1134 TRACE("(%p) : Created texture %p\n", This, object);
1139 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1140 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1141 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1144 struct wined3d_texture *object;
1147 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1148 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1150 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1153 ERR("Out of memory\n");
1155 return WINED3DERR_OUTOFVIDEOMEMORY;
1158 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1161 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1162 HeapFree(GetProcessHeap(), 0, object);
1167 TRACE("(%p) : Created volume texture %p.\n", This, object);
1173 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1174 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1175 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1178 IWineD3DVolumeImpl *object;
1181 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1182 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1184 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1187 ERR("Out of memory\n");
1189 return WINED3DERR_OUTOFVIDEOMEMORY;
1192 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1195 WARN("Failed to initialize volume, returning %#x.\n", hr);
1196 HeapFree(GetProcessHeap(), 0, object);
1200 TRACE("(%p) : Created volume %p.\n", This, object);
1201 *ppVolume = (IWineD3DVolume *)object;
1206 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1207 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1208 const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture)
1210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1211 struct wined3d_texture *object;
1214 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1217 ERR("Out of memory\n");
1219 return WINED3DERR_OUTOFVIDEOMEMORY;
1222 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1225 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1226 HeapFree(GetProcessHeap(), 0, object);
1231 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1237 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1238 WINED3DQUERYTYPE type, struct wined3d_query **query)
1240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1241 struct wined3d_query *object;
1244 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1246 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1249 ERR("Failed to allocate query memory.\n");
1250 return E_OUTOFMEMORY;
1253 hr = query_init(object, This, type);
1256 WARN("Failed to initialize query, hr %#x.\n", hr);
1257 HeapFree(GetProcessHeap(), 0, object);
1261 TRACE("Created query %p.\n", object);
1267 /* Do not call while under the GL lock. */
1268 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1269 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1270 void *parent, IWineD3DSwapChain **swapchain)
1272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 IWineD3DSwapChainImpl *object;
1276 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1277 iface, present_parameters, swapchain, parent, surface_type);
1279 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1282 ERR("Failed to allocate swapchain memory.\n");
1283 return E_OUTOFMEMORY;
1286 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1289 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1290 HeapFree(GetProcessHeap(), 0, object);
1294 TRACE("Created swapchain %p.\n", object);
1295 *swapchain = (IWineD3DSwapChain *)object;
1300 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1301 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 TRACE("(%p)\n", This);
1305 return This->NumberOfSwapChains;
1308 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1310 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1312 if (iSwapChain < This->NumberOfSwapChains)
1314 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1315 IWineD3DSwapChain_AddRef(*pSwapChain);
1316 TRACE("(%p) returning %p\n", This, *pSwapChain);
1319 TRACE("Swapchain out of range\n");
1321 return WINED3DERR_INVALIDCALL;
1325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1326 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1327 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1330 struct wined3d_vertex_declaration *object;
1333 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1334 iface, elements, element_count, parent, parent_ops, declaration);
1336 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1339 ERR("Failed to allocate vertex declaration memory.\n");
1340 return E_OUTOFMEMORY;
1343 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1346 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1347 HeapFree(GetProcessHeap(), 0, object);
1351 TRACE("Created vertex declaration %p.\n", object);
1352 *declaration = object;
1357 struct wined3d_fvf_convert_state
1359 const struct wined3d_gl_info *gl_info;
1360 WINED3DVERTEXELEMENT *elements;
1365 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1366 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1368 WINED3DVERTEXELEMENT *elements = state->elements;
1369 const struct wined3d_format *format;
1370 UINT offset = state->offset;
1371 UINT idx = state->idx;
1373 elements[idx].format = format_id;
1374 elements[idx].input_slot = 0;
1375 elements[idx].offset = offset;
1376 elements[idx].output_slot = 0;
1377 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1378 elements[idx].usage = usage;
1379 elements[idx].usage_idx = usage_idx;
1381 format = wined3d_get_format(state->gl_info, format_id);
1382 state->offset += format->component_count * format->component_size;
1386 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1387 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1389 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1390 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1391 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1392 BOOL has_blend_idx = has_blend &&
1393 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1394 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1395 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1396 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1397 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1398 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1399 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1401 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1402 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1403 struct wined3d_fvf_convert_state state;
1406 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1407 if (has_blend_idx) num_blends--;
1409 /* Compute declaration size */
1410 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1411 has_psize + has_diffuse + has_specular + num_textures;
1413 state.gl_info = gl_info;
1414 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1415 if (!state.elements) return ~0U;
1421 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1422 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1423 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1424 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1426 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1429 if (has_blend && (num_blends > 0))
1431 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1432 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1447 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1450 ERR("Unexpected amount of blend values: %u\n", num_blends);
1457 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1458 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1459 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1460 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1461 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1463 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1466 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1467 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1468 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1469 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1471 for (idx = 0; idx < num_textures; ++idx)
1473 switch ((texcoords >> (idx * 2)) & 0x03)
1475 case WINED3DFVF_TEXTUREFORMAT1:
1476 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 case WINED3DFVF_TEXTUREFORMAT2:
1479 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 case WINED3DFVF_TEXTUREFORMAT3:
1482 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1484 case WINED3DFVF_TEXTUREFORMAT4:
1485 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1490 *ppVertexElements = state.elements;
1494 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1495 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1496 struct wined3d_vertex_declaration **declaration)
1498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1499 WINED3DVERTEXELEMENT *elements;
1503 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1504 iface, fvf, parent, parent_ops, declaration);
1506 size = ConvertFvfToDeclaration(This, fvf, &elements);
1507 if (size == ~0U) return E_OUTOFMEMORY;
1509 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1510 HeapFree(GetProcessHeap(), 0, elements);
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1515 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1516 void *parent, const struct wined3d_parent_ops *parent_ops,
1517 struct wined3d_shader **shader)
1519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1520 struct wined3d_shader *object;
1523 if (This->vs_selected_mode == SHADER_NONE)
1524 return WINED3DERR_INVALIDCALL;
1526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1529 ERR("Failed to allocate shader memory.\n");
1530 return E_OUTOFMEMORY;
1533 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1536 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1537 HeapFree(GetProcessHeap(), 0, object);
1541 TRACE("Created vertex shader %p.\n", object);
1547 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1548 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1549 void *parent, const struct wined3d_parent_ops *parent_ops,
1550 struct wined3d_shader **shader)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 struct wined3d_shader *object;
1556 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1559 ERR("Failed to allocate shader memory.\n");
1560 return E_OUTOFMEMORY;
1563 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1566 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1567 HeapFree(GetProcessHeap(), 0, object);
1571 TRACE("Created geometry shader %p.\n", object);
1577 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1578 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1579 void *parent, const struct wined3d_parent_ops *parent_ops,
1580 struct wined3d_shader **shader)
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 struct wined3d_shader *object;
1586 if (This->ps_selected_mode == SHADER_NONE)
1587 return WINED3DERR_INVALIDCALL;
1589 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1592 ERR("Failed to allocate shader memory.\n");
1593 return E_OUTOFMEMORY;
1596 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1599 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1600 HeapFree(GetProcessHeap(), 0, object);
1604 TRACE("Created pixel shader %p.\n", object);
1610 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1611 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1614 struct wined3d_palette *object;
1617 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1618 iface, flags, entries, palette, parent);
1620 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1623 ERR("Failed to allocate palette memory.\n");
1624 return E_OUTOFMEMORY;
1627 hr = wined3d_palette_init(object, This, flags, entries, parent);
1630 WARN("Failed to initialize palette, hr %#x.\n", hr);
1631 HeapFree(GetProcessHeap(), 0, object);
1635 TRACE("Created palette %p.\n", object);
1641 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1645 HDC dcb = NULL, dcs = NULL;
1646 WINEDDCOLORKEY colorkey;
1648 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1651 GetObjectA(hbm, sizeof(BITMAP), &bm);
1652 dcb = CreateCompatibleDC(NULL);
1654 SelectObject(dcb, hbm);
1658 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1659 * couldn't be loaded
1661 memset(&bm, 0, sizeof(bm));
1666 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1667 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1668 &wined3d_null_parent_ops, &This->logo_surface);
1671 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1676 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1677 if(FAILED(hr)) goto out;
1678 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1679 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1681 colorkey.dwColorSpaceLowValue = 0;
1682 colorkey.dwColorSpaceHighValue = 0;
1683 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1687 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1688 /* Fill the surface with a white color to show that wined3d is there */
1689 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1693 if (dcb) DeleteDC(dcb);
1694 if (hbm) DeleteObject(hbm);
1697 /* Context activation is done by the caller. */
1698 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1700 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1702 /* Under DirectX you can have texture stage operations even if no texture is
1703 bound, whereas opengl will only do texture operations when a valid texture is
1704 bound. We emulate this by creating dummy textures and binding them to each
1705 texture stage, but disable all stages by default. Hence if a stage is enabled
1706 then the default texture will kick in until replaced by a SetTexture call */
1709 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1711 /* The dummy texture does not have client storage backing */
1712 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1713 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1716 for (i = 0; i < gl_info->limits.textures; ++i)
1718 GLubyte white = 255;
1720 /* Make appropriate texture active */
1721 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1722 checkGLcall("glActiveTextureARB");
1724 /* Generate an opengl texture name */
1725 glGenTextures(1, &This->dummyTextureName[i]);
1726 checkGLcall("glGenTextures");
1727 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1729 /* Generate a dummy 2d texture (not using 1d because they cause many
1730 * DRI drivers fall back to sw) */
1731 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1732 checkGLcall("glBindTexture");
1734 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1735 checkGLcall("glTexImage2D");
1738 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1740 /* Reenable because if supported it is enabled by default */
1741 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1742 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1748 /* Context activation is done by the caller. */
1749 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1752 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1753 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1756 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1759 static LONG fullscreen_style(LONG style)
1761 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1762 style |= WS_POPUP | WS_SYSMENU;
1763 style &= ~(WS_CAPTION | WS_THICKFRAME);
1768 static LONG fullscreen_exstyle(LONG exstyle)
1770 /* Filter out window decorations. */
1771 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1776 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1778 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1779 BOOL filter_messages;
1780 LONG style, exstyle;
1782 TRACE("Setting up window %p for fullscreen mode.\n", window);
1784 if (device->style || device->exStyle)
1786 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1787 window, device->style, device->exStyle);
1790 device->style = GetWindowLongW(window, GWL_STYLE);
1791 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1793 style = fullscreen_style(device->style);
1794 exstyle = fullscreen_exstyle(device->exStyle);
1796 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1797 device->style, device->exStyle, style, exstyle);
1799 filter_messages = device->filter_messages;
1800 device->filter_messages = TRUE;
1802 SetWindowLongW(window, GWL_STYLE, style);
1803 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1804 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1806 device->filter_messages = filter_messages;
1809 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1811 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1812 BOOL filter_messages;
1813 LONG style, exstyle;
1815 if (!device->style && !device->exStyle) return;
1817 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1818 window, device->style, device->exStyle);
1820 style = GetWindowLongW(window, GWL_STYLE);
1821 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1823 filter_messages = device->filter_messages;
1824 device->filter_messages = TRUE;
1826 /* Only restore the style if the application didn't modify it during the
1827 * fullscreen phase. Some applications change it before calling Reset()
1828 * when switching between windowed and fullscreen modes (HL2), some
1829 * depend on the original style (Eve Online). */
1830 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1832 SetWindowLongW(window, GWL_STYLE, device->style);
1833 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1835 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1837 device->filter_messages = filter_messages;
1839 /* Delete the old values. */
1841 device->exStyle = 0;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1846 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1848 TRACE("iface %p, window %p.\n", iface, window);
1850 if (!wined3d_register_window(window, device))
1852 ERR("Failed to register window %p.\n", window);
1856 device->focus_window = window;
1857 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1862 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1864 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1866 TRACE("iface %p.\n", iface);
1868 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1869 device->focus_window = NULL;
1872 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1873 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1876 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1877 IWineD3DSwapChainImpl *swapchain = NULL;
1878 struct wined3d_context *context;
1883 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1885 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1886 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1888 TRACE("(%p) : Creating stateblock\n", This);
1889 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1892 WARN("Failed to create stateblock\n");
1895 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1896 This->updateStateBlock = This->stateBlock;
1897 wined3d_stateblock_incref(This->updateStateBlock);
1899 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1900 sizeof(*This->render_targets) * gl_info->limits.buffers);
1902 This->NumberOfPalettes = 1;
1903 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1904 if (!This->palettes || !This->render_targets)
1906 ERR("Out of memory!\n");
1910 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1911 if(!This->palettes[0]) {
1912 ERR("Out of memory!\n");
1916 for (i = 0; i < 256; ++i) {
1917 This->palettes[0][i].peRed = 0xFF;
1918 This->palettes[0][i].peGreen = 0xFF;
1919 This->palettes[0][i].peBlue = 0xFF;
1920 This->palettes[0][i].peFlags = 0xFF;
1922 This->currentPalette = 0;
1924 /* Initialize the texture unit mapping to a 1:1 mapping */
1925 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1927 if (state < gl_info->limits.fragment_samplers)
1929 This->texUnitMap[state] = state;
1930 This->rev_tex_unit_map[state] = state;
1932 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1933 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1937 /* Setup the implicit swapchain. This also initializes a context. */
1938 TRACE("Creating implicit swapchain\n");
1939 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1940 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1943 WARN("Failed to create implicit swapchain\n");
1947 This->NumberOfSwapChains = 1;
1948 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1949 if (!This->swapchains)
1951 ERR("Out of memory!\n");
1954 This->swapchains[0] = swapchain;
1956 if (swapchain->back_buffers && swapchain->back_buffers[0])
1958 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1959 This->render_targets[0] = swapchain->back_buffers[0];
1963 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1964 This->render_targets[0] = swapchain->front_buffer;
1966 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1968 /* Depth Stencil support */
1969 This->depth_stencil = This->auto_depth_stencil;
1970 if (This->depth_stencil)
1971 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1973 hr = This->shader_backend->shader_alloc_private(This);
1975 TRACE("Shader private data couldn't be allocated\n");
1978 hr = This->frag_pipe->alloc_private(This);
1980 TRACE("Fragment pipeline private data couldn't be allocated\n");
1983 hr = This->blitter->alloc_private(This);
1985 TRACE("Blitter private data couldn't be allocated\n");
1989 /* Set up some starting GL setup */
1991 /* Setup all the devices defaults */
1992 stateblock_init_default_state(This->stateBlock);
1994 context = context_acquire(This, swapchain->front_buffer);
1996 create_dummy_textures(This);
2000 /* Initialize the current view state */
2001 This->view_ident = 1;
2002 This->contexts[0]->last_was_rhw = 0;
2003 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2004 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2006 switch(wined3d_settings.offscreen_rendering_mode) {
2008 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2011 case ORM_BACKBUFFER:
2013 if (context_get_current()->aux_buffers > 0)
2015 TRACE("Using auxilliary buffer for offscreen rendering\n");
2016 This->offscreenBuffer = GL_AUX0;
2018 TRACE("Using back buffer for offscreen rendering\n");
2019 This->offscreenBuffer = GL_BACK;
2024 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2027 context_release(context);
2029 /* Clear the screen */
2030 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2031 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2034 This->d3d_initialized = TRUE;
2036 if(wined3d_settings.logo) {
2037 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2039 This->highest_dirty_ps_const = 0;
2040 This->highest_dirty_vs_const = 0;
2044 HeapFree(GetProcessHeap(), 0, This->render_targets);
2045 HeapFree(GetProcessHeap(), 0, This->swapchains);
2046 This->NumberOfSwapChains = 0;
2047 if(This->palettes) {
2048 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2049 HeapFree(GetProcessHeap(), 0, This->palettes);
2051 This->NumberOfPalettes = 0;
2053 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2055 if (This->stateBlock)
2057 wined3d_stateblock_decref(This->stateBlock);
2058 This->stateBlock = NULL;
2060 if (This->blit_priv) {
2061 This->blitter->free_private(This);
2063 if (This->fragment_priv) {
2064 This->frag_pipe->free_private(This);
2066 if (This->shader_priv) {
2067 This->shader_backend->shader_free_private(This);
2072 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2073 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2076 IWineD3DSwapChainImpl *swapchain = NULL;
2079 /* Setup the implicit swapchain */
2080 TRACE("Creating implicit swapchain\n");
2081 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2082 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2085 WARN("Failed to create implicit swapchain\n");
2089 This->NumberOfSwapChains = 1;
2090 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2091 if (!This->swapchains)
2093 ERR("Out of memory!\n");
2096 This->swapchains[0] = swapchain;
2100 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2104 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2106 TRACE("Unloading resource %p.\n", resource);
2108 resource->resource_ops->resource_unload(resource);
2113 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2114 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2117 const struct wined3d_gl_info *gl_info;
2118 struct IWineD3DSurfaceImpl *surface;
2119 struct wined3d_context *context;
2122 TRACE("(%p)\n", This);
2124 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2126 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2127 * it was created. Thus make sure a context is active for the glDelete* calls
2129 context = context_acquire(This, NULL);
2130 gl_info = context->gl_info;
2132 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2134 /* Unload resources */
2135 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2137 TRACE("Deleting high order patches\n");
2138 for(i = 0; i < PATCHMAP_SIZE; i++) {
2139 struct list *e1, *e2;
2140 struct WineD3DRectPatch *patch;
2141 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2142 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2143 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2147 /* Delete the mouse cursor texture */
2148 if(This->cursorTexture) {
2150 glDeleteTextures(1, &This->cursorTexture);
2152 This->cursorTexture = 0;
2155 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2156 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2158 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2159 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2162 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2163 * private data, it might contain opengl pointers
2165 if(This->depth_blt_texture) {
2167 glDeleteTextures(1, &This->depth_blt_texture);
2169 This->depth_blt_texture = 0;
2171 if (This->depth_blt_rb) {
2173 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2175 This->depth_blt_rb = 0;
2176 This->depth_blt_rb_w = 0;
2177 This->depth_blt_rb_h = 0;
2180 /* Release the update stateblock */
2181 if (wined3d_stateblock_decref(This->updateStateBlock))
2183 if (This->updateStateBlock != This->stateBlock)
2184 FIXME("Something's still holding the update stateblock.\n");
2186 This->updateStateBlock = NULL;
2189 struct wined3d_stateblock *stateblock = This->stateBlock;
2190 This->stateBlock = NULL;
2192 /* Release the stateblock */
2193 if (wined3d_stateblock_decref(stateblock))
2194 FIXME("Something's still holding the stateblock.\n");
2197 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2198 This->blitter->free_private(This);
2199 This->frag_pipe->free_private(This);
2200 This->shader_backend->shader_free_private(This);
2202 /* Release the buffers (with sanity checks)*/
2203 if (This->onscreen_depth_stencil)
2205 surface = This->onscreen_depth_stencil;
2206 This->onscreen_depth_stencil = NULL;
2207 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2210 if (This->depth_stencil)
2212 surface = This->depth_stencil;
2214 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2216 This->depth_stencil = NULL;
2217 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2218 && surface != This->auto_depth_stencil)
2220 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2224 if (This->auto_depth_stencil)
2226 surface = This->auto_depth_stencil;
2227 This->auto_depth_stencil = NULL;
2228 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2230 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2234 for (i = 1; i < gl_info->limits.buffers; ++i)
2236 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2239 surface = This->render_targets[0];
2240 TRACE("Setting rendertarget 0 to NULL\n");
2241 This->render_targets[0] = NULL;
2242 TRACE("Releasing the render target at %p\n", surface);
2243 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2245 context_release(context);
2247 for (i = 0; i < This->NumberOfSwapChains; ++i)
2249 TRACE("Releasing the implicit swapchain %u.\n", i);
2250 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2252 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2256 HeapFree(GetProcessHeap(), 0, This->swapchains);
2257 This->swapchains = NULL;
2258 This->NumberOfSwapChains = 0;
2260 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2261 HeapFree(GetProcessHeap(), 0, This->palettes);
2262 This->palettes = NULL;
2263 This->NumberOfPalettes = 0;
2265 HeapFree(GetProcessHeap(), 0, This->render_targets);
2266 This->render_targets = NULL;
2268 This->d3d_initialized = FALSE;
2273 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2277 for (i = 0; i < This->NumberOfSwapChains; ++i)
2279 TRACE("Releasing the implicit swapchain %u.\n", i);
2280 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2282 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2286 HeapFree(GetProcessHeap(), 0, This->swapchains);
2287 This->swapchains = NULL;
2288 This->NumberOfSwapChains = 0;
2292 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2293 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2294 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2296 * There is no way to deactivate thread safety once it is enabled.
2298 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2301 /*For now just store the flag(needed in case of ddraw) */
2302 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2305 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2306 const WINED3DDISPLAYMODE* pMode) {
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2309 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2313 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2315 /* Resize the screen even without a window:
2316 * The app could have unset it with SetCooperativeLevel, but not called
2317 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2318 * but we don't have any hwnd
2321 memset(&devmode, 0, sizeof(devmode));
2322 devmode.dmSize = sizeof(devmode);
2323 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2324 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2325 devmode.dmPelsWidth = pMode->Width;
2326 devmode.dmPelsHeight = pMode->Height;
2328 devmode.dmDisplayFrequency = pMode->RefreshRate;
2329 if (pMode->RefreshRate)
2330 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2332 /* Only change the mode if necessary */
2333 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2334 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2337 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2338 if (ret != DISP_CHANGE_SUCCESSFUL)
2340 if (devmode.dmDisplayFrequency)
2342 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2343 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2344 devmode.dmDisplayFrequency = 0;
2345 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2347 if(ret != DISP_CHANGE_SUCCESSFUL) {
2348 return WINED3DERR_NOTAVAILABLE;
2352 /* Store the new values */
2353 This->ddraw_width = pMode->Width;
2354 This->ddraw_height = pMode->Height;
2355 This->ddraw_format = pMode->Format;
2357 /* And finally clip mouse to our screen */
2358 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2359 ClipCursor(&clip_rc);
2364 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2366 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2368 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2370 *wined3d = device->wined3d;
2371 wined3d_incref(*wined3d);
2373 TRACE("Returning %p.\n", *wined3d);
2378 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2381 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2382 (This->adapter->TextureRam/(1024*1024)),
2383 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2384 /* return simulated texture memory left */
2385 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2388 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2389 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 struct wined3d_stream_state *stream;
2393 struct wined3d_buffer *prev_buffer;
2395 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2396 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2398 if (StreamNumber >= MAX_STREAMS) {
2399 WARN("Stream out of range %d\n", StreamNumber);
2400 return WINED3DERR_INVALIDCALL;
2401 } else if(OffsetInBytes & 0x3) {
2402 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2403 return WINED3DERR_INVALIDCALL;
2406 stream = &This->updateStateBlock->state.streams[StreamNumber];
2407 prev_buffer = stream->buffer;
2409 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2411 if (prev_buffer == buffer
2412 && stream->stride == Stride
2413 && stream->offset == OffsetInBytes)
2415 TRACE("Application is setting the old values over, nothing to do\n");
2419 stream->buffer = buffer;
2422 stream->stride = Stride;
2423 stream->offset = OffsetInBytes;
2426 /* Handle recording of state blocks */
2427 if (This->isRecordingState) {
2428 TRACE("Recording... not performing anything\n");
2430 wined3d_buffer_incref(buffer);
2432 wined3d_buffer_decref(prev_buffer);
2438 InterlockedIncrement(&buffer->bind_count);
2439 wined3d_buffer_incref(buffer);
2443 InterlockedDecrement(&prev_buffer->bind_count);
2444 wined3d_buffer_decref(prev_buffer);
2447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2452 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2453 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2456 struct wined3d_stream_state *stream;
2458 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2459 iface, StreamNumber, buffer, pOffset, pStride);
2461 if (StreamNumber >= MAX_STREAMS)
2463 WARN("Stream out of range %d\n", StreamNumber);
2464 return WINED3DERR_INVALIDCALL;
2467 stream = &This->stateBlock->state.streams[StreamNumber];
2468 *buffer = stream->buffer;
2469 *pStride = stream->stride;
2470 if (pOffset) *pOffset = stream->offset;
2473 wined3d_buffer_incref(*buffer);
2478 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 struct wined3d_stream_state *stream;
2481 UINT old_flags, oldFreq;
2483 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2485 /* Verify input at least in d3d9 this is invalid. */
2486 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2488 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2489 return WINED3DERR_INVALIDCALL;
2491 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2493 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2494 return WINED3DERR_INVALIDCALL;
2498 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2499 return WINED3DERR_INVALIDCALL;
2502 stream = &This->updateStateBlock->state.streams[StreamNumber];
2503 old_flags = stream->flags;
2504 oldFreq = stream->frequency;
2506 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2507 stream->frequency = Divider & 0x7FFFFF;
2509 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2511 if (stream->frequency != oldFreq || stream->flags != old_flags)
2512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2517 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2519 struct wined3d_stream_state *stream;
2521 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2523 stream = &This->updateStateBlock->state.streams[StreamNumber];
2524 *Divider = stream->flags | stream->frequency;
2526 TRACE("Returning %#x.\n", *Divider);
2532 * Get / Set & Multiply Transform
2534 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 /* Most of this routine, comments included copied from ddraw tree initially: */
2538 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2540 /* Handle recording of state blocks */
2541 if (This->isRecordingState) {
2542 TRACE("Recording... not performing anything\n");
2543 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2544 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2549 * If the new matrix is the same as the current one,
2550 * we cut off any further processing. this seems to be a reasonable
2551 * optimization because as was noticed, some apps (warcraft3 for example)
2552 * tend towards setting the same matrix repeatedly for some reason.
2554 * From here on we assume that the new matrix is different, wherever it matters.
2556 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2558 TRACE("The app is setting the same matrix over again\n");
2563 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2567 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2568 where ViewMat = Camera space, WorldMat = world space.
2570 In OpenGL, camera and world space is combined into GL_MODELVIEW
2571 matrix. The Projection matrix stay projection matrix.
2574 /* Capture the times we can just ignore the change for now */
2575 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2576 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2577 /* Handled by the state manager */
2580 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2587 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2588 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2590 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2592 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2594 *matrix = device->stateBlock->state.transforms[state];
2599 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2600 const WINED3DMATRIX *mat = NULL;
2603 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2604 * below means it will be recorded in a state block change, but it
2605 * works regardless where it is recorded.
2606 * If this is found to be wrong, change to StateBlock.
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2611 if (State <= HIGHEST_TRANSFORMSTATE)
2613 mat = &This->updateStateBlock->state.transforms[State];
2617 FIXME("Unhandled transform state!!\n");
2620 multiply_matrix(&temp, mat, pMatrix);
2622 /* Apply change via set transform - will reapply to eg. lights this way */
2623 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2629 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2630 you can reference any indexes you want as long as that number max are enabled at any
2631 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2632 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2633 but when recording, just build a chain pretty much of commands to be replayed. */
2635 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2637 struct wined3d_light_info *object = NULL;
2638 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2644 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2648 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2649 return WINED3DERR_INVALIDCALL;
2652 switch(pLight->Type) {
2653 case WINED3DLIGHT_POINT:
2654 case WINED3DLIGHT_SPOT:
2655 case WINED3DLIGHT_PARALLELPOINT:
2656 case WINED3DLIGHT_GLSPOT:
2657 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2660 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2662 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2667 case WINED3DLIGHT_DIRECTIONAL:
2668 /* Ignores attenuation */
2672 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2673 return WINED3DERR_INVALIDCALL;
2676 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2678 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2679 if(object->OriginalIndex == Index) break;
2684 TRACE("Adding new light\n");
2685 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2687 ERR("Out of memory error when allocating a light\n");
2688 return E_OUTOFMEMORY;
2690 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2691 object->glIndex = -1;
2692 object->OriginalIndex = Index;
2695 /* Initialize the object */
2696 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,
2697 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2698 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2699 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2700 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2701 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2702 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2704 /* Save away the information */
2705 object->OriginalParms = *pLight;
2707 switch (pLight->Type) {
2708 case WINED3DLIGHT_POINT:
2710 object->lightPosn[0] = pLight->Position.x;
2711 object->lightPosn[1] = pLight->Position.y;
2712 object->lightPosn[2] = pLight->Position.z;
2713 object->lightPosn[3] = 1.0f;
2714 object->cutoff = 180.0f;
2718 case WINED3DLIGHT_DIRECTIONAL:
2720 object->lightPosn[0] = -pLight->Direction.x;
2721 object->lightPosn[1] = -pLight->Direction.y;
2722 object->lightPosn[2] = -pLight->Direction.z;
2723 object->lightPosn[3] = 0.0f;
2724 object->exponent = 0.0f;
2725 object->cutoff = 180.0f;
2728 case WINED3DLIGHT_SPOT:
2730 object->lightPosn[0] = pLight->Position.x;
2731 object->lightPosn[1] = pLight->Position.y;
2732 object->lightPosn[2] = pLight->Position.z;
2733 object->lightPosn[3] = 1.0f;
2736 object->lightDirn[0] = pLight->Direction.x;
2737 object->lightDirn[1] = pLight->Direction.y;
2738 object->lightDirn[2] = pLight->Direction.z;
2739 object->lightDirn[3] = 1.0f;
2742 * opengl-ish and d3d-ish spot lights use too different models for the
2743 * light "intensity" as a function of the angle towards the main light direction,
2744 * so we only can approximate very roughly.
2745 * however spot lights are rather rarely used in games (if ever used at all).
2746 * furthermore if still used, probably nobody pays attention to such details.
2748 if (!pLight->Falloff)
2750 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2751 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2752 * will always be 1.0 for both of them, and we don't have to care for the
2753 * rest of the rather complex calculation
2755 object->exponent = 0.0f;
2757 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2758 if (rho < 0.0001f) rho = 0.0001f;
2759 object->exponent = -0.3f/logf(cosf(rho/2));
2761 if (object->exponent > 128.0f)
2763 object->exponent = 128.0f;
2765 object->cutoff = (float) (pLight->Phi*90/M_PI);
2771 FIXME("Unrecognized light type %d\n", pLight->Type);
2774 /* Update the live definitions if the light is currently assigned a glIndex */
2775 if (object->glIndex != -1 && !This->isRecordingState) {
2776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2781 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2783 struct wined3d_light_info *lightInfo = NULL;
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2787 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2789 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2791 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2792 if(lightInfo->OriginalIndex == Index) break;
2798 TRACE("Light information requested but light not defined\n");
2799 return WINED3DERR_INVALIDCALL;
2802 *pLight = lightInfo->OriginalParms;
2807 * Get / Set Light Enable
2808 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2810 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2812 struct wined3d_light_info *lightInfo = NULL;
2813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2816 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2818 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2820 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2821 if(lightInfo->OriginalIndex == Index) break;
2824 TRACE("Found light: %p\n", lightInfo);
2826 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2829 TRACE("Light enabled requested but light not defined, so defining one!\n");
2830 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2832 /* Search for it again! Should be fairly quick as near head of list */
2833 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2835 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2836 if(lightInfo->OriginalIndex == Index) break;
2841 FIXME("Adding default lights has failed dismally\n");
2842 return WINED3DERR_INVALIDCALL;
2847 if(lightInfo->glIndex != -1) {
2848 if(!This->isRecordingState) {
2849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2852 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2853 lightInfo->glIndex = -1;
2855 TRACE("Light already disabled, nothing to do\n");
2857 lightInfo->enabled = FALSE;
2859 lightInfo->enabled = TRUE;
2860 if (lightInfo->glIndex != -1) {
2862 TRACE("Nothing to do as light was enabled\n");
2865 /* Find a free gl light */
2866 for (i = 0; i < This->maxConcurrentLights; ++i)
2868 if (!This->updateStateBlock->state.lights[i])
2870 This->updateStateBlock->state.lights[i] = lightInfo;
2871 lightInfo->glIndex = i;
2875 if(lightInfo->glIndex == -1) {
2876 /* Our tests show that Windows returns D3D_OK in this situation, even with
2877 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2878 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2879 * as well for those lights.
2881 * TODO: Test how this affects rendering
2883 WARN("Too many concurrently active lights\n");
2887 /* i == lightInfo->glIndex */
2888 if(!This->isRecordingState) {
2889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2897 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2899 struct wined3d_light_info *lightInfo = NULL;
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2903 TRACE("(%p) : for idx(%d)\n", This, Index);
2905 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2907 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2908 if(lightInfo->OriginalIndex == Index) break;
2914 TRACE("Light enabled state requested but light not defined\n");
2915 return WINED3DERR_INVALIDCALL;
2917 /* true is 128 according to SetLightEnable */
2918 *pEnable = lightInfo->enabled ? 128 : 0;
2923 * Get / Set Clip Planes
2925 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2927 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2929 /* Validate Index */
2930 if (Index >= This->adapter->gl_info.limits.clipplanes)
2932 TRACE("Application has requested clipplane this device doesn't support\n");
2933 return WINED3DERR_INVALIDCALL;
2936 This->updateStateBlock->changed.clipplane |= 1 << Index;
2938 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2939 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2940 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2941 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2943 TRACE("Application is setting old values over, nothing to do\n");
2947 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2948 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2949 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2950 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2952 /* Handle recording of state blocks */
2953 if (This->isRecordingState) {
2954 TRACE("Recording... not performing anything\n");
2958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 TRACE("(%p) : for idx %d\n", This, Index);
2967 /* Validate Index */
2968 if (Index >= This->adapter->gl_info.limits.clipplanes)
2970 TRACE("Application has requested clipplane this device doesn't support\n");
2971 return WINED3DERR_INVALIDCALL;
2974 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2975 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2976 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2977 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2982 * Get / Set Clip Plane Status
2983 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 FIXME("(%p) : stub\n", This);
2990 return WINED3DERR_INVALIDCALL;
2992 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2993 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2997 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 FIXME("(%p) : stub\n", This);
3002 return WINED3DERR_INVALIDCALL;
3004 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3005 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3010 * Get / Set Material
3012 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 This->updateStateBlock->changed.material = TRUE;
3016 This->updateStateBlock->state.material = *pMaterial;
3018 /* Handle recording of state blocks */
3019 if (This->isRecordingState) {
3020 TRACE("Recording... not performing anything\n");
3024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 *pMaterial = This->updateStateBlock->state.material;
3031 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3032 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3033 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3034 pMaterial->Ambient.b, pMaterial->Ambient.a);
3035 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3036 pMaterial->Specular.b, pMaterial->Specular.a);
3037 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3038 pMaterial->Emissive.b, pMaterial->Emissive.a);
3039 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3048 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 struct wined3d_buffer *prev_buffer;
3053 TRACE("iface %p, buffer %p, format %s.\n",
3054 iface, buffer, debug_d3dformat(fmt));
3056 prev_buffer = This->updateStateBlock->state.index_buffer;
3058 This->updateStateBlock->changed.indices = TRUE;
3059 This->updateStateBlock->state.index_buffer = buffer;
3060 This->updateStateBlock->state.index_format = fmt;
3062 /* Handle recording of state blocks */
3063 if (This->isRecordingState) {
3064 TRACE("Recording... not performing anything\n");
3066 wined3d_buffer_incref(buffer);
3068 wined3d_buffer_decref(prev_buffer);
3072 if (prev_buffer != buffer)
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3077 InterlockedIncrement(&buffer->bind_count);
3078 wined3d_buffer_incref(buffer);
3082 InterlockedDecrement(&prev_buffer->bind_count);
3083 wined3d_buffer_decref(prev_buffer);
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 TRACE("iface %p, buffer %p.\n", iface, buffer);
3096 *buffer = This->stateBlock->state.index_buffer;
3099 wined3d_buffer_incref(*buffer);
3101 TRACE("Returning %p.\n", *buffer);
3106 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3107 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 TRACE("(%p)->(%d)\n", This, BaseIndex);
3111 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3113 TRACE("Application is setting the old value over, nothing to do\n");
3117 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3119 if (This->isRecordingState) {
3120 TRACE("Recording... not performing anything\n");
3123 /* The base vertex index affects the stream sources */
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p) : base_index %p\n", This, base_index);
3132 *base_index = This->stateBlock->state.base_vertex_index;
3134 TRACE("Returning %u\n", *base_index);
3140 * Get / Set Viewports
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p)\n", This);
3146 This->updateStateBlock->changed.viewport = TRUE;
3147 This->updateStateBlock->state.viewport = *pViewport;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3155 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3156 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 TRACE("(%p)\n", This);
3166 *pViewport = This->stateBlock->state.viewport;
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3171 WINED3DRENDERSTATETYPE State, DWORD Value)
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 DWORD oldValue = This->stateBlock->state.render_states[State];
3176 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3178 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3179 This->updateStateBlock->state.render_states[State] = Value;
3181 /* Handle recording of state blocks */
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3187 /* Compared here and not before the assignment to allow proper stateblock recording */
3188 if(Value == oldValue) {
3189 TRACE("Application is setting the old value over, nothing to do\n");
3191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3197 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3198 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3204 *pValue = This->stateBlock->state.render_states[State];
3209 * Get / Set Sampler States
3210 * TODO: Verify against dx9 definitions
3213 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3218 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3220 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3221 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3224 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3226 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3227 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3230 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3231 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3232 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3234 /* Handle recording of state blocks */
3235 if (This->isRecordingState) {
3236 TRACE("Recording... not performing anything\n");
3240 if(oldValue == Value) {
3241 TRACE("Application is setting the old value over, nothing to do\n");
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3254 This, Sampler, debug_d3dsamplerstate(Type), Type);
3256 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3257 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3260 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3262 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3263 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3265 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3266 TRACE("(%p) : Returning %#x\n", This, *Value);
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 This->updateStateBlock->changed.scissorRect = TRUE;
3275 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3277 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3280 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3282 if(This->isRecordingState) {
3283 TRACE("Recording... not performing anything\n");
3287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3292 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 *pRect = This->updateStateBlock->state.scissor_rect;
3296 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3300 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3301 struct wined3d_vertex_declaration *pDecl)
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3304 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3306 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3309 wined3d_vertex_declaration_incref(pDecl);
3311 wined3d_vertex_declaration_decref(oldDecl);
3313 This->updateStateBlock->state.vertex_declaration = pDecl;
3314 This->updateStateBlock->changed.vertexDecl = TRUE;
3316 if (This->isRecordingState) {
3317 TRACE("Recording... not performing anything\n");
3319 } else if(pDecl == oldDecl) {
3320 /* Checked after the assignment to allow proper stateblock recording */
3321 TRACE("Application is setting the old declaration over, nothing to do\n");
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3329 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3330 struct wined3d_vertex_declaration **ppDecl)
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3336 *ppDecl = This->stateBlock->state.vertex_declaration;
3338 wined3d_vertex_declaration_incref(*ppDecl);
3343 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3345 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3346 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
3348 device->updateStateBlock->state.vertex_shader = shader;
3349 device->updateStateBlock->changed.vertexShader = TRUE;
3351 if (device->isRecordingState)
3354 wined3d_shader_incref(shader);
3356 wined3d_shader_decref(prev);
3357 TRACE("Recording... not performing anything.\n");
3360 else if(prev == shader)
3362 /* Checked here to allow proper stateblock recording */
3363 TRACE("App is setting the old shader over, nothing to do.\n");
3367 TRACE("(%p) : setting shader(%p)\n", device, shader);
3369 wined3d_shader_incref(shader);
3371 wined3d_shader_decref(prev);
3373 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VSHADER);
3378 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3380 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3381 struct wined3d_shader *shader;
3383 TRACE("iface %p.\n", iface);
3385 shader = device->stateBlock->state.vertex_shader;
3387 wined3d_shader_incref(shader);
3389 TRACE("Returning %p.\n", shader);
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3394 IWineD3DDevice *iface,
3396 CONST BOOL *srcData,
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3402 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3403 iface, srcData, start, count);
3405 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3407 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3408 for (i = 0; i < cnt; i++)
3409 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3411 for (i = start; i < cnt + start; ++i) {
3412 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3415 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3420 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3421 IWineD3DDevice *iface,
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3427 int cnt = min(count, MAX_CONST_B - start);
3429 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3430 iface, dstData, start, count);
3432 if (!dstData || cnt < 0)
3433 return WINED3DERR_INVALIDCALL;
3435 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3439 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3440 IWineD3DDevice *iface,
3445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3446 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3448 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3449 iface, srcData, start, count);
3451 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3453 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3454 for (i = 0; i < cnt; i++)
3455 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3456 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3458 for (i = start; i < cnt + start; ++i) {
3459 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3462 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3467 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3468 IWineD3DDevice *iface,
3473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3474 int cnt = min(count, MAX_CONST_I - start);
3476 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3477 iface, dstData, start, count);
3479 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3480 return WINED3DERR_INVALIDCALL;
3482 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3486 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3487 IWineD3DDevice *iface,
3489 CONST float *srcData,
3492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3495 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3496 iface, srcData, start, count);
3498 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3499 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3500 return WINED3DERR_INVALIDCALL;
3502 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3504 for (i = 0; i < count; i++)
3505 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3506 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3509 if (!This->isRecordingState)
3511 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3515 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3516 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3521 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3522 IWineD3DDevice *iface,
3527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3528 int cnt = min(count, This->d3d_vshader_constantF - start);
3530 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3531 iface, dstData, start, count);
3533 if (!dstData || cnt < 0)
3534 return WINED3DERR_INVALIDCALL;
3536 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3540 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3542 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3548 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3550 DWORD i = This->rev_tex_unit_map[unit];
3551 DWORD j = This->texUnitMap[stage];
3553 This->texUnitMap[stage] = unit;
3554 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3556 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3559 This->rev_tex_unit_map[unit] = stage;
3560 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3562 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3566 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3569 This->fixed_function_usage_map = 0;
3570 for (i = 0; i < MAX_TEXTURES; ++i)
3572 const struct wined3d_state *state = &This->stateBlock->state;
3573 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3574 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3575 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3576 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3577 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3578 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3579 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3580 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3582 if (color_op == WINED3DTOP_DISABLE) {
3583 /* Not used, and disable higher stages */
3587 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3588 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3589 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3590 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3591 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3592 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3593 This->fixed_function_usage_map |= (1 << i);
3596 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3597 This->fixed_function_usage_map |= (1 << (i + 1));
3602 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3604 unsigned int i, tex;
3607 device_update_fixed_function_usage_map(This);
3608 ffu_map = This->fixed_function_usage_map;
3610 if (This->max_ffp_textures == gl_info->limits.texture_stages
3611 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3613 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3615 if (!(ffu_map & 1)) continue;
3617 if (This->texUnitMap[i] != i) {
3618 device_map_stage(This, i, i);
3619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3620 markTextureStagesDirty(This, i);
3626 /* Now work out the mapping */
3628 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3630 if (!(ffu_map & 1)) continue;
3632 if (This->texUnitMap[i] != tex) {
3633 device_map_stage(This, i, tex);
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3635 markTextureStagesDirty(This, i);
3642 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3644 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3645 This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3648 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3649 if (sampler_type[i] && This->texUnitMap[i] != i)
3651 device_map_stage(This, i, i);
3652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3653 if (i < gl_info->limits.texture_stages)
3655 markTextureStagesDirty(This, i);
3661 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3662 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3664 DWORD current_mapping = This->rev_tex_unit_map[unit];
3666 /* Not currently used */
3667 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3669 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3670 /* Used by a fragment sampler */
3672 if (!pshader_sampler_tokens) {
3673 /* No pixel shader, check fixed function */
3674 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3677 /* Pixel shader, check the shader's sampler map */
3678 return !pshader_sampler_tokens[current_mapping];
3681 /* Used by a vertex sampler */
3682 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3685 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3687 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3688 This->stateBlock->state.vertex_shader->reg_maps.sampler_type;
3689 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3690 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3695 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3696 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3697 pshader_sampler_type = This->stateBlock->state.pixel_shader->reg_maps.sampler_type;
3700 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3701 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3702 if (vshader_sampler_type[i])
3704 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3706 /* Already mapped somewhere */
3710 while (start >= 0) {
3711 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3713 device_map_stage(This, vsampler_idx, start);
3714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3726 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3728 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3729 const struct wined3d_state *state = &This->stateBlock->state;
3730 BOOL vs = use_vs(state);
3731 BOOL ps = use_ps(state);
3734 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3735 * that would be really messy and require shader recompilation
3736 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3737 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3739 if (ps) device_map_psamplers(This, gl_info);
3740 else device_map_fixed_function_samplers(This, gl_info);
3742 if (vs) device_map_vsamplers(This, ps, gl_info);
3745 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, struct wined3d_shader *shader)
3747 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3748 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
3750 device->updateStateBlock->state.pixel_shader = shader;
3751 device->updateStateBlock->changed.pixelShader = TRUE;
3753 /* Handle recording of state blocks */
3754 if (device->isRecordingState)
3755 TRACE("Recording... not performing anything\n");
3757 if (device->isRecordingState)
3759 TRACE("Recording... not performing anything.\n");
3761 wined3d_shader_incref(shader);
3763 wined3d_shader_decref(prev);
3769 TRACE("App is setting the old pixel shader over, nothing to do.\n");
3774 wined3d_shader_incref(shader);
3776 wined3d_shader_decref(prev);
3778 TRACE("Setting shader %p.\n", shader);
3779 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_PIXELSHADER);
3784 static struct wined3d_shader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3786 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3787 struct wined3d_shader *shader;
3789 TRACE("iface %p.\n", iface);
3791 shader = device->stateBlock->state.pixel_shader;
3793 wined3d_shader_incref(shader);
3795 TRACE("Returning %p.\n", shader);
3799 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3800 IWineD3DDevice *iface,
3802 CONST BOOL *srcData,
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3808 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3809 iface, srcData, start, count);
3811 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3813 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3814 for (i = 0; i < cnt; i++)
3815 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3817 for (i = start; i < cnt + start; ++i) {
3818 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3821 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3826 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3827 IWineD3DDevice *iface,
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 int cnt = min(count, MAX_CONST_B - start);
3835 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3836 iface, dstData, start, count);
3838 if (!dstData || cnt < 0)
3839 return WINED3DERR_INVALIDCALL;
3841 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3845 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3846 IWineD3DDevice *iface,
3851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3852 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3854 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3855 iface, srcData, start, count);
3857 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3859 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3860 for (i = 0; i < cnt; i++)
3861 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3862 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3864 for (i = start; i < cnt + start; ++i) {
3865 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3868 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3874 IWineD3DDevice *iface,
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 int cnt = min(count, MAX_CONST_I - start);
3882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3883 iface, dstData, start, count);
3885 if (!dstData || cnt < 0)
3886 return WINED3DERR_INVALIDCALL;
3888 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3892 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3893 IWineD3DDevice *iface,
3895 CONST float *srcData,
3898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3902 iface, srcData, start, count);
3904 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3905 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3906 return WINED3DERR_INVALIDCALL;
3908 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3910 for (i = 0; i < count; i++)
3911 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3912 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3915 if (!This->isRecordingState)
3917 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3921 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3922 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3927 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3928 IWineD3DDevice *iface,
3933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3934 int cnt = min(count, This->d3d_pshader_constantF - start);
3936 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3937 iface, dstData, start, count);
3939 if (!dstData || cnt < 0)
3940 return WINED3DERR_INVALIDCALL;
3942 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3946 /* Context activation is done by the caller. */
3947 /* Do not call while under the GL lock. */
3948 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3949 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3950 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3953 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3954 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3957 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3961 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3963 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3966 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3968 ERR("Source has no position mask\n");
3969 return WINED3DERR_INVALIDCALL;
3972 if (!dest->resource.allocatedMemory)
3973 buffer_get_sysmem(dest, gl_info);
3975 /* Get a pointer into the destination vbo(create one if none exists) and
3976 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3978 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3980 dest->flags |= WINED3D_BUFFER_CREATEBO;
3981 wined3d_buffer_preload(dest);
3984 if (dest->buffer_object)
3986 unsigned char extrabytes = 0;
3987 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3988 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3989 * this may write 4 extra bytes beyond the area that should be written
3991 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3992 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3993 if(!dest_conv_addr) {
3994 ERR("Out of memory\n");
3995 /* Continue without storing converted vertices */
3997 dest_conv = dest_conv_addr;
4000 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
4002 static BOOL warned = FALSE;
4004 * The clipping code is not quite correct. Some things need
4005 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4006 * so disable clipping for now.
4007 * (The graphics in Half-Life are broken, and my processvertices
4008 * test crashes with IDirect3DDevice3)
4014 FIXME("Clipping is broken and disabled for now\n");
4016 } else doClip = FALSE;
4017 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4019 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4022 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4023 WINED3DTS_PROJECTION,
4025 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4026 WINED3DTS_WORLDMATRIX(0),
4029 TRACE("View mat:\n");
4030 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);
4031 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);
4032 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);
4033 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);
4035 TRACE("Proj mat:\n");
4036 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);
4037 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);
4038 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);
4039 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);
4041 TRACE("World mat:\n");
4042 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);
4043 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);
4044 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);
4045 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);
4047 /* Get the viewport */
4048 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4049 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4050 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4052 multiply_matrix(&mat,&view_mat,&world_mat);
4053 multiply_matrix(&mat,&proj_mat,&mat);
4055 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4057 for (i = 0; i < dwCount; i+= 1) {
4058 unsigned int tex_index;
4060 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4061 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4062 /* The position first */
4063 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4064 const float *p = (const float *)(element->data + i * element->stride);
4066 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4068 /* Multiplication with world, view and projection matrix */
4069 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);
4070 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);
4071 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);
4072 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);
4074 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4076 /* WARNING: The following things are taken from d3d7 and were not yet checked
4077 * against d3d8 or d3d9!
4080 /* Clipping conditions: From msdn
4082 * A vertex is clipped if it does not match the following requirements
4086 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4088 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4089 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4094 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4095 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4098 /* "Normal" viewport transformation (not clipped)
4099 * 1) The values are divided by rhw
4100 * 2) The y axis is negative, so multiply it with -1
4101 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4102 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4103 * 4) Multiply x with Width/2 and add Width/2
4104 * 5) The same for the height
4105 * 6) Add the viewpoint X and Y to the 2D coordinates and
4106 * The minimum Z value to z
4107 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4109 * Well, basically it's simply a linear transformation into viewport
4121 z *= vp.MaxZ - vp.MinZ;
4123 x += vp.Width / 2 + vp.X;
4124 y += vp.Height / 2 + vp.Y;
4129 /* That vertex got clipped
4130 * Contrary to OpenGL it is not dropped completely, it just
4131 * undergoes a different calculation.
4133 TRACE("Vertex got clipped\n");
4140 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4141 * outside of the main vertex buffer memory. That needs some more
4146 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4149 ( (float *) dest_ptr)[0] = x;
4150 ( (float *) dest_ptr)[1] = y;
4151 ( (float *) dest_ptr)[2] = z;
4152 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4154 dest_ptr += 3 * sizeof(float);
4156 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4157 dest_ptr += sizeof(float);
4162 ( (float *) dest_conv)[0] = x * w;
4163 ( (float *) dest_conv)[1] = y * w;
4164 ( (float *) dest_conv)[2] = z * w;
4165 ( (float *) dest_conv)[3] = w;
4167 dest_conv += 3 * sizeof(float);
4169 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4170 dest_conv += sizeof(float);
4174 if (DestFVF & WINED3DFVF_PSIZE) {
4175 dest_ptr += sizeof(DWORD);
4176 if(dest_conv) dest_conv += sizeof(DWORD);
4178 if (DestFVF & WINED3DFVF_NORMAL) {
4179 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4180 const float *normal = (const float *)(element->data + i * element->stride);
4181 /* AFAIK this should go into the lighting information */
4182 FIXME("Didn't expect the destination to have a normal\n");
4183 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4185 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4189 if (DestFVF & WINED3DFVF_DIFFUSE) {
4190 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4191 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4192 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4194 static BOOL warned = FALSE;
4197 ERR("No diffuse color in source, but destination has one\n");
4201 *( (DWORD *) dest_ptr) = 0xffffffff;
4202 dest_ptr += sizeof(DWORD);
4205 *( (DWORD *) dest_conv) = 0xffffffff;
4206 dest_conv += sizeof(DWORD);
4210 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4212 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4213 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4214 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4215 dest_conv += sizeof(DWORD);
4220 if (DestFVF & WINED3DFVF_SPECULAR)
4222 /* What's the color value in the feedback buffer? */
4223 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4224 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4225 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4227 static BOOL warned = FALSE;
4230 ERR("No specular color in source, but destination has one\n");
4234 *( (DWORD *) dest_ptr) = 0xFF000000;
4235 dest_ptr += sizeof(DWORD);
4238 *( (DWORD *) dest_conv) = 0xFF000000;
4239 dest_conv += sizeof(DWORD);
4243 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4245 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4246 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4247 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4248 dest_conv += sizeof(DWORD);
4253 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4254 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4255 const float *tex_coord = (const float *)(element->data + i * element->stride);
4256 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4258 ERR("No source texture, but destination requests one\n");
4259 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4260 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4263 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4265 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4275 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4276 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4277 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4278 dwCount * get_flexible_vertex_size(DestFVF),
4280 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4284 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4289 #undef copy_and_next
4291 /* Do not call while under the GL lock. */
4292 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4293 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4294 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4297 struct wined3d_stream_info stream_info;
4298 const struct wined3d_gl_info *gl_info;
4299 struct wined3d_context *context;
4300 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4303 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4306 ERR("Output vertex declaration not implemented yet\n");
4309 /* Need any context to write to the vbo. */
4310 context = context_acquire(This, NULL);
4311 gl_info = context->gl_info;
4313 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4314 * control the streamIsUP flag, thus restore it afterwards.
4316 This->stateBlock->state.user_stream = FALSE;
4317 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4318 This->stateBlock->state.user_stream = streamWasUP;
4320 if(vbo || SrcStartIndex) {
4322 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4323 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4325 * Also get the start index in, but only loop over all elements if there's something to add at all.
4327 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4329 struct wined3d_stream_info_element *e;
4331 if (!(stream_info.use_map & (1 << i))) continue;
4333 e = &stream_info.elements[i];
4334 if (e->buffer_object)
4336 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4337 e->buffer_object = 0;
4338 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4340 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4341 vb->buffer_object = 0;
4344 if (e->data) e->data += e->stride * SrcStartIndex;
4348 hr = process_vertices_strided(This, DestIndex, VertexCount,
4349 &stream_info, dst_buffer, flags, DestFVF);
4351 context_release(context);
4357 * Get / Set Texture Stage States
4358 * TODO: Verify against dx9 definitions
4360 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4363 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4366 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4368 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4370 WARN("Invalid Type %d passed.\n", Type);
4374 if (Stage >= gl_info->limits.texture_stages)
4376 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4377 Stage, gl_info->limits.texture_stages - 1);
4381 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4382 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4383 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4385 if (This->isRecordingState) {
4386 TRACE("Recording... not performing anything\n");
4390 /* Checked after the assignments to allow proper stateblock recording */
4391 if(oldValue == Value) {
4392 TRACE("App is setting the old value over, nothing to do\n");
4396 if (Stage > This->stateBlock->state.lowest_disabled_stage
4397 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4398 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4400 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4401 * Changes in other states are important on disabled stages too
4406 if(Type == WINED3DTSS_COLOROP) {
4409 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4410 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4411 * they have to be disabled
4413 * The current stage is dirtified below.
4415 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4417 TRACE("Additionally dirtifying stage %u\n", i);
4418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4420 This->stateBlock->state.lowest_disabled_stage = Stage;
4421 TRACE("New lowest disabled: %u\n", Stage);
4422 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4423 /* Previously disabled stage enabled. Stages above it may need enabling
4424 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4425 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4427 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4430 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4432 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4434 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4437 This->stateBlock->state.lowest_disabled_stage = i;
4438 TRACE("New lowest disabled: %u\n", i);
4442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4447 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 TRACE("iface %p, stage %u, state %s, value %p.\n",
4452 iface, Stage, debug_d3dtexturestate(Type), pValue);
4454 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4456 WARN("Invalid Type %d passed.\n", Type);
4460 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4461 TRACE("Returning %#x.\n", *pValue);
4466 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4467 DWORD stage, struct wined3d_texture *texture)
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4471 struct wined3d_texture *prev;
4473 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4475 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4476 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4478 /* Windows accepts overflowing this array... we do not. */
4479 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4481 WARN("Ignoring invalid stage %u.\n", stage);
4485 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4486 if (texture && texture->resource.pool == WINED3DPOOL_SCRATCH)
4488 WARN("Rejecting attempt to set scratch texture.\n");
4489 return WINED3DERR_INVALIDCALL;
4492 This->updateStateBlock->changed.textures |= 1 << stage;
4494 prev = This->updateStateBlock->state.textures[stage];
4495 TRACE("Previous texture %p.\n", prev);
4497 if (texture == prev)
4499 TRACE("App is setting the same texture again, nothing to do.\n");
4503 TRACE("Setting new texture to %p.\n", texture);
4504 This->updateStateBlock->state.textures[stage] = texture;
4506 if (This->isRecordingState)
4508 TRACE("Recording... not performing anything\n");
4510 if (texture) wined3d_texture_incref(texture);
4511 if (prev) wined3d_texture_decref(prev);
4518 LONG bind_count = InterlockedIncrement(&texture->bind_count);
4520 wined3d_texture_incref(texture);
4522 if (!prev || texture->target != prev->target)
4523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4525 if (!prev && stage < gl_info->limits.texture_stages)
4527 /* The source arguments for color and alpha ops have different
4528 * meanings when a NULL texture is bound, so the COLOROP and
4529 * ALPHAOP have to be dirtified. */
4530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4534 if (bind_count == 1)
4535 texture->sampler = stage;
4540 LONG bind_count = InterlockedDecrement(&prev->bind_count);
4542 wined3d_texture_decref(prev);
4544 if (!texture && stage < gl_info->limits.texture_stages)
4546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4550 if (bind_count && prev->sampler == stage)
4554 /* Search for other stages the texture is bound to. Shouldn't
4555 * happen if applications bind textures to a single stage only. */
4556 TRACE("Searching for other stages the texture is bound to.\n");
4557 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4559 if (This->updateStateBlock->state.textures[i] == prev)
4561 TRACE("Texture is also bound to stage %u.\n", i);
4569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4574 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface,
4575 DWORD stage, struct wined3d_texture **texture)
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4581 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4582 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4584 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4586 WARN("Current stage overflows textures array (stage %u).\n", stage);
4587 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4590 *texture = This->stateBlock->state.textures[stage];
4592 wined3d_texture_incref(*texture);
4594 TRACE("Returning %p.\n", *texture);
4602 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4603 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4605 IWineD3DSwapChain *swapchain;
4608 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4609 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4611 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4614 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4618 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4619 IWineD3DSwapChain_Release(swapchain);
4622 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4629 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4631 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4633 TRACE("iface %p, caps %p.\n", iface, caps);
4635 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4640 IWineD3DSwapChain *swapChain;
4643 if(iSwapChain > 0) {
4644 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4645 if (hr == WINED3D_OK) {
4646 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4647 IWineD3DSwapChain_Release(swapChain);
4649 FIXME("(%p) Error getting display mode\n", This);
4652 /* Don't read the real display mode,
4653 but return the stored mode instead. X11 can't change the color
4654 depth, and some apps are pretty angry if they SetDisplayMode from
4655 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4657 Also don't relay to the swapchain because with ddraw it's possible
4658 that there isn't a swapchain at all */
4659 pMode->Width = This->ddraw_width;
4660 pMode->Height = This->ddraw_height;
4661 pMode->Format = This->ddraw_format;
4662 pMode->RefreshRate = 0;
4670 * Stateblock related functions
4673 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4676 struct wined3d_stateblock *stateblock;
4679 TRACE("(%p)\n", This);
4681 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4683 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4684 if (FAILED(hr)) return hr;
4686 wined3d_stateblock_decref(This->updateStateBlock);
4687 This->updateStateBlock = stateblock;
4688 This->isRecordingState = TRUE;
4690 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4695 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4696 struct wined3d_stateblock **stateblock)
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 struct wined3d_stateblock *object = This->updateStateBlock;
4701 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4703 if (!This->isRecordingState) {
4704 WARN("(%p) not recording! returning error\n", This);
4706 return WINED3DERR_INVALIDCALL;
4709 stateblock_init_contained_states(object);
4711 *stateblock = object;
4712 This->isRecordingState = FALSE;
4713 This->updateStateBlock = This->stateBlock;
4714 wined3d_stateblock_incref(This->updateStateBlock);
4716 TRACE("Returning stateblock %p.\n", *stateblock);
4722 * Scene related functions
4724 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4725 /* At the moment we have no need for any functionality at the beginning
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4728 TRACE("(%p)\n", This);
4731 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4732 return WINED3DERR_INVALIDCALL;
4734 This->inScene = TRUE;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 struct wined3d_context *context;
4743 TRACE("(%p)\n", This);
4745 if(!This->inScene) {
4746 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4747 return WINED3DERR_INVALIDCALL;
4750 context = context_acquire(This, NULL);
4751 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4753 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4755 context_release(context);
4757 This->inScene = FALSE;
4761 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4762 const RECT *pSourceRect, const RECT *pDestRect,
4763 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4765 IWineD3DSwapChain *swapChain = NULL;
4767 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4769 TRACE("iface %p.\n", iface);
4771 for(i = 0 ; i < swapchains ; i ++) {
4773 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4774 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4775 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4776 IWineD3DSwapChain_Release(swapChain);
4782 /* Do not call while under the GL lock. */
4783 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4784 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4786 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4787 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4790 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4791 iface, rect_count, rects, flags, color, depth, stencil);
4793 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4795 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4798 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4799 /* TODO: What about depth stencil buffers without stencil bits? */
4800 return WINED3DERR_INVALIDCALL;
4802 else if (flags & WINED3DCLEAR_TARGET)
4804 if(ds->resource.width < device->render_targets[0]->resource.width ||
4805 ds->resource.height < device->render_targets[0]->resource.height)
4807 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4813 device_get_draw_rect(device, &draw_rect);
4815 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4816 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4823 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4824 WINED3DPRIMITIVETYPE primitive_type)
4826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4828 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4830 This->updateStateBlock->changed.primitive_type = TRUE;
4831 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4834 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4835 WINED3DPRIMITIVETYPE *primitive_type)
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4839 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4841 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4843 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4846 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4850 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4852 if (!This->stateBlock->state.vertex_declaration)
4854 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4855 return WINED3DERR_INVALIDCALL;
4858 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4859 if (This->stateBlock->state.user_stream)
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4862 This->stateBlock->state.user_stream = FALSE;
4865 if (This->stateBlock->state.load_base_vertex_index)
4867 This->stateBlock->state.load_base_vertex_index = 0;
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4870 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4871 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4875 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4878 struct wined3d_buffer *index_buffer;
4882 index_buffer = This->stateBlock->state.index_buffer;
4885 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4886 * without an index buffer set. (The first time at least...)
4887 * D3D8 simply dies, but I doubt it can do much harm to return
4888 * D3DERR_INVALIDCALL there as well. */
4889 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4890 return WINED3DERR_INVALIDCALL;
4893 if (!This->stateBlock->state.vertex_declaration)
4895 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4896 return WINED3DERR_INVALIDCALL;
4899 if (This->stateBlock->state.user_stream)
4901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4902 This->stateBlock->state.user_stream = FALSE;
4904 vbo = index_buffer->buffer_object;
4906 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4908 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4913 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4915 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4919 drawPrimitive(This, index_count, startIndex, idxStride,
4920 vbo ? NULL : index_buffer->resource.allocatedMemory);
4925 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4926 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4929 struct wined3d_stream_state *stream;
4930 struct wined3d_buffer *vb;
4932 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4933 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4935 if (!This->stateBlock->state.vertex_declaration)
4937 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4938 return WINED3DERR_INVALIDCALL;
4941 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4942 stream = &This->stateBlock->state.streams[0];
4943 vb = stream->buffer;
4944 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4946 wined3d_buffer_decref(vb);
4948 stream->stride = VertexStreamZeroStride;
4949 This->stateBlock->state.user_stream = TRUE;
4950 This->stateBlock->state.load_base_vertex_index = 0;
4952 /* TODO: Only mark dirty if drawing from a different UP address */
4953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4955 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4957 /* MSDN specifies stream zero settings must be set to NULL */
4958 stream->buffer = NULL;
4961 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4962 * the new stream sources or use UP drawing again
4967 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4968 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4969 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 struct wined3d_stream_state *stream;
4974 struct wined3d_buffer *vb, *ib;
4976 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4977 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4979 if (!This->stateBlock->state.vertex_declaration)
4981 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4982 return WINED3DERR_INVALIDCALL;
4985 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4991 stream = &This->stateBlock->state.streams[0];
4992 vb = stream->buffer;
4993 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4995 wined3d_buffer_decref(vb);
4997 stream->stride = VertexStreamZeroStride;
4998 This->stateBlock->state.user_stream = TRUE;
5000 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5001 This->stateBlock->state.base_vertex_index = 0;
5002 This->stateBlock->state.load_base_vertex_index = 0;
5003 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5007 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
5009 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5010 stream->buffer = NULL;
5012 ib = This->stateBlock->state.index_buffer;
5015 wined3d_buffer_decref(ib);
5016 This->stateBlock->state.index_buffer = NULL;
5018 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5019 * SetStreamSource to specify a vertex buffer
5025 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5026 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5030 /* Mark the state dirty until we have nicer tracking
5031 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5036 This->stateBlock->state.base_vertex_index = 0;
5037 This->up_strided = DrawPrimStrideData;
5038 drawPrimitive(This, vertex_count, 0, 0, NULL);
5039 This->up_strided = NULL;
5043 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5044 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5045 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5048 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5050 /* Mark the state dirty until we have nicer tracking
5051 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5056 This->stateBlock->state.user_stream = TRUE;
5057 This->stateBlock->state.base_vertex_index = 0;
5058 This->up_strided = DrawPrimStrideData;
5059 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5060 This->up_strided = NULL;
5064 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5065 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5066 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5068 WINED3DLOCKED_BOX src;
5069 WINED3DLOCKED_BOX dst;
5072 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5073 iface, pSourceVolume, pDestinationVolume);
5075 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5076 * dirtification to improve loading performance.
5078 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5079 if (FAILED(hr)) return hr;
5080 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5083 IWineD3DVolume_Unmap(pSourceVolume);
5087 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5089 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5091 IWineD3DVolume_Unmap(pSourceVolume);
5093 hr = IWineD3DVolume_Unmap(pSourceVolume);
5098 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5099 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
5101 unsigned int level_count, i;
5102 WINED3DRESOURCETYPE type;
5105 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5107 /* Verify that the source and destination textures are non-NULL. */
5108 if (!src_texture || !dst_texture)
5110 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5111 return WINED3DERR_INVALIDCALL;
5114 if (src_texture == dst_texture)
5116 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5117 return WINED3DERR_INVALIDCALL;
5120 /* Verify that the source and destination textures are the same type. */
5121 type = wined3d_texture_get_type(src_texture);
5122 if (wined3d_texture_get_type(dst_texture) != type)
5124 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5125 return WINED3DERR_INVALIDCALL;
5128 /* Check that both textures have the identical numbers of levels. */
5129 level_count = wined3d_texture_get_level_count(src_texture);
5130 if (wined3d_texture_get_level_count(dst_texture) != level_count)
5132 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5133 return WINED3DERR_INVALIDCALL;
5136 /* Make sure that the destination texture is loaded. */
5137 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
5139 /* Update every surface level of the texture. */
5142 case WINED3DRTYPE_TEXTURE:
5144 IWineD3DSurface *src_surface;
5145 IWineD3DSurface *dst_surface;
5147 for (i = 0; i < level_count; ++i)
5149 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5151 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5153 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5156 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5163 case WINED3DRTYPE_CUBETEXTURE:
5165 IWineD3DSurface *src_surface;
5166 IWineD3DSurface *dst_surface;
5168 for (i = 0; i < level_count * 6; ++i)
5170 src_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5172 dst_surface = (IWineD3DSurface *)surface_from_resource(wined3d_texture_get_sub_resource(
5174 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5177 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5184 case WINED3DRTYPE_VOLUMETEXTURE:
5186 IWineD3DVolume *src_volume;
5187 IWineD3DVolume *dst_volume;
5189 for (i = 0; i < level_count; ++i)
5191 src_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
5192 dst_volume = (IWineD3DVolume *)volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
5193 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5196 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5204 FIXME("Unsupported texture type %#x.\n", type);
5205 return WINED3DERR_INVALIDCALL;
5211 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5212 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5214 IWineD3DSwapChain *swapchain;
5217 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5219 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5220 if (FAILED(hr)) return hr;
5222 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5223 IWineD3DSwapChain_Release(swapchain);
5228 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD *pNumPasses)
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5231 const struct wined3d_state *state = &This->stateBlock->state;
5232 struct wined3d_texture *texture;
5235 TRACE("(%p) : %p\n", This, pNumPasses);
5237 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5239 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5241 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5242 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5244 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5246 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5247 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5250 texture = state->textures[i];
5251 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5253 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5255 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5258 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5260 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5263 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5264 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5266 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5271 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5272 state->render_states[WINED3DRS_STENCILENABLE])
5274 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5275 IWineD3DSurfaceImpl *target = This->render_targets[0];
5278 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5280 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5281 return WINED3DERR_CONFLICTINGRENDERSTATE;
5285 /* return a sensible default */
5288 TRACE("returning D3D_OK\n");
5292 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5296 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5298 struct wined3d_texture *texture = device->stateBlock->state.textures[i];
5299 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5300 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5302 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5307 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5311 PALETTEENTRY **palettes;
5313 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5315 if (PaletteNumber >= MAX_PALETTES) {
5316 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5317 return WINED3DERR_INVALIDCALL;
5320 if (PaletteNumber >= This->NumberOfPalettes) {
5321 NewSize = This->NumberOfPalettes;
5324 } while(PaletteNumber >= NewSize);
5325 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5327 ERR("Out of memory!\n");
5328 return E_OUTOFMEMORY;
5330 This->palettes = palettes;
5331 This->NumberOfPalettes = NewSize;
5334 if (!This->palettes[PaletteNumber]) {
5335 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5336 if (!This->palettes[PaletteNumber]) {
5337 ERR("Out of memory!\n");
5338 return E_OUTOFMEMORY;
5342 for (j = 0; j < 256; ++j) {
5343 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5344 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5345 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5346 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5348 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5349 TRACE("(%p) : returning\n", This);
5353 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5356 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5357 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5358 /* What happens in such situation isn't documented; Native seems to silently abort
5359 on such conditions. Return Invalid Call. */
5360 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5361 return WINED3DERR_INVALIDCALL;
5363 for (j = 0; j < 256; ++j) {
5364 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5365 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5366 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5367 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5369 TRACE("(%p) : returning\n", This);
5373 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5375 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5376 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5377 (tested with reference rasterizer). Return Invalid Call. */
5378 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5379 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5380 return WINED3DERR_INVALIDCALL;
5382 /*TODO: stateblocks */
5383 if (This->currentPalette != PaletteNumber) {
5384 This->currentPalette = PaletteNumber;
5385 dirtify_p8_texture_samplers(This);
5387 TRACE("(%p) : returning\n", This);
5391 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5396 WARN("(%p) : returning Invalid Call\n", This);
5397 return WINED3DERR_INVALIDCALL;
5399 /*TODO: stateblocks */
5400 *PaletteNumber = This->currentPalette;
5401 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5405 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5410 FIXME("(%p) : stub\n", This);
5414 This->softwareVertexProcessing = bSoftware;
5419 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5424 FIXME("(%p) : stub\n", This);
5427 return This->softwareVertexProcessing;
5430 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5431 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5433 IWineD3DSwapChain *swapchain;
5436 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5437 iface, swapchain_idx, raster_status);
5439 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5442 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5446 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5447 IWineD3DSwapChain_Release(swapchain);
5450 WARN("Failed to get raster status, hr %#x.\n", hr);
5457 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5460 if(nSegments != 0.0f) {
5463 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5470 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5475 FIXME("iface %p stub!\n", iface);
5481 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5482 IWineD3DSurface *src_surface, const RECT *src_rect,
5483 IWineD3DSurface *dst_surface, const POINT *dst_point)
5485 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5486 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 const struct wined3d_format *src_format;
5489 const struct wined3d_format *dst_format;
5490 const struct wined3d_gl_info *gl_info;
5491 struct wined3d_context *context;
5492 const unsigned char *data;
5493 UINT update_w, update_h;
5494 CONVERT_TYPES convert;
5498 struct wined3d_format format;
5500 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5501 iface, src_surface, wine_dbgstr_rect(src_rect),
5502 dst_surface, wine_dbgstr_point(dst_point));
5504 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5506 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5507 src_surface, dst_surface);
5508 return WINED3DERR_INVALIDCALL;
5511 src_format = src_impl->resource.format;
5512 dst_format = dst_impl->resource.format;
5514 if (src_format->id != dst_format->id)
5516 WARN("Source and destination surfaces should have the same format.\n");
5517 return WINED3DERR_INVALIDCALL;
5520 dst_x = dst_point ? dst_point->x : 0;
5521 dst_y = dst_point ? dst_point->y : 0;
5523 /* This call loads the OpenGL surface directly, instead of copying the
5524 * surface to the destination's sysmem copy. If surface conversion is
5525 * needed, use BltFast instead to copy in sysmem and use regular surface
5527 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5528 if (convert != NO_CONVERSION || format.convert)
5529 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5531 context = context_acquire(This, NULL);
5532 gl_info = context->gl_info;
5535 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5536 checkGLcall("glActiveTextureARB");
5539 /* Make sure the surface is loaded and up to date */
5540 surface_internal_preload(dst_impl, SRGB_RGB);
5541 surface_bind(dst_impl, gl_info, FALSE);
5543 src_w = src_impl->resource.width;
5544 src_h = src_impl->resource.height;
5545 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5546 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5548 data = src_impl->resource.allocatedMemory;
5549 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5553 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5555 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5556 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5557 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5561 data += (src_rect->top / src_format->block_height) * src_pitch;
5562 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5565 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5566 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5567 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5569 if (row_length == src_pitch)
5571 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5572 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5578 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5579 * can't use the unpack row length like below. */
5580 for (row = 0, y = dst_y; row < row_count; ++row)
5582 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5583 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5584 y += src_format->block_height;
5588 checkGLcall("glCompressedTexSubImage2DARB");
5594 data += src_rect->top * src_w * src_format->byte_count;
5595 data += src_rect->left * src_format->byte_count;
5598 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5599 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5600 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5602 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5603 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5604 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5605 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5606 checkGLcall("glTexSubImage2D");
5610 context_release(context);
5612 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5613 sampler = This->rev_tex_unit_map[0];
5614 if (sampler != WINED3D_UNMAPPED_STAGE)
5616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5622 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5624 struct WineD3DRectPatch *patch;
5625 GLenum old_primitive_type;
5629 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5631 if(!(Handle || pRectPatchInfo)) {
5632 /* TODO: Write a test for the return value, thus the FIXME */
5633 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5634 return WINED3DERR_INVALIDCALL;
5638 i = PATCHMAP_HASHFUNC(Handle);
5640 LIST_FOR_EACH(e, &This->patches[i]) {
5641 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5642 if(patch->Handle == Handle) {
5649 TRACE("Patch does not exist. Creating a new one\n");
5650 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5651 patch->Handle = Handle;
5652 list_add_head(&This->patches[i], &patch->entry);
5654 TRACE("Found existing patch %p\n", patch);
5657 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5658 * attributes we have to tesselate, read back, and draw. This needs a patch
5659 * management structure instance. Create one.
5661 * A possible improvement is to check if a vertex shader is used, and if not directly
5664 FIXME("Drawing an uncached patch. This is slow\n");
5665 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5668 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5669 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5670 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5673 TRACE("Tesselation density or patch info changed, retesselating\n");
5675 if(pRectPatchInfo) {
5676 patch->RectPatchInfo = *pRectPatchInfo;
5678 patch->numSegs[0] = pNumSegs[0];
5679 patch->numSegs[1] = pNumSegs[1];
5680 patch->numSegs[2] = pNumSegs[2];
5681 patch->numSegs[3] = pNumSegs[3];
5683 hr = tesselate_rectpatch(This, patch);
5685 WARN("Patch tesselation failed\n");
5687 /* Do not release the handle to store the params of the patch */
5689 HeapFree(GetProcessHeap(), 0, patch);
5695 This->currentPatch = patch;
5696 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5697 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5698 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5699 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5700 This->currentPatch = NULL;
5702 /* Destroy uncached patches */
5704 HeapFree(GetProcessHeap(), 0, patch->mem);
5705 HeapFree(GetProcessHeap(), 0, patch);
5710 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5711 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5713 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5714 iface, handle, segment_count, patch_info);
5719 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5722 struct WineD3DRectPatch *patch;
5724 TRACE("(%p) Handle(%d)\n", This, Handle);
5726 i = PATCHMAP_HASHFUNC(Handle);
5727 LIST_FOR_EACH(e, &This->patches[i]) {
5728 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5729 if(patch->Handle == Handle) {
5730 TRACE("Deleting patch %p\n", patch);
5731 list_remove(&patch->entry);
5732 HeapFree(GetProcessHeap(), 0, patch->mem);
5733 HeapFree(GetProcessHeap(), 0, patch);
5738 /* TODO: Write a test for the return value */
5739 FIXME("Attempt to destroy nonexistent patch\n");
5740 return WINED3DERR_INVALIDCALL;
5743 /* Do not call while under the GL lock. */
5744 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5745 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5747 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5749 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5750 iface, surface, wine_dbgstr_rect(rect),
5751 color->r, color->g, color->b, color->a);
5753 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5755 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5756 return WINED3DERR_INVALIDCALL;
5759 return surface_color_fill(s, rect, color);
5762 /* Do not call while under the GL lock. */
5763 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5764 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5766 struct wined3d_resource *resource;
5769 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5772 ERR("Failed to get resource, hr %#x\n", hr);
5776 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5778 FIXME("Only supported on surface resources\n");
5782 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5783 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5786 /* rendertarget and depth stencil functions */
5787 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5788 DWORD render_target_idx, IWineD3DSurface **render_target)
5790 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5792 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5793 iface, render_target_idx, render_target);
5795 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5797 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5798 return WINED3DERR_INVALIDCALL;
5801 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5802 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5804 TRACE("Returning render target %p.\n", *render_target);
5809 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5811 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5813 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5815 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5816 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5817 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5818 IWineD3DSurface_AddRef(*depth_stencil);
5823 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5824 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5826 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5827 IWineD3DSurfaceImpl *prev;
5829 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5830 iface, render_target_idx, render_target, set_viewport);
5832 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5834 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5835 return WINED3DERR_INVALIDCALL;
5838 prev = device->render_targets[render_target_idx];
5839 if (render_target == (IWineD3DSurface *)prev)
5841 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5845 /* Render target 0 can't be set to NULL. */
5846 if (!render_target && !render_target_idx)
5848 WARN("Trying to set render target 0 to NULL.\n");
5849 return WINED3DERR_INVALIDCALL;
5852 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5854 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5855 return WINED3DERR_INVALIDCALL;
5858 if (render_target) IWineD3DSurface_AddRef(render_target);
5859 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5860 /* Release after the assignment, to prevent device_resource_released()
5861 * from seeing the surface as still in use. */
5862 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5864 /* Render target 0 is special. */
5865 if (!render_target_idx && set_viewport)
5867 /* Set the viewport and scissor rectangles, if requested. Tests show
5868 * that stateblock recording is ignored, the change goes directly
5869 * into the primary stateblock. */
5870 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5871 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5872 device->stateBlock->state.viewport.X = 0;
5873 device->stateBlock->state.viewport.Y = 0;
5874 device->stateBlock->state.viewport.MaxZ = 1.0f;
5875 device->stateBlock->state.viewport.MinZ = 0.0f;
5876 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5878 device->stateBlock->state.scissor_rect.top = 0;
5879 device->stateBlock->state.scissor_rect.left = 0;
5880 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5881 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5882 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5888 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5891 IWineD3DSurfaceImpl *tmp;
5893 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5895 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5897 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5901 if (This->depth_stencil)
5903 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5904 || This->depth_stencil->flags & SFLAG_DISCARD)
5906 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5907 This->depth_stencil->resource.width,
5908 This->depth_stencil->resource.height);
5909 if (This->depth_stencil == This->onscreen_depth_stencil)
5911 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5912 This->onscreen_depth_stencil = NULL;
5917 tmp = This->depth_stencil;
5918 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5919 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5920 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5922 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5924 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5925 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5933 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5934 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5937 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5938 WINED3DLOCKED_RECT lockedRect;
5940 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5941 iface, XHotSpot, YHotSpot, cursor_image);
5943 /* some basic validation checks */
5944 if (This->cursorTexture)
5946 struct wined3d_context *context = context_acquire(This, NULL);
5948 glDeleteTextures(1, &This->cursorTexture);
5950 context_release(context);
5951 This->cursorTexture = 0;
5954 if (s->resource.width == 32 && s->resource.height == 32)
5955 This->haveHardwareCursor = TRUE;
5957 This->haveHardwareCursor = FALSE;
5961 WINED3DLOCKED_RECT rect;
5963 /* MSDN: Cursor must be A8R8G8B8 */
5964 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5966 WARN("surface %p has an invalid format.\n", cursor_image);
5967 return WINED3DERR_INVALIDCALL;
5970 /* MSDN: Cursor must be smaller than the display mode */
5971 if (s->resource.width > This->ddraw_width
5972 || s->resource.height > This->ddraw_height)
5974 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5975 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5976 return WINED3DERR_INVALIDCALL;
5979 if (!This->haveHardwareCursor) {
5980 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5982 /* Do not store the surface's pointer because the application may
5983 * release it after setting the cursor image. Windows doesn't
5984 * addref the set surface, so we can't do this either without
5985 * creating circular refcount dependencies. Copy out the gl texture
5988 This->cursorWidth = s->resource.width;
5989 This->cursorHeight = s->resource.height;
5990 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5992 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5993 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5994 struct wined3d_context *context;
5995 char *mem, *bits = rect.pBits;
5996 GLint intfmt = format->glInternal;
5997 GLint gl_format = format->glFormat;
5998 GLint type = format->glType;
5999 INT height = This->cursorHeight;
6000 INT width = This->cursorWidth;
6001 INT bpp = format->byte_count;
6005 /* Reformat the texture memory (pitch and width can be
6007 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6008 for(i = 0; i < height; i++)
6009 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6010 IWineD3DSurface_Unmap(cursor_image);
6012 context = context_acquire(This, NULL);
6016 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6018 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6019 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6022 /* Make sure that a proper texture unit is selected */
6023 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6024 checkGLcall("glActiveTextureARB");
6025 sampler = This->rev_tex_unit_map[0];
6026 if (sampler != WINED3D_UNMAPPED_STAGE)
6028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6030 /* Create a new cursor texture */
6031 glGenTextures(1, &This->cursorTexture);
6032 checkGLcall("glGenTextures");
6033 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6034 checkGLcall("glBindTexture");
6035 /* Copy the bitmap memory into the cursor texture */
6036 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6037 checkGLcall("glTexImage2D");
6038 HeapFree(GetProcessHeap(), 0, mem);
6040 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6042 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6043 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6048 context_release(context);
6052 FIXME("A cursor texture was not returned.\n");
6053 This->cursorTexture = 0;
6058 /* Draw a hardware cursor */
6059 ICONINFO cursorInfo;
6061 /* Create and clear maskBits because it is not needed for
6062 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6064 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6065 (s->resource.width * s->resource.height / 8));
6066 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6067 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6068 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6070 cursorInfo.fIcon = FALSE;
6071 cursorInfo.xHotspot = XHotSpot;
6072 cursorInfo.yHotspot = YHotSpot;
6073 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6074 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6075 IWineD3DSurface_Unmap(cursor_image);
6076 /* Create our cursor and clean up. */
6077 cursor = CreateIconIndirect(&cursorInfo);
6079 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6080 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6081 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6082 This->hardwareCursor = cursor;
6083 HeapFree(GetProcessHeap(), 0, maskBits);
6087 This->xHotSpot = XHotSpot;
6088 This->yHotSpot = YHotSpot;
6092 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6093 int XScreenSpace, int YScreenSpace, DWORD flags)
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6097 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6098 iface, XScreenSpace, YScreenSpace, flags);
6100 This->xScreenSpace = XScreenSpace;
6101 This->yScreenSpace = YScreenSpace;
6104 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6106 BOOL oldVisible = This->bCursorVisible;
6109 TRACE("(%p) : visible(%d)\n", This, bShow);
6112 * When ShowCursor is first called it should make the cursor appear at the OS's last
6113 * known cursor position. Because of this, some applications just repetitively call
6114 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6117 This->xScreenSpace = pt.x;
6118 This->yScreenSpace = pt.y;
6120 if (This->haveHardwareCursor) {
6121 This->bCursorVisible = bShow;
6123 SetCursor(This->hardwareCursor);
6129 if (This->cursorTexture)
6130 This->bCursorVisible = bShow;
6136 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6138 TRACE("checking resource %p for eviction\n", resource);
6140 if (resource->pool == WINED3DPOOL_MANAGED)
6142 TRACE("Evicting %p.\n", resource);
6143 resource->resource_ops->resource_unload(resource);
6149 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6151 TRACE("iface %p.\n", iface);
6153 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6154 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6155 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6160 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6162 IWineD3DDeviceImpl *device = surface->resource.device;
6163 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6165 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6166 if (surface->flags & SFLAG_DIBSECTION)
6168 /* Release the DC */
6169 SelectObject(surface->hDC, surface->dib.holdbitmap);
6170 DeleteDC(surface->hDC);
6171 /* Release the DIB section */
6172 DeleteObject(surface->dib.DIBsection);
6173 surface->dib.bitmap_data = NULL;
6174 surface->resource.allocatedMemory = NULL;
6175 surface->flags &= ~SFLAG_DIBSECTION;
6177 surface->resource.width = pPresentationParameters->BackBufferWidth;
6178 surface->resource.height = pPresentationParameters->BackBufferHeight;
6179 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6180 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6182 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6183 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6185 surface->pow2Width = surface->pow2Height = 1;
6186 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6187 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6190 if (surface->texture_name)
6192 struct wined3d_context *context = context_acquire(device, NULL);
6194 glDeleteTextures(1, &surface->texture_name);
6196 context_release(context);
6197 surface->texture_name = 0;
6198 surface->flags &= ~SFLAG_CLIENT;
6200 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6201 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6203 surface->flags |= SFLAG_NONPOW2;
6207 surface->flags &= ~SFLAG_NONPOW2;
6209 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6210 surface->resource.allocatedMemory = NULL;
6211 surface->resource.heapMemory = NULL;
6212 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6214 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6216 if (!surface_init_sysmem(surface))
6218 return E_OUTOFMEMORY;
6223 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6226 WINED3DDISPLAYMODE m;
6229 /* All Windowed modes are supported, as is leaving the current mode */
6230 if(pp->Windowed) return TRUE;
6231 if(!pp->BackBufferWidth) return TRUE;
6232 if(!pp->BackBufferHeight) return TRUE;
6234 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6235 for (i = 0; i < count; ++i)
6237 memset(&m, 0, sizeof(m));
6238 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6240 ERR("Failed to enumerate adapter mode.\n");
6241 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6242 /* Mode found, it is supported. */
6245 /* Mode not found -> not supported */
6249 /* Do not call while under the GL lock. */
6250 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6252 const struct wined3d_gl_info *gl_info;
6253 struct wined3d_context *context;
6254 struct wined3d_shader *shader;
6256 context = context_acquire(device, NULL);
6257 gl_info = context->gl_info;
6259 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6260 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
6262 device->shader_backend->shader_destroy(shader);
6266 if (device->depth_blt_texture)
6268 glDeleteTextures(1, &device->depth_blt_texture);
6269 device->depth_blt_texture = 0;
6271 if (device->depth_blt_rb)
6273 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6274 device->depth_blt_rb = 0;
6275 device->depth_blt_rb_w = 0;
6276 device->depth_blt_rb_h = 0;
6280 device->blitter->free_private(device);
6281 device->frag_pipe->free_private(device);
6282 device->shader_backend->shader_free_private(device);
6283 destroy_dummy_textures(device, gl_info);
6285 context_release(context);
6287 while (device->context_count)
6289 context_destroy(device, device->contexts[0]);
6291 HeapFree(GetProcessHeap(), 0, swapchain->context);
6292 swapchain->context = NULL;
6293 swapchain->num_contexts = 0;
6296 /* Do not call while under the GL lock. */
6297 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6299 struct wined3d_context *context;
6301 IWineD3DSurfaceImpl *target;
6303 /* Recreate the primary swapchain's context */
6304 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6305 if (!swapchain->context)
6307 ERR("Failed to allocate memory for swapchain context array.\n");
6308 return E_OUTOFMEMORY;
6311 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6312 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6314 WARN("Failed to create context.\n");
6315 HeapFree(GetProcessHeap(), 0, swapchain->context);
6319 swapchain->context[0] = context;
6320 swapchain->num_contexts = 1;
6321 create_dummy_textures(device);
6322 context_release(context);
6324 hr = device->shader_backend->shader_alloc_private(device);
6327 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6331 hr = device->frag_pipe->alloc_private(device);
6334 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6335 device->shader_backend->shader_free_private(device);
6339 hr = device->blitter->alloc_private(device);
6342 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6343 device->frag_pipe->free_private(device);
6344 device->shader_backend->shader_free_private(device);
6351 context_acquire(device, NULL);
6352 destroy_dummy_textures(device, context->gl_info);
6353 context_release(context);
6354 context_destroy(device, context);
6355 HeapFree(GetProcessHeap(), 0, swapchain->context);
6356 swapchain->num_contexts = 0;
6360 /* Do not call while under the GL lock. */
6361 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6362 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6365 IWineD3DSwapChainImpl *swapchain;
6367 BOOL DisplayModeChanged = FALSE;
6368 WINED3DDISPLAYMODE mode;
6369 TRACE("(%p)\n", This);
6371 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6373 ERR("Failed to get the first implicit swapchain\n");
6377 if(!is_display_mode_supported(This, pPresentationParameters)) {
6378 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6379 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6380 pPresentationParameters->BackBufferHeight);
6381 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6382 return WINED3DERR_INVALIDCALL;
6385 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6386 * on an existing gl context, so there's no real need for recreation.
6388 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6390 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6392 TRACE("New params:\n");
6393 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6394 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6395 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6396 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6397 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6398 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6399 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6400 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6401 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6402 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6403 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6404 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6405 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6407 /* No special treatment of these parameters. Just store them */
6408 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6409 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6410 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6411 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6413 /* What to do about these? */
6414 if (pPresentationParameters->BackBufferCount
6415 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6416 ERR("Cannot change the back buffer count yet\n");
6418 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6419 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6420 ERR("Cannot change the back buffer format yet\n");
6423 if (pPresentationParameters->hDeviceWindow
6424 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6425 ERR("Cannot change the device window yet\n");
6427 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6431 TRACE("Creating the depth stencil buffer\n");
6433 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6434 pPresentationParameters->BackBufferWidth,
6435 pPresentationParameters->BackBufferHeight,
6436 pPresentationParameters->AutoDepthStencilFormat,
6437 pPresentationParameters->MultiSampleType,
6438 pPresentationParameters->MultiSampleQuality,
6440 (IWineD3DSurface **)&This->auto_depth_stencil);
6443 ERR("Failed to create the depth stencil buffer\n");
6444 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6445 return WINED3DERR_INVALIDCALL;
6449 if (This->onscreen_depth_stencil)
6451 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6452 This->onscreen_depth_stencil = NULL;
6455 /* Reset the depth stencil */
6456 if (pPresentationParameters->EnableAutoDepthStencil)
6457 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6459 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6461 TRACE("Resetting stateblock\n");
6462 wined3d_stateblock_decref(This->updateStateBlock);
6463 wined3d_stateblock_decref(This->stateBlock);
6465 delete_opengl_contexts(This, swapchain);
6467 if(pPresentationParameters->Windowed) {
6468 mode.Width = swapchain->orig_width;
6469 mode.Height = swapchain->orig_height;
6470 mode.RefreshRate = 0;
6471 mode.Format = swapchain->presentParms.BackBufferFormat;
6473 mode.Width = pPresentationParameters->BackBufferWidth;
6474 mode.Height = pPresentationParameters->BackBufferHeight;
6475 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6476 mode.Format = swapchain->presentParms.BackBufferFormat;
6479 /* Should Width == 800 && Height == 0 set 800x600? */
6480 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6481 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6482 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6486 if(!pPresentationParameters->Windowed) {
6487 DisplayModeChanged = TRUE;
6489 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6490 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6492 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6495 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6499 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6501 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6504 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6508 if (This->auto_depth_stencil)
6510 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6513 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6519 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6520 || DisplayModeChanged)
6522 BOOL filter = This->filter_messages;
6523 This->filter_messages = TRUE;
6525 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6527 if (!pPresentationParameters->Windowed)
6529 if (swapchain->presentParms.Windowed)
6531 HWND focus_window = This->createParms.hFocusWindow;
6532 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6533 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6535 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6536 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6540 /* switch from windowed to fs */
6541 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6542 pPresentationParameters->BackBufferWidth,
6543 pPresentationParameters->BackBufferHeight);
6547 /* Fullscreen -> fullscreen mode change */
6548 MoveWindow(swapchain->device_window, 0, 0,
6549 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6553 else if (!swapchain->presentParms.Windowed)
6555 /* Fullscreen -> windowed switch */
6556 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6557 IWineD3DDevice_ReleaseFocusWindow(iface);
6559 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6561 This->filter_messages = filter;
6563 else if (!pPresentationParameters->Windowed)
6565 DWORD style = This->style, exStyle = This->exStyle;
6566 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6567 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6568 * Reset to clear up their mess. Guild Wars also loses the device during that.
6572 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6573 pPresentationParameters->BackBufferWidth,
6574 pPresentationParameters->BackBufferHeight);
6575 This->style = style;
6576 This->exStyle = exStyle;
6579 /* Note: No parent needed for initial internal stateblock */
6580 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6581 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6582 else TRACE("Created stateblock %p\n", This->stateBlock);
6583 This->updateStateBlock = This->stateBlock;
6584 wined3d_stateblock_incref(This->updateStateBlock);
6586 stateblock_init_default_state(This->stateBlock);
6588 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6591 GetClientRect(swapchain->win_handle, &client_rect);
6593 if(!swapchain->presentParms.BackBufferCount)
6595 TRACE("Single buffered rendering\n");
6596 swapchain->render_to_fbo = FALSE;
6598 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6599 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6601 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6602 swapchain->presentParms.BackBufferWidth,
6603 swapchain->presentParms.BackBufferHeight,
6604 client_rect.right, client_rect.bottom);
6605 swapchain->render_to_fbo = TRUE;
6609 TRACE("Rendering directly to GL_BACK\n");
6610 swapchain->render_to_fbo = FALSE;
6614 hr = create_primary_opengl_context(This, swapchain);
6615 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6617 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6623 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6625 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6627 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6633 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6635 TRACE("(%p) : pParameters %p\n", This, pParameters);
6637 *pParameters = This->createParms;
6641 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6642 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6644 IWineD3DSwapChain *swapchain;
6646 TRACE("Relaying to swapchain\n");
6648 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6650 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6651 IWineD3DSwapChain_Release(swapchain);
6655 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6656 IWineD3DSwapChain *swapchain;
6658 TRACE("Relaying to swapchain\n");
6660 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6661 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6662 IWineD3DSwapChain_Release(swapchain);
6666 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6668 TRACE("device %p, resource %p.\n", device, resource);
6670 list_add_head(&device->resources, &resource->resource_list_entry);
6673 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6675 TRACE("device %p, resource %p.\n", device, resource);
6677 list_remove(&resource->resource_list_entry);
6680 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6682 WINED3DRESOURCETYPE type = resource->resourceType;
6685 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6687 context_resource_released(device, resource, type);
6691 case WINED3DRTYPE_SURFACE:
6693 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6695 if (!device->d3d_initialized) break;
6697 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6699 if (device->render_targets[i] == surface)
6701 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6702 device->render_targets[i] = NULL;
6706 if (device->depth_stencil == surface)
6708 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6709 device->depth_stencil = NULL;
6714 case WINED3DRTYPE_TEXTURE:
6715 case WINED3DRTYPE_CUBETEXTURE:
6716 case WINED3DRTYPE_VOLUMETEXTURE:
6717 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6719 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
6721 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6723 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6724 texture, device->stateBlock, i);
6725 device->stateBlock->state.textures[i] = NULL;
6728 if (device->updateStateBlock != device->stateBlock
6729 && device->updateStateBlock->state.textures[i] == texture)
6731 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6732 texture, device->updateStateBlock, i);
6733 device->updateStateBlock->state.textures[i] = NULL;
6738 case WINED3DRTYPE_BUFFER:
6740 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6742 for (i = 0; i < MAX_STREAMS; ++i)
6744 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6746 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6747 buffer, device->stateBlock, i);
6748 device->stateBlock->state.streams[i].buffer = NULL;
6751 if (device->updateStateBlock != device->stateBlock
6752 && device->updateStateBlock->state.streams[i].buffer == buffer)
6754 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6755 buffer, device->updateStateBlock, i);
6756 device->updateStateBlock->state.streams[i].buffer = NULL;
6761 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6763 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6764 buffer, device->stateBlock);
6765 device->stateBlock->state.index_buffer = NULL;
6768 if (device->updateStateBlock != device->stateBlock
6769 && device->updateStateBlock->state.index_buffer == buffer)
6771 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6772 buffer, device->updateStateBlock);
6773 device->updateStateBlock->state.index_buffer = NULL;
6782 /* Remove the resource from the resourceStore */
6783 device_resource_remove(device, resource);
6785 TRACE("Resource released.\n");
6788 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6789 D3DCB_ENUMRESOURCES callback, void *data)
6791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6792 struct wined3d_resource *resource, *cursor;
6794 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6796 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6798 TRACE("enumerating resource %p.\n", resource);
6799 if (callback(resource, data) == S_FALSE)
6801 TRACE("Canceling enumeration.\n");
6809 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6812 struct wined3d_resource *resource;
6814 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6816 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6818 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6822 TRACE("Found surface %p for dc %p.\n", s, dc);
6823 *surface = (IWineD3DSurface *)s;
6829 return WINED3DERR_INVALIDCALL;
6832 /**********************************************************
6833 * IWineD3DDevice VTbl follows
6834 **********************************************************/
6836 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6838 /*** IUnknown methods ***/
6839 IWineD3DDeviceImpl_QueryInterface,
6840 IWineD3DDeviceImpl_AddRef,
6841 IWineD3DDeviceImpl_Release,
6842 /*** IWineD3DDevice methods ***/
6843 /*** Creation methods**/
6844 IWineD3DDeviceImpl_CreateBuffer,
6845 IWineD3DDeviceImpl_CreateVertexBuffer,
6846 IWineD3DDeviceImpl_CreateIndexBuffer,
6847 IWineD3DDeviceImpl_CreateStateBlock,
6848 IWineD3DDeviceImpl_CreateSurface,
6849 IWineD3DDeviceImpl_CreateRendertargetView,
6850 IWineD3DDeviceImpl_CreateTexture,
6851 IWineD3DDeviceImpl_CreateVolumeTexture,
6852 IWineD3DDeviceImpl_CreateVolume,
6853 IWineD3DDeviceImpl_CreateCubeTexture,
6854 IWineD3DDeviceImpl_CreateQuery,
6855 IWineD3DDeviceImpl_CreateSwapChain,
6856 IWineD3DDeviceImpl_CreateVertexDeclaration,
6857 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6858 IWineD3DDeviceImpl_CreateVertexShader,
6859 IWineD3DDeviceImpl_CreateGeometryShader,
6860 IWineD3DDeviceImpl_CreatePixelShader,
6861 IWineD3DDeviceImpl_CreatePalette,
6862 /*** Odd functions **/
6863 IWineD3DDeviceImpl_Init3D,
6864 IWineD3DDeviceImpl_InitGDI,
6865 IWineD3DDeviceImpl_Uninit3D,
6866 IWineD3DDeviceImpl_UninitGDI,
6867 IWineD3DDeviceImpl_SetMultithreaded,
6868 IWineD3DDeviceImpl_EvictManagedResources,
6869 IWineD3DDeviceImpl_GetAvailableTextureMem,
6870 IWineD3DDeviceImpl_GetBackBuffer,
6871 IWineD3DDeviceImpl_GetCreationParameters,
6872 IWineD3DDeviceImpl_GetDeviceCaps,
6873 IWineD3DDeviceImpl_GetDirect3D,
6874 IWineD3DDeviceImpl_GetDisplayMode,
6875 IWineD3DDeviceImpl_SetDisplayMode,
6876 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6877 IWineD3DDeviceImpl_GetRasterStatus,
6878 IWineD3DDeviceImpl_GetSwapChain,
6879 IWineD3DDeviceImpl_Reset,
6880 IWineD3DDeviceImpl_SetDialogBoxMode,
6881 IWineD3DDeviceImpl_SetCursorProperties,
6882 IWineD3DDeviceImpl_SetCursorPosition,
6883 IWineD3DDeviceImpl_ShowCursor,
6884 /*** Getters and setters **/
6885 IWineD3DDeviceImpl_SetClipPlane,
6886 IWineD3DDeviceImpl_GetClipPlane,
6887 IWineD3DDeviceImpl_SetClipStatus,
6888 IWineD3DDeviceImpl_GetClipStatus,
6889 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6890 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6891 IWineD3DDeviceImpl_SetDepthStencilSurface,
6892 IWineD3DDeviceImpl_GetDepthStencilSurface,
6893 IWineD3DDeviceImpl_SetGammaRamp,
6894 IWineD3DDeviceImpl_GetGammaRamp,
6895 IWineD3DDeviceImpl_SetIndexBuffer,
6896 IWineD3DDeviceImpl_GetIndexBuffer,
6897 IWineD3DDeviceImpl_SetBaseVertexIndex,
6898 IWineD3DDeviceImpl_GetBaseVertexIndex,
6899 IWineD3DDeviceImpl_SetLight,
6900 IWineD3DDeviceImpl_GetLight,
6901 IWineD3DDeviceImpl_SetLightEnable,
6902 IWineD3DDeviceImpl_GetLightEnable,
6903 IWineD3DDeviceImpl_SetMaterial,
6904 IWineD3DDeviceImpl_GetMaterial,
6905 IWineD3DDeviceImpl_SetNPatchMode,
6906 IWineD3DDeviceImpl_GetNPatchMode,
6907 IWineD3DDeviceImpl_SetPaletteEntries,
6908 IWineD3DDeviceImpl_GetPaletteEntries,
6909 IWineD3DDeviceImpl_SetPixelShader,
6910 IWineD3DDeviceImpl_GetPixelShader,
6911 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6912 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6913 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6914 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6915 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6916 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6917 IWineD3DDeviceImpl_SetRenderState,
6918 IWineD3DDeviceImpl_GetRenderState,
6919 IWineD3DDeviceImpl_SetRenderTarget,
6920 IWineD3DDeviceImpl_GetRenderTarget,
6921 IWineD3DDeviceImpl_SetSamplerState,
6922 IWineD3DDeviceImpl_GetSamplerState,
6923 IWineD3DDeviceImpl_SetScissorRect,
6924 IWineD3DDeviceImpl_GetScissorRect,
6925 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6926 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6927 IWineD3DDeviceImpl_SetStreamSource,
6928 IWineD3DDeviceImpl_GetStreamSource,
6929 IWineD3DDeviceImpl_SetStreamSourceFreq,
6930 IWineD3DDeviceImpl_GetStreamSourceFreq,
6931 IWineD3DDeviceImpl_SetTexture,
6932 IWineD3DDeviceImpl_GetTexture,
6933 IWineD3DDeviceImpl_SetTextureStageState,
6934 IWineD3DDeviceImpl_GetTextureStageState,
6935 IWineD3DDeviceImpl_SetTransform,
6936 IWineD3DDeviceImpl_GetTransform,
6937 IWineD3DDeviceImpl_SetVertexDeclaration,
6938 IWineD3DDeviceImpl_GetVertexDeclaration,
6939 IWineD3DDeviceImpl_SetVertexShader,
6940 IWineD3DDeviceImpl_GetVertexShader,
6941 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6942 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6943 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6944 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6945 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6946 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6947 IWineD3DDeviceImpl_SetViewport,
6948 IWineD3DDeviceImpl_GetViewport,
6949 IWineD3DDeviceImpl_MultiplyTransform,
6950 IWineD3DDeviceImpl_ValidateDevice,
6951 IWineD3DDeviceImpl_ProcessVertices,
6952 /*** State block ***/
6953 IWineD3DDeviceImpl_BeginStateBlock,
6954 IWineD3DDeviceImpl_EndStateBlock,
6955 /*** Scene management ***/
6956 IWineD3DDeviceImpl_BeginScene,
6957 IWineD3DDeviceImpl_EndScene,
6958 IWineD3DDeviceImpl_Present,
6959 IWineD3DDeviceImpl_Clear,
6960 IWineD3DDeviceImpl_ClearRendertargetView,
6962 IWineD3DDeviceImpl_SetPrimitiveType,
6963 IWineD3DDeviceImpl_GetPrimitiveType,
6964 IWineD3DDeviceImpl_DrawPrimitive,
6965 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6966 IWineD3DDeviceImpl_DrawPrimitiveUP,
6967 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6968 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6969 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6970 IWineD3DDeviceImpl_DrawRectPatch,
6971 IWineD3DDeviceImpl_DrawTriPatch,
6972 IWineD3DDeviceImpl_DeletePatch,
6973 IWineD3DDeviceImpl_ColorFill,
6974 IWineD3DDeviceImpl_UpdateTexture,
6975 IWineD3DDeviceImpl_UpdateSurface,
6976 IWineD3DDeviceImpl_GetFrontBufferData,
6977 /*** object tracking ***/
6978 IWineD3DDeviceImpl_EnumResources,
6979 IWineD3DDeviceImpl_GetSurfaceFromDC,
6980 IWineD3DDeviceImpl_AcquireFocusWindow,
6981 IWineD3DDeviceImpl_ReleaseFocusWindow,
6982 IWineD3DDeviceImpl_SetupFullscreenWindow,
6983 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6986 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6987 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6988 IWineD3DDeviceParent *device_parent)
6990 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6991 const struct fragment_pipeline *fragment_pipeline;
6992 struct shader_caps shader_caps;
6993 struct fragment_caps ffp_caps;
6994 WINED3DDISPLAYMODE mode;
6998 device->lpVtbl = &IWineD3DDevice_Vtbl;
7000 device->wined3d = wined3d;
7001 wined3d_incref(device->wined3d);
7002 device->adapter = wined3d->adapter_count ? adapter : NULL;
7003 device->device_parent = device_parent;
7004 list_init(&device->resources);
7005 list_init(&device->shaders);
7007 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7009 /* Get the initial screen setup for ddraw. */
7010 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7013 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7014 wined3d_decref(device->wined3d);
7017 device->ddraw_width = mode.Width;
7018 device->ddraw_height = mode.Height;
7019 device->ddraw_format = mode.Format;
7021 /* Save the creation parameters. */
7022 device->createParms.AdapterOrdinal = adapter_idx;
7023 device->createParms.DeviceType = device_type;
7024 device->createParms.hFocusWindow = focus_window;
7025 device->createParms.BehaviorFlags = flags;
7027 device->devType = device_type;
7028 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7030 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7031 device->shader_backend = adapter->shader_backend;
7033 if (device->shader_backend)
7035 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7036 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7037 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7038 device->vs_clipping = shader_caps.VSClipping;
7040 fragment_pipeline = adapter->fragment_pipe;
7041 device->frag_pipe = fragment_pipeline;
7042 if (fragment_pipeline)
7044 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7045 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7047 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7048 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7051 ERR("Failed to compile state table, hr %#x.\n", hr);
7052 wined3d_decref(device->wined3d);
7056 device->blitter = adapter->blitter;
7062 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7063 DWORD rep = This->StateTable[state].representative;
7064 struct wined3d_context *context;
7069 for (i = 0; i < This->context_count; ++i)
7071 context = This->contexts[i];
7072 if(isStateDirty(context, rep)) continue;
7074 context->dirtyArray[context->numDirtyEntries++] = rep;
7075 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7076 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7077 context->isStateDirty[idx] |= (1 << shift);
7081 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7083 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7084 *width = context->current_rt->pow2Width;
7085 *height = context->current_rt->pow2Height;
7088 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7090 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7091 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7092 * current context's drawable, which is the size of the back buffer of the swapchain
7093 * the active context belongs to. */
7094 *width = swapchain->presentParms.BackBufferWidth;
7095 *height = swapchain->presentParms.BackBufferHeight;
7098 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7099 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7101 if (device->filter_messages)
7103 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7104 window, message, wparam, lparam);
7106 return DefWindowProcW(window, message, wparam, lparam);
7108 return DefWindowProcA(window, message, wparam, lparam);
7111 if (message == WM_DESTROY)
7113 TRACE("unregister window %p.\n", window);
7114 wined3d_unregister_window(window);
7116 if (device->focus_window == window) device->focus_window = NULL;
7117 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7121 return CallWindowProcW(proc, window, message, wparam, lparam);
7123 return CallWindowProcA(proc, window, message, wparam, lparam);