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-2010 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 IWineD3DBaseTextureImpl *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->baseTexture.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->baseShader.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->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 struct wined3d_stateblock *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->resource.width
595 || draw_rect->bottom < target->resource.height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->resource.width
601 || clear_rect->bottom < target->resource.height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
691 context_release(context);
692 WARN("Failed to apply clear state, skipping clear.\n");
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(¤t_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 struct wined3d_resource *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
875 FIXME("Leftover resource %p with type %s (%#x).\n",
876 resource, debug_d3dresourcetype(resource->resourceType), resource->resourceType);
880 if(This->contexts) ERR("Context array not freed!\n");
881 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
882 This->haveHardwareCursor = FALSE;
884 wined3d_decref(This->wined3d);
885 This->wined3d = NULL;
886 HeapFree(GetProcessHeap(), 0, This);
887 TRACE("Freed device %p\n", This);
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
894 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 struct wined3d_buffer *object;
900 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
902 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
905 ERR("Failed to allocate memory\n");
906 return E_OUTOFMEMORY;
909 FIXME("Ignoring access flags (pool)\n");
911 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
912 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
915 WARN("Failed to initialize buffer, hr %#x.\n", hr);
916 HeapFree(GetProcessHeap(), 0, object);
919 object->desc = *desc;
921 TRACE("Created buffer %p.\n", object);
928 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
929 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
932 struct wined3d_buffer *object;
935 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
936 iface, Size, Usage, Pool, parent, parent_ops, buffer);
938 if (Pool == WINED3DPOOL_SCRATCH)
940 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
941 * anyway, SCRATCH vertex buffers aren't usable anywhere
943 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
951 ERR("Out of memory\n");
953 return WINED3DERR_OUTOFVIDEOMEMORY;
956 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
957 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
960 WARN("Failed to initialize buffer, hr %#x.\n", hr);
961 HeapFree(GetProcessHeap(), 0, object);
965 TRACE("Created buffer %p.\n", object);
971 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
972 WINED3DPOOL Pool, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
975 struct wined3d_buffer *object;
978 TRACE("iface %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
979 iface, Length, Usage, Pool, parent, parent_ops, buffer);
981 /* Allocate the storage for the device */
982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
985 ERR("Out of memory\n");
987 return WINED3DERR_OUTOFVIDEOMEMORY;
990 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
991 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
995 WARN("Failed to initialize buffer, hr %#x\n", hr);
996 HeapFree(GetProcessHeap(), 0, object);
1000 TRACE("Created buffer %p.\n", object);
1007 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1008 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1011 struct wined3d_stateblock *object;
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1017 ERR("Failed to allocate stateblock memory.\n");
1018 return E_OUTOFMEMORY;
1021 hr = stateblock_init(object, This, type);
1024 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1029 TRACE("Created stateblock %p.\n", object);
1030 *stateblock = object;
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1036 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1037 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1038 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 IWineD3DSurfaceImpl *object;
1044 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1045 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1046 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1047 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1048 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1050 if (Impl == SURFACE_OPENGL && !This->adapter)
1052 ERR("OpenGL surfaces are not available without OpenGL.\n");
1053 return WINED3DERR_NOTAVAILABLE;
1056 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1059 ERR("Failed to allocate surface memory.\n");
1060 return WINED3DERR_OUTOFVIDEOMEMORY;
1063 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1064 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1067 WARN("Failed to initialize surface, returning %#x.\n", hr);
1068 HeapFree(GetProcessHeap(), 0, object);
1072 TRACE("(%p) : Created surface %p\n", This, object);
1074 *surface = (IWineD3DSurface *)object;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1080 struct wined3d_resource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1082 struct wined3d_rendertarget_view *object;
1084 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1085 iface, resource, parent, rendertarget_view);
1087 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1090 ERR("Failed to allocate memory\n");
1091 return E_OUTOFMEMORY;
1094 wined3d_rendertarget_view_init(object, resource, parent);
1096 TRACE("Created render target view %p.\n", object);
1097 *rendertarget_view = (IWineD3DRendertargetView *)object;
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1103 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1104 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBaseTexture **texture)
1106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1107 IWineD3DBaseTextureImpl *object;
1110 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1111 TRACE("Format %#x (%s), Pool %#x, texture %p, parent %p\n",
1112 Format, debug_d3dformat(Format), Pool, texture, parent);
1114 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1117 ERR("Out of memory\n");
1119 return WINED3DERR_OUTOFVIDEOMEMORY;
1122 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1125 WARN("Failed to initialize texture, returning %#x\n", hr);
1126 HeapFree(GetProcessHeap(), 0, object);
1131 *texture = (IWineD3DBaseTexture *)object;
1133 TRACE("(%p) : Created texture %p\n", This, object);
1138 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1139 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1140 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBaseTexture **ppVolumeTexture)
1142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1143 IWineD3DBaseTextureImpl *object;
1146 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1147 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1149 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1152 ERR("Out of memory\n");
1153 *ppVolumeTexture = NULL;
1154 return WINED3DERR_OUTOFVIDEOMEMORY;
1157 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1160 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1161 HeapFree(GetProcessHeap(), 0, object);
1162 *ppVolumeTexture = NULL;
1166 TRACE("(%p) : Created volume texture %p.\n", This, object);
1167 *ppVolumeTexture = (IWineD3DBaseTexture *)object;
1172 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1173 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1174 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DVolumeImpl *object;
1180 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1181 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1183 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1186 ERR("Out of memory\n");
1188 return WINED3DERR_OUTOFVIDEOMEMORY;
1191 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1194 WARN("Failed to initialize volume, returning %#x.\n", hr);
1195 HeapFree(GetProcessHeap(), 0, object);
1199 TRACE("(%p) : Created volume %p.\n", This, object);
1200 *ppVolume = (IWineD3DVolume *)object;
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1206 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1207 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1210 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1213 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1216 ERR("Out of memory\n");
1217 *ppCubeTexture = NULL;
1218 return WINED3DERR_OUTOFVIDEOMEMORY;
1221 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1224 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1225 HeapFree(GetProcessHeap(), 0, object);
1226 *ppCubeTexture = NULL;
1230 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1231 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1236 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1237 WINED3DQUERYTYPE type, struct wined3d_query **query)
1239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1240 struct wined3d_query *object;
1243 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1245 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1248 ERR("Failed to allocate query memory.\n");
1249 return E_OUTOFMEMORY;
1252 hr = query_init(object, This, type);
1255 WARN("Failed to initialize query, hr %#x.\n", hr);
1256 HeapFree(GetProcessHeap(), 0, object);
1260 TRACE("Created query %p.\n", object);
1266 /* Do not call while under the GL lock. */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1268 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1269 void *parent, IWineD3DSwapChain **swapchain)
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1272 IWineD3DSwapChainImpl *object;
1275 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1276 iface, present_parameters, swapchain, parent, surface_type);
1278 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1281 ERR("Failed to allocate swapchain memory.\n");
1282 return E_OUTOFMEMORY;
1285 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1288 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1289 HeapFree(GetProcessHeap(), 0, object);
1293 TRACE("Created swapchain %p.\n", object);
1294 *swapchain = (IWineD3DSwapChain *)object;
1299 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1300 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 TRACE("(%p)\n", This);
1304 return This->NumberOfSwapChains;
1307 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1311 if (iSwapChain < This->NumberOfSwapChains)
1313 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1314 IWineD3DSwapChain_AddRef(*pSwapChain);
1315 TRACE("(%p) returning %p\n", This, *pSwapChain);
1318 TRACE("Swapchain out of range\n");
1320 return WINED3DERR_INVALIDCALL;
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1325 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1326 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 struct wined3d_vertex_declaration *object;
1332 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1333 iface, elements, element_count, parent, parent_ops, declaration);
1335 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1338 ERR("Failed to allocate vertex declaration memory.\n");
1339 return E_OUTOFMEMORY;
1342 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1345 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1346 HeapFree(GetProcessHeap(), 0, object);
1350 TRACE("Created vertex declaration %p.\n", object);
1351 *declaration = object;
1356 struct wined3d_fvf_convert_state
1358 const struct wined3d_gl_info *gl_info;
1359 WINED3DVERTEXELEMENT *elements;
1364 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1365 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1367 WINED3DVERTEXELEMENT *elements = state->elements;
1368 const struct wined3d_format *format;
1369 UINT offset = state->offset;
1370 UINT idx = state->idx;
1372 elements[idx].format = format_id;
1373 elements[idx].input_slot = 0;
1374 elements[idx].offset = offset;
1375 elements[idx].output_slot = 0;
1376 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1377 elements[idx].usage = usage;
1378 elements[idx].usage_idx = usage_idx;
1380 format = wined3d_get_format(state->gl_info, format_id);
1381 state->offset += format->component_count * format->component_size;
1385 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1386 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1388 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1389 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1390 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1391 BOOL has_blend_idx = has_blend &&
1392 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1393 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1394 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1395 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1396 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1397 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1398 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1400 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1401 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1402 struct wined3d_fvf_convert_state state;
1405 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1406 if (has_blend_idx) num_blends--;
1408 /* Compute declaration size */
1409 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1410 has_psize + has_diffuse + has_specular + num_textures;
1412 state.gl_info = gl_info;
1413 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1414 if (!state.elements) return ~0U;
1420 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1421 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1422 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1425 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1428 if (has_blend && (num_blends > 0))
1430 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1431 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 ERR("Unexpected amount of blend values: %u\n", num_blends);
1456 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1457 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1458 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1459 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1460 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1466 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1467 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1468 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1470 for (idx = 0; idx < num_textures; ++idx)
1472 switch ((texcoords >> (idx * 2)) & 0x03)
1474 case WINED3DFVF_TEXTUREFORMAT1:
1475 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1477 case WINED3DFVF_TEXTUREFORMAT2:
1478 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1480 case WINED3DFVF_TEXTUREFORMAT3:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1483 case WINED3DFVF_TEXTUREFORMAT4:
1484 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1489 *ppVertexElements = state.elements;
1493 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1494 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1495 struct wined3d_vertex_declaration **declaration)
1497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1498 WINED3DVERTEXELEMENT *elements;
1502 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1503 iface, fvf, parent, parent_ops, declaration);
1505 size = ConvertFvfToDeclaration(This, fvf, &elements);
1506 if (size == ~0U) return E_OUTOFMEMORY;
1508 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1509 HeapFree(GetProcessHeap(), 0, elements);
1513 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1514 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1515 void *parent, const struct wined3d_parent_ops *parent_ops,
1516 IWineD3DVertexShader **ppVertexShader)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1519 IWineD3DVertexShaderImpl *object;
1522 if (This->vs_selected_mode == SHADER_NONE)
1523 return WINED3DERR_INVALIDCALL;
1525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1528 ERR("Failed to allocate shader memory.\n");
1529 return E_OUTOFMEMORY;
1532 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1535 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1536 HeapFree(GetProcessHeap(), 0, object);
1540 TRACE("Created vertex shader %p.\n", object);
1541 *ppVertexShader = (IWineD3DVertexShader *)object;
1546 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1547 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1548 void *parent, const struct wined3d_parent_ops *parent_ops,
1549 IWineD3DGeometryShader **shader)
1551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1552 struct wined3d_geometryshader *object;
1555 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1558 ERR("Failed to allocate shader memory.\n");
1559 return E_OUTOFMEMORY;
1562 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1565 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1566 HeapFree(GetProcessHeap(), 0, object);
1570 TRACE("Created geometry shader %p.\n", object);
1571 *shader = (IWineD3DGeometryShader *)object;
1576 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1577 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1578 void *parent, const struct wined3d_parent_ops *parent_ops,
1579 IWineD3DPixelShader **ppPixelShader)
1581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1582 IWineD3DPixelShaderImpl *object;
1585 if (This->ps_selected_mode == SHADER_NONE)
1586 return WINED3DERR_INVALIDCALL;
1588 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1591 ERR("Failed to allocate shader memory.\n");
1592 return E_OUTOFMEMORY;
1595 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1598 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1599 HeapFree(GetProcessHeap(), 0, object);
1603 TRACE("Created pixel shader %p.\n", object);
1604 *ppPixelShader = (IWineD3DPixelShader *)object;
1609 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1610 const PALETTEENTRY *entries, void *parent, struct wined3d_palette **palette)
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1613 struct wined3d_palette *object;
1616 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1617 iface, flags, entries, palette, parent);
1619 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1622 ERR("Failed to allocate palette memory.\n");
1623 return E_OUTOFMEMORY;
1626 hr = wined3d_palette_init(object, This, flags, entries, parent);
1629 WARN("Failed to initialize palette, hr %#x.\n", hr);
1630 HeapFree(GetProcessHeap(), 0, object);
1634 TRACE("Created palette %p.\n", object);
1640 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1644 HDC dcb = NULL, dcs = NULL;
1645 WINEDDCOLORKEY colorkey;
1647 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1650 GetObjectA(hbm, sizeof(BITMAP), &bm);
1651 dcb = CreateCompatibleDC(NULL);
1653 SelectObject(dcb, hbm);
1657 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1658 * couldn't be loaded
1660 memset(&bm, 0, sizeof(bm));
1665 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1666 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1667 &wined3d_null_parent_ops, &This->logo_surface);
1670 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1675 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1676 if(FAILED(hr)) goto out;
1677 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1678 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1680 colorkey.dwColorSpaceLowValue = 0;
1681 colorkey.dwColorSpaceHighValue = 0;
1682 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1686 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1687 /* Fill the surface with a white color to show that wined3d is there */
1688 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1692 if (dcb) DeleteDC(dcb);
1693 if (hbm) DeleteObject(hbm);
1696 /* Context activation is done by the caller. */
1697 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1699 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1701 /* Under DirectX you can have texture stage operations even if no texture is
1702 bound, whereas opengl will only do texture operations when a valid texture is
1703 bound. We emulate this by creating dummy textures and binding them to each
1704 texture stage, but disable all stages by default. Hence if a stage is enabled
1705 then the default texture will kick in until replaced by a SetTexture call */
1708 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1710 /* The dummy texture does not have client storage backing */
1711 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1712 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1715 for (i = 0; i < gl_info->limits.textures; ++i)
1717 GLubyte white = 255;
1719 /* Make appropriate texture active */
1720 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1721 checkGLcall("glActiveTextureARB");
1723 /* Generate an opengl texture name */
1724 glGenTextures(1, &This->dummyTextureName[i]);
1725 checkGLcall("glGenTextures");
1726 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1728 /* Generate a dummy 2d texture (not using 1d because they cause many
1729 * DRI drivers fall back to sw) */
1730 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1731 checkGLcall("glBindTexture");
1733 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1734 checkGLcall("glTexImage2D");
1737 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1739 /* Reenable because if supported it is enabled by default */
1740 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1741 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1747 /* Context activation is done by the caller. */
1748 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1751 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1752 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1755 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1758 static LONG fullscreen_style(LONG style)
1760 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1761 style |= WS_POPUP | WS_SYSMENU;
1762 style &= ~(WS_CAPTION | WS_THICKFRAME);
1767 static LONG fullscreen_exstyle(LONG exstyle)
1769 /* Filter out window decorations. */
1770 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1775 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1777 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1778 BOOL filter_messages;
1779 LONG style, exstyle;
1781 TRACE("Setting up window %p for fullscreen mode.\n", window);
1783 if (device->style || device->exStyle)
1785 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1786 window, device->style, device->exStyle);
1789 device->style = GetWindowLongW(window, GWL_STYLE);
1790 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1792 style = fullscreen_style(device->style);
1793 exstyle = fullscreen_exstyle(device->exStyle);
1795 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1796 device->style, device->exStyle, style, exstyle);
1798 filter_messages = device->filter_messages;
1799 device->filter_messages = TRUE;
1801 SetWindowLongW(window, GWL_STYLE, style);
1802 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1803 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1805 device->filter_messages = filter_messages;
1808 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1810 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1811 BOOL filter_messages;
1812 LONG style, exstyle;
1814 if (!device->style && !device->exStyle) return;
1816 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1817 window, device->style, device->exStyle);
1819 style = GetWindowLongW(window, GWL_STYLE);
1820 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1822 filter_messages = device->filter_messages;
1823 device->filter_messages = TRUE;
1825 /* Only restore the style if the application didn't modify it during the
1826 * fullscreen phase. Some applications change it before calling Reset()
1827 * when switching between windowed and fullscreen modes (HL2), some
1828 * depend on the original style (Eve Online). */
1829 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1831 SetWindowLongW(window, GWL_STYLE, device->style);
1832 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1834 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1836 device->filter_messages = filter_messages;
1838 /* Delete the old values. */
1840 device->exStyle = 0;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1845 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1847 TRACE("iface %p, window %p.\n", iface, window);
1849 if (!wined3d_register_window(window, device))
1851 ERR("Failed to register window %p.\n", window);
1855 device->focus_window = window;
1856 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1861 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1863 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1865 TRACE("iface %p.\n", iface);
1867 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1868 device->focus_window = NULL;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1872 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1875 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1876 IWineD3DSwapChainImpl *swapchain = NULL;
1877 struct wined3d_context *context;
1882 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1884 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1885 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1887 TRACE("(%p) : Creating stateblock\n", This);
1888 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1891 WARN("Failed to create stateblock\n");
1894 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1895 This->updateStateBlock = This->stateBlock;
1896 wined3d_stateblock_incref(This->updateStateBlock);
1898 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1899 sizeof(*This->render_targets) * gl_info->limits.buffers);
1901 This->NumberOfPalettes = 1;
1902 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1903 if (!This->palettes || !This->render_targets)
1905 ERR("Out of memory!\n");
1909 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1910 if(!This->palettes[0]) {
1911 ERR("Out of memory!\n");
1915 for (i = 0; i < 256; ++i) {
1916 This->palettes[0][i].peRed = 0xFF;
1917 This->palettes[0][i].peGreen = 0xFF;
1918 This->palettes[0][i].peBlue = 0xFF;
1919 This->palettes[0][i].peFlags = 0xFF;
1921 This->currentPalette = 0;
1923 /* Initialize the texture unit mapping to a 1:1 mapping */
1924 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1926 if (state < gl_info->limits.fragment_samplers)
1928 This->texUnitMap[state] = state;
1929 This->rev_tex_unit_map[state] = state;
1931 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1932 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1936 /* Setup the implicit swapchain. This also initializes a context. */
1937 TRACE("Creating implicit swapchain\n");
1938 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1939 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1942 WARN("Failed to create implicit swapchain\n");
1946 This->NumberOfSwapChains = 1;
1947 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1948 if (!This->swapchains)
1950 ERR("Out of memory!\n");
1953 This->swapchains[0] = swapchain;
1955 if (swapchain->back_buffers && swapchain->back_buffers[0])
1957 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1958 This->render_targets[0] = swapchain->back_buffers[0];
1962 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1963 This->render_targets[0] = swapchain->front_buffer;
1965 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1967 /* Depth Stencil support */
1968 This->depth_stencil = This->auto_depth_stencil;
1969 if (This->depth_stencil)
1970 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1972 hr = This->shader_backend->shader_alloc_private(This);
1974 TRACE("Shader private data couldn't be allocated\n");
1977 hr = This->frag_pipe->alloc_private(This);
1979 TRACE("Fragment pipeline private data couldn't be allocated\n");
1982 hr = This->blitter->alloc_private(This);
1984 TRACE("Blitter private data couldn't be allocated\n");
1988 /* Set up some starting GL setup */
1990 /* Setup all the devices defaults */
1991 stateblock_init_default_state(This->stateBlock);
1993 context = context_acquire(This, swapchain->front_buffer);
1995 create_dummy_textures(This);
1999 /* Initialize the current view state */
2000 This->view_ident = 1;
2001 This->contexts[0]->last_was_rhw = 0;
2002 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2003 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2005 switch(wined3d_settings.offscreen_rendering_mode) {
2007 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2010 case ORM_BACKBUFFER:
2012 if (context_get_current()->aux_buffers > 0)
2014 TRACE("Using auxilliary buffer for offscreen rendering\n");
2015 This->offscreenBuffer = GL_AUX0;
2017 TRACE("Using back buffer for offscreen rendering\n");
2018 This->offscreenBuffer = GL_BACK;
2023 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2026 context_release(context);
2028 /* Clear the screen */
2029 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2030 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2033 This->d3d_initialized = TRUE;
2035 if(wined3d_settings.logo) {
2036 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2038 This->highest_dirty_ps_const = 0;
2039 This->highest_dirty_vs_const = 0;
2043 HeapFree(GetProcessHeap(), 0, This->render_targets);
2044 HeapFree(GetProcessHeap(), 0, This->swapchains);
2045 This->NumberOfSwapChains = 0;
2046 if(This->palettes) {
2047 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2048 HeapFree(GetProcessHeap(), 0, This->palettes);
2050 This->NumberOfPalettes = 0;
2052 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2054 if (This->stateBlock)
2056 wined3d_stateblock_decref(This->stateBlock);
2057 This->stateBlock = NULL;
2059 if (This->blit_priv) {
2060 This->blitter->free_private(This);
2062 if (This->fragment_priv) {
2063 This->frag_pipe->free_private(This);
2065 if (This->shader_priv) {
2066 This->shader_backend->shader_free_private(This);
2071 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2072 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 IWineD3DSwapChainImpl *swapchain = NULL;
2078 /* Setup the implicit swapchain */
2079 TRACE("Creating implicit swapchain\n");
2080 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2081 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 WARN("Failed to create implicit swapchain\n");
2088 This->NumberOfSwapChains = 1;
2089 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2090 if (!This->swapchains)
2092 ERR("Out of memory!\n");
2095 This->swapchains[0] = swapchain;
2099 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2103 static HRESULT WINAPI device_unload_resource(struct wined3d_resource *resource, void *data)
2105 TRACE("Unloading resource %p.\n", resource);
2107 resource->resource_ops->resource_unload(resource);
2112 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2113 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 const struct wined3d_gl_info *gl_info;
2117 struct IWineD3DSurfaceImpl *surface;
2118 struct wined3d_context *context;
2121 TRACE("(%p)\n", This);
2123 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2125 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2126 * it was created. Thus make sure a context is active for the glDelete* calls
2128 context = context_acquire(This, NULL);
2129 gl_info = context->gl_info;
2131 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2133 /* Unload resources */
2134 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2136 TRACE("Deleting high order patches\n");
2137 for(i = 0; i < PATCHMAP_SIZE; i++) {
2138 struct list *e1, *e2;
2139 struct WineD3DRectPatch *patch;
2140 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2141 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2142 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2146 /* Delete the mouse cursor texture */
2147 if(This->cursorTexture) {
2149 glDeleteTextures(1, &This->cursorTexture);
2151 This->cursorTexture = 0;
2154 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2155 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2157 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2158 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2161 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2162 * private data, it might contain opengl pointers
2164 if(This->depth_blt_texture) {
2166 glDeleteTextures(1, &This->depth_blt_texture);
2168 This->depth_blt_texture = 0;
2170 if (This->depth_blt_rb) {
2172 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2174 This->depth_blt_rb = 0;
2175 This->depth_blt_rb_w = 0;
2176 This->depth_blt_rb_h = 0;
2179 /* Release the update stateblock */
2180 if (wined3d_stateblock_decref(This->updateStateBlock))
2182 if (This->updateStateBlock != This->stateBlock)
2183 FIXME("Something's still holding the update stateblock.\n");
2185 This->updateStateBlock = NULL;
2188 struct wined3d_stateblock *stateblock = This->stateBlock;
2189 This->stateBlock = NULL;
2191 /* Release the stateblock */
2192 if (wined3d_stateblock_decref(stateblock))
2193 FIXME("Something's still holding the stateblock.\n");
2196 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2197 This->blitter->free_private(This);
2198 This->frag_pipe->free_private(This);
2199 This->shader_backend->shader_free_private(This);
2201 /* Release the buffers (with sanity checks)*/
2202 if (This->onscreen_depth_stencil)
2204 surface = This->onscreen_depth_stencil;
2205 This->onscreen_depth_stencil = NULL;
2206 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2209 if (This->depth_stencil)
2211 surface = This->depth_stencil;
2213 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2215 This->depth_stencil = NULL;
2216 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2217 && surface != This->auto_depth_stencil)
2219 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2223 if (This->auto_depth_stencil)
2225 surface = This->auto_depth_stencil;
2226 This->auto_depth_stencil = NULL;
2227 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2229 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2233 for (i = 1; i < gl_info->limits.buffers; ++i)
2235 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2238 surface = This->render_targets[0];
2239 TRACE("Setting rendertarget 0 to NULL\n");
2240 This->render_targets[0] = NULL;
2241 TRACE("Releasing the render target at %p\n", surface);
2242 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2244 context_release(context);
2246 for (i = 0; i < This->NumberOfSwapChains; ++i)
2248 TRACE("Releasing the implicit swapchain %u.\n", i);
2249 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2251 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2255 HeapFree(GetProcessHeap(), 0, This->swapchains);
2256 This->swapchains = NULL;
2257 This->NumberOfSwapChains = 0;
2259 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2260 HeapFree(GetProcessHeap(), 0, This->palettes);
2261 This->palettes = NULL;
2262 This->NumberOfPalettes = 0;
2264 HeapFree(GetProcessHeap(), 0, This->render_targets);
2265 This->render_targets = NULL;
2267 This->d3d_initialized = FALSE;
2272 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2276 for (i = 0; i < This->NumberOfSwapChains; ++i)
2278 TRACE("Releasing the implicit swapchain %u.\n", i);
2279 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2281 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2285 HeapFree(GetProcessHeap(), 0, This->swapchains);
2286 This->swapchains = NULL;
2287 This->NumberOfSwapChains = 0;
2291 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2292 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2293 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2295 * There is no way to deactivate thread safety once it is enabled.
2297 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 /*For now just store the flag(needed in case of ddraw) */
2301 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2305 const WINED3DDISPLAYMODE* pMode) {
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2312 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2314 /* Resize the screen even without a window:
2315 * The app could have unset it with SetCooperativeLevel, but not called
2316 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2317 * but we don't have any hwnd
2320 memset(&devmode, 0, sizeof(devmode));
2321 devmode.dmSize = sizeof(devmode);
2322 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2323 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2324 devmode.dmPelsWidth = pMode->Width;
2325 devmode.dmPelsHeight = pMode->Height;
2327 devmode.dmDisplayFrequency = pMode->RefreshRate;
2328 if (pMode->RefreshRate)
2329 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2331 /* Only change the mode if necessary */
2332 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2333 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2336 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2337 if (ret != DISP_CHANGE_SUCCESSFUL)
2339 if (devmode.dmDisplayFrequency)
2341 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2342 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2343 devmode.dmDisplayFrequency = 0;
2344 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2346 if(ret != DISP_CHANGE_SUCCESSFUL) {
2347 return WINED3DERR_NOTAVAILABLE;
2351 /* Store the new values */
2352 This->ddraw_width = pMode->Width;
2353 This->ddraw_height = pMode->Height;
2354 This->ddraw_format = pMode->Format;
2356 /* And finally clip mouse to our screen */
2357 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2358 ClipCursor(&clip_rc);
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, struct wined3d **wined3d)
2365 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2367 TRACE("iface %p, wined3d %p.\n", iface, wined3d);
2369 *wined3d = device->wined3d;
2370 wined3d_incref(*wined3d);
2372 TRACE("Returning %p.\n", *wined3d);
2377 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2381 (This->adapter->TextureRam/(1024*1024)),
2382 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2383 /* return simulated texture memory left */
2384 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2388 struct wined3d_buffer *buffer, UINT OffsetInBytes, UINT Stride)
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2392 struct wined3d_buffer *prev_buffer;
2394 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2395 iface, StreamNumber, buffer, OffsetInBytes, Stride);
2397 if (StreamNumber >= MAX_STREAMS) {
2398 WARN("Stream out of range %d\n", StreamNumber);
2399 return WINED3DERR_INVALIDCALL;
2400 } else if(OffsetInBytes & 0x3) {
2401 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2402 return WINED3DERR_INVALIDCALL;
2405 stream = &This->updateStateBlock->state.streams[StreamNumber];
2406 prev_buffer = stream->buffer;
2408 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2410 if (prev_buffer == buffer
2411 && stream->stride == Stride
2412 && stream->offset == OffsetInBytes)
2414 TRACE("Application is setting the old values over, nothing to do\n");
2418 stream->buffer = buffer;
2421 stream->stride = Stride;
2422 stream->offset = OffsetInBytes;
2425 /* Handle recording of state blocks */
2426 if (This->isRecordingState) {
2427 TRACE("Recording... not performing anything\n");
2429 wined3d_buffer_incref(buffer);
2431 wined3d_buffer_decref(prev_buffer);
2437 InterlockedIncrement(&buffer->bind_count);
2438 wined3d_buffer_incref(buffer);
2442 InterlockedDecrement(&prev_buffer->bind_count);
2443 wined3d_buffer_decref(prev_buffer);
2446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2452 UINT StreamNumber, struct wined3d_buffer **buffer, UINT *pOffset, UINT *pStride)
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 struct wined3d_stream_state *stream;
2457 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2458 iface, StreamNumber, buffer, pOffset, pStride);
2460 if (StreamNumber >= MAX_STREAMS)
2462 WARN("Stream out of range %d\n", StreamNumber);
2463 return WINED3DERR_INVALIDCALL;
2466 stream = &This->stateBlock->state.streams[StreamNumber];
2467 *buffer = stream->buffer;
2468 *pStride = stream->stride;
2469 if (pOffset) *pOffset = stream->offset;
2472 wined3d_buffer_incref(*buffer);
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 struct wined3d_stream_state *stream;
2480 UINT old_flags, oldFreq;
2482 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2484 /* Verify input at least in d3d9 this is invalid. */
2485 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2487 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2488 return WINED3DERR_INVALIDCALL;
2490 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2492 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2493 return WINED3DERR_INVALIDCALL;
2497 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2498 return WINED3DERR_INVALIDCALL;
2501 stream = &This->updateStateBlock->state.streams[StreamNumber];
2502 old_flags = stream->flags;
2503 oldFreq = stream->frequency;
2505 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2506 stream->frequency = Divider & 0x7FFFFF;
2508 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2510 if (stream->frequency != oldFreq || stream->flags != old_flags)
2511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2516 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 struct wined3d_stream_state *stream;
2520 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2522 stream = &This->updateStateBlock->state.streams[StreamNumber];
2523 *Divider = stream->flags | stream->frequency;
2525 TRACE("Returning %#x.\n", *Divider);
2531 * Get / Set & Multiply Transform
2533 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 /* Most of this routine, comments included copied from ddraw tree initially: */
2537 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2539 /* Handle recording of state blocks */
2540 if (This->isRecordingState) {
2541 TRACE("Recording... not performing anything\n");
2542 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2543 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2548 * If the new matrix is the same as the current one,
2549 * we cut off any further processing. this seems to be a reasonable
2550 * optimization because as was noticed, some apps (warcraft3 for example)
2551 * tend towards setting the same matrix repeatedly for some reason.
2553 * From here on we assume that the new matrix is different, wherever it matters.
2555 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2557 TRACE("The app is setting the same matrix over again\n");
2562 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2566 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2567 where ViewMat = Camera space, WorldMat = world space.
2569 In OpenGL, camera and world space is combined into GL_MODELVIEW
2570 matrix. The Projection matrix stay projection matrix.
2573 /* Capture the times we can just ignore the change for now */
2574 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2575 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2576 /* Handled by the state manager */
2579 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2587 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2589 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2591 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2593 *matrix = device->stateBlock->state.transforms[state];
2598 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2599 const WINED3DMATRIX *mat = NULL;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2610 if (State <= HIGHEST_TRANSFORMSTATE)
2612 mat = &This->updateStateBlock->state.transforms[State];
2616 FIXME("Unhandled transform state!!\n");
2619 multiply_matrix(&temp, mat, pMatrix);
2621 /* Apply change via set transform - will reapply to eg. lights this way */
2622 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2628 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2629 you can reference any indexes you want as long as that number max are enabled at any
2630 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2631 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2632 but when recording, just build a chain pretty much of commands to be replayed. */
2634 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2636 struct wined3d_light_info *object = NULL;
2637 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2643 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2647 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2648 return WINED3DERR_INVALIDCALL;
2651 switch(pLight->Type) {
2652 case WINED3DLIGHT_POINT:
2653 case WINED3DLIGHT_SPOT:
2654 case WINED3DLIGHT_PARALLELPOINT:
2655 case WINED3DLIGHT_GLSPOT:
2656 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2659 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2661 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2666 case WINED3DLIGHT_DIRECTIONAL:
2667 /* Ignores attenuation */
2671 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2672 return WINED3DERR_INVALIDCALL;
2675 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2677 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2678 if(object->OriginalIndex == Index) break;
2683 TRACE("Adding new light\n");
2684 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2686 ERR("Out of memory error when allocating a light\n");
2687 return E_OUTOFMEMORY;
2689 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2690 object->glIndex = -1;
2691 object->OriginalIndex = Index;
2694 /* Initialize the object */
2695 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2696 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2697 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2698 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2699 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2700 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2701 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2703 /* Save away the information */
2704 object->OriginalParms = *pLight;
2706 switch (pLight->Type) {
2707 case WINED3DLIGHT_POINT:
2709 object->lightPosn[0] = pLight->Position.x;
2710 object->lightPosn[1] = pLight->Position.y;
2711 object->lightPosn[2] = pLight->Position.z;
2712 object->lightPosn[3] = 1.0f;
2713 object->cutoff = 180.0f;
2717 case WINED3DLIGHT_DIRECTIONAL:
2719 object->lightPosn[0] = -pLight->Direction.x;
2720 object->lightPosn[1] = -pLight->Direction.y;
2721 object->lightPosn[2] = -pLight->Direction.z;
2722 object->lightPosn[3] = 0.0f;
2723 object->exponent = 0.0f;
2724 object->cutoff = 180.0f;
2727 case WINED3DLIGHT_SPOT:
2729 object->lightPosn[0] = pLight->Position.x;
2730 object->lightPosn[1] = pLight->Position.y;
2731 object->lightPosn[2] = pLight->Position.z;
2732 object->lightPosn[3] = 1.0f;
2735 object->lightDirn[0] = pLight->Direction.x;
2736 object->lightDirn[1] = pLight->Direction.y;
2737 object->lightDirn[2] = pLight->Direction.z;
2738 object->lightDirn[3] = 1.0f;
2741 * opengl-ish and d3d-ish spot lights use too different models for the
2742 * light "intensity" as a function of the angle towards the main light direction,
2743 * so we only can approximate very roughly.
2744 * however spot lights are rather rarely used in games (if ever used at all).
2745 * furthermore if still used, probably nobody pays attention to such details.
2747 if (!pLight->Falloff)
2749 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2750 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2751 * will always be 1.0 for both of them, and we don't have to care for the
2752 * rest of the rather complex calculation
2754 object->exponent = 0.0f;
2756 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2757 if (rho < 0.0001f) rho = 0.0001f;
2758 object->exponent = -0.3f/logf(cosf(rho/2));
2760 if (object->exponent > 128.0f)
2762 object->exponent = 128.0f;
2764 object->cutoff = (float) (pLight->Phi*90/M_PI);
2770 FIXME("Unrecognized light type %d\n", pLight->Type);
2773 /* Update the live definitions if the light is currently assigned a glIndex */
2774 if (object->glIndex != -1 && !This->isRecordingState) {
2775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2780 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2782 struct wined3d_light_info *lightInfo = NULL;
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2786 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2788 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2790 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2791 if(lightInfo->OriginalIndex == Index) break;
2797 TRACE("Light information requested but light not defined\n");
2798 return WINED3DERR_INVALIDCALL;
2801 *pLight = lightInfo->OriginalParms;
2806 * Get / Set Light Enable
2807 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2811 struct wined3d_light_info *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2815 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2817 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2819 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2820 if(lightInfo->OriginalIndex == Index) break;
2823 TRACE("Found light: %p\n", lightInfo);
2825 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2828 TRACE("Light enabled requested but light not defined, so defining one!\n");
2829 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2831 /* Search for it again! Should be fairly quick as near head of list */
2832 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2834 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2835 if(lightInfo->OriginalIndex == Index) break;
2840 FIXME("Adding default lights has failed dismally\n");
2841 return WINED3DERR_INVALIDCALL;
2846 if(lightInfo->glIndex != -1) {
2847 if(!This->isRecordingState) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2851 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2852 lightInfo->glIndex = -1;
2854 TRACE("Light already disabled, nothing to do\n");
2856 lightInfo->enabled = FALSE;
2858 lightInfo->enabled = TRUE;
2859 if (lightInfo->glIndex != -1) {
2861 TRACE("Nothing to do as light was enabled\n");
2864 /* Find a free gl light */
2865 for (i = 0; i < This->maxConcurrentLights; ++i)
2867 if (!This->updateStateBlock->state.lights[i])
2869 This->updateStateBlock->state.lights[i] = lightInfo;
2870 lightInfo->glIndex = i;
2874 if(lightInfo->glIndex == -1) {
2875 /* Our tests show that Windows returns D3D_OK in this situation, even with
2876 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2877 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2878 * as well for those lights.
2880 * TODO: Test how this affects rendering
2882 WARN("Too many concurrently active lights\n");
2886 /* i == lightInfo->glIndex */
2887 if(!This->isRecordingState) {
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2896 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2898 struct wined3d_light_info *lightInfo = NULL;
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2902 TRACE("(%p) : for idx(%d)\n", This, Index);
2904 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2906 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2907 if(lightInfo->OriginalIndex == Index) break;
2913 TRACE("Light enabled state requested but light not defined\n");
2914 return WINED3DERR_INVALIDCALL;
2916 /* true is 128 according to SetLightEnable */
2917 *pEnable = lightInfo->enabled ? 128 : 0;
2922 * Get / Set Clip Planes
2924 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2928 /* Validate Index */
2929 if (Index >= This->adapter->gl_info.limits.clipplanes)
2931 TRACE("Application has requested clipplane this device doesn't support\n");
2932 return WINED3DERR_INVALIDCALL;
2935 This->updateStateBlock->changed.clipplane |= 1 << Index;
2937 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2938 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2939 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2940 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2942 TRACE("Application is setting old values over, nothing to do\n");
2946 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2947 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2948 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2949 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2951 /* Handle recording of state blocks */
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2962 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p) : for idx %d\n", This, Index);
2966 /* Validate Index */
2967 if (Index >= This->adapter->gl_info.limits.clipplanes)
2969 TRACE("Application has requested clipplane this device doesn't support\n");
2970 return WINED3DERR_INVALIDCALL;
2973 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2974 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2975 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2976 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2981 * Get / Set Clip Plane Status
2982 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2984 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 FIXME("(%p) : stub\n", This);
2989 return WINED3DERR_INVALIDCALL;
2991 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2992 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 FIXME("(%p) : stub\n", This);
3001 return WINED3DERR_INVALIDCALL;
3003 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
3004 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3009 * Get / Set Material
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 This->updateStateBlock->changed.material = TRUE;
3015 This->updateStateBlock->state.material = *pMaterial;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 *pMaterial = This->updateStateBlock->state.material;
3030 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3031 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3032 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3033 pMaterial->Ambient.b, pMaterial->Ambient.a);
3034 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3035 pMaterial->Specular.b, pMaterial->Specular.a);
3036 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3037 pMaterial->Emissive.b, pMaterial->Emissive.a);
3038 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3047 struct wined3d_buffer *buffer, enum wined3d_format_id fmt)
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 struct wined3d_buffer *prev_buffer;
3052 TRACE("iface %p, buffer %p, format %s.\n",
3053 iface, buffer, debug_d3dformat(fmt));
3055 prev_buffer = This->updateStateBlock->state.index_buffer;
3057 This->updateStateBlock->changed.indices = TRUE;
3058 This->updateStateBlock->state.index_buffer = buffer;
3059 This->updateStateBlock->state.index_format = fmt;
3061 /* Handle recording of state blocks */
3062 if (This->isRecordingState) {
3063 TRACE("Recording... not performing anything\n");
3065 wined3d_buffer_incref(buffer);
3067 wined3d_buffer_decref(prev_buffer);
3071 if (prev_buffer != buffer)
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3076 InterlockedIncrement(&buffer->bind_count);
3077 wined3d_buffer_incref(buffer);
3081 InterlockedDecrement(&prev_buffer->bind_count);
3082 wined3d_buffer_decref(prev_buffer);
3089 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, struct wined3d_buffer **buffer)
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("iface %p, buffer %p.\n", iface, buffer);
3095 *buffer = This->stateBlock->state.index_buffer;
3098 wined3d_buffer_incref(*buffer);
3100 TRACE("Returning %p.\n", *buffer);
3105 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("(%p)->(%d)\n", This, BaseIndex);
3110 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3112 TRACE("Application is setting the old value over, nothing to do\n");
3116 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3122 /* The base vertex index affects the stream sources */
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p) : base_index %p\n", This, base_index);
3131 *base_index = This->stateBlock->state.base_vertex_index;
3133 TRACE("Returning %u\n", *base_index);
3139 * Get / Set Viewports
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 TRACE("(%p)\n", This);
3145 This->updateStateBlock->changed.viewport = TRUE;
3146 This->updateStateBlock->state.viewport = *pViewport;
3148 /* Handle recording of state blocks */
3149 if (This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3154 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3155 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3162 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 TRACE("(%p)\n", This);
3165 *pViewport = This->stateBlock->state.viewport;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3170 WINED3DRENDERSTATETYPE State, DWORD Value)
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 DWORD oldValue = This->stateBlock->state.render_states[State];
3175 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3177 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3178 This->updateStateBlock->state.render_states[State] = Value;
3180 /* Handle recording of state blocks */
3181 if (This->isRecordingState) {
3182 TRACE("Recording... not performing anything\n");
3186 /* Compared here and not before the assignment to allow proper stateblock recording */
3187 if(Value == oldValue) {
3188 TRACE("Application is setting the old value over, nothing to do\n");
3190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3196 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3197 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3203 *pValue = This->stateBlock->state.render_states[State];
3208 * Get / Set Sampler States
3209 * TODO: Verify against dx9 definitions
3212 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3216 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3217 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3219 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3220 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3223 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3225 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3226 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3229 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3230 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3231 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3233 /* Handle recording of state blocks */
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3239 if(oldValue == Value) {
3240 TRACE("Application is setting the old value over, nothing to do\n");
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3253 This, Sampler, debug_d3dsamplerstate(Type), Type);
3255 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3256 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3259 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3261 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3262 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3264 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3265 TRACE("(%p) : Returning %#x\n", This, *Value);
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 This->updateStateBlock->changed.scissorRect = TRUE;
3274 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3276 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3279 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3281 if(This->isRecordingState) {
3282 TRACE("Recording... not performing anything\n");
3286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 *pRect = This->updateStateBlock->state.scissor_rect;
3295 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3299 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3300 struct wined3d_vertex_declaration *pDecl)
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3303 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3305 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3308 wined3d_vertex_declaration_incref(pDecl);
3310 wined3d_vertex_declaration_decref(oldDecl);
3312 This->updateStateBlock->state.vertex_declaration = pDecl;
3313 This->updateStateBlock->changed.vertexDecl = TRUE;
3315 if (This->isRecordingState) {
3316 TRACE("Recording... not performing anything\n");
3318 } else if(pDecl == oldDecl) {
3319 /* Checked after the assignment to allow proper stateblock recording */
3320 TRACE("Application is setting the old declaration over, nothing to do\n");
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3328 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3329 struct wined3d_vertex_declaration **ppDecl)
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3335 *ppDecl = This->stateBlock->state.vertex_declaration;
3337 wined3d_vertex_declaration_incref(*ppDecl);
3342 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3347 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3348 This->updateStateBlock->changed.vertexShader = TRUE;
3350 if (This->isRecordingState) {
3351 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3352 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3353 TRACE("Recording... not performing anything\n");
3355 } else if(oldShader == pShader) {
3356 /* Checked here to allow proper stateblock recording */
3357 TRACE("App is setting the old shader over, nothing to do\n");
3361 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3362 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3363 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3370 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3372 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3373 IWineD3DVertexShader *shader;
3375 TRACE("iface %p.\n", iface);
3377 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3378 if (shader) IWineD3DVertexShader_AddRef(shader);
3380 TRACE("Returning %p.\n", shader);
3384 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3385 IWineD3DDevice *iface,
3387 CONST BOOL *srcData,
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3393 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3394 iface, srcData, start, count);
3396 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3398 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3399 for (i = 0; i < cnt; i++)
3400 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3402 for (i = start; i < cnt + start; ++i) {
3403 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3406 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3411 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3412 IWineD3DDevice *iface,
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3418 int cnt = min(count, MAX_CONST_B - start);
3420 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3421 iface, dstData, start, count);
3423 if (!dstData || cnt < 0)
3424 return WINED3DERR_INVALIDCALL;
3426 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3430 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3431 IWineD3DDevice *iface,
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3439 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3440 iface, srcData, start, count);
3442 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3444 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3445 for (i = 0; i < cnt; i++)
3446 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3447 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3449 for (i = start; i < cnt + start; ++i) {
3450 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3453 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3458 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3459 IWineD3DDevice *iface,
3464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3465 int cnt = min(count, MAX_CONST_I - start);
3467 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3468 iface, dstData, start, count);
3470 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3471 return WINED3DERR_INVALIDCALL;
3473 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3478 IWineD3DDevice *iface,
3480 CONST float *srcData,
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3487 iface, srcData, start, count);
3489 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3490 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3491 return WINED3DERR_INVALIDCALL;
3493 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3495 for (i = 0; i < count; i++)
3496 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3497 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3500 if (!This->isRecordingState)
3502 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3506 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3507 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3512 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3513 IWineD3DDevice *iface,
3518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3519 int cnt = min(count, This->d3d_vshader_constantF - start);
3521 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3522 iface, dstData, start, count);
3524 if (!dstData || cnt < 0)
3525 return WINED3DERR_INVALIDCALL;
3527 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3531 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3533 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3539 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3541 DWORD i = This->rev_tex_unit_map[unit];
3542 DWORD j = This->texUnitMap[stage];
3544 This->texUnitMap[stage] = unit;
3545 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3547 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3550 This->rev_tex_unit_map[unit] = stage;
3551 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3553 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3557 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3560 This->fixed_function_usage_map = 0;
3561 for (i = 0; i < MAX_TEXTURES; ++i)
3563 const struct wined3d_state *state = &This->stateBlock->state;
3564 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3565 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3566 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3567 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3568 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3569 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3570 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3571 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3573 if (color_op == WINED3DTOP_DISABLE) {
3574 /* Not used, and disable higher stages */
3578 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3579 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3580 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3581 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3582 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3583 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3584 This->fixed_function_usage_map |= (1 << i);
3587 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3588 This->fixed_function_usage_map |= (1 << (i + 1));
3593 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3595 unsigned int i, tex;
3598 device_update_fixed_function_usage_map(This);
3599 ffu_map = This->fixed_function_usage_map;
3601 if (This->max_ffp_textures == gl_info->limits.texture_stages
3602 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3604 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3606 if (!(ffu_map & 1)) continue;
3608 if (This->texUnitMap[i] != i) {
3609 device_map_stage(This, i, i);
3610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3611 markTextureStagesDirty(This, i);
3617 /* Now work out the mapping */
3619 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3621 if (!(ffu_map & 1)) continue;
3623 if (This->texUnitMap[i] != tex) {
3624 device_map_stage(This, i, tex);
3625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3626 markTextureStagesDirty(This, i);
3633 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3635 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3636 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3639 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3640 if (sampler_type[i] && This->texUnitMap[i] != i)
3642 device_map_stage(This, i, i);
3643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3644 if (i < gl_info->limits.texture_stages)
3646 markTextureStagesDirty(This, i);
3652 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3653 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3655 DWORD current_mapping = This->rev_tex_unit_map[unit];
3657 /* Not currently used */
3658 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3660 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3661 /* Used by a fragment sampler */
3663 if (!pshader_sampler_tokens) {
3664 /* No pixel shader, check fixed function */
3665 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3668 /* Pixel shader, check the shader's sampler map */
3669 return !pshader_sampler_tokens[current_mapping];
3672 /* Used by a vertex sampler */
3673 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3676 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3678 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3679 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3680 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3681 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3686 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3688 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3689 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3690 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3693 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3694 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3695 if (vshader_sampler_type[i])
3697 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3699 /* Already mapped somewhere */
3703 while (start >= 0) {
3704 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3706 device_map_stage(This, vsampler_idx, start);
3707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3719 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3721 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3722 const struct wined3d_state *state = &This->stateBlock->state;
3723 BOOL vs = use_vs(state);
3724 BOOL ps = use_ps(state);
3727 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3728 * that would be really messy and require shader recompilation
3729 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3730 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3732 if (ps) device_map_psamplers(This, gl_info);
3733 else device_map_fixed_function_samplers(This, gl_info);
3735 if (vs) device_map_vsamplers(This, ps, gl_info);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3742 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3743 This->updateStateBlock->changed.pixelShader = TRUE;
3745 /* Handle recording of state blocks */
3746 if (This->isRecordingState) {
3747 TRACE("Recording... not performing anything\n");
3750 if (This->isRecordingState) {
3751 TRACE("Recording... not performing anything\n");
3752 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3753 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3757 if(pShader == oldShader) {
3758 TRACE("App is setting the old pixel shader over, nothing to do\n");
3762 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3763 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3765 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3771 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3774 IWineD3DPixelShader *shader;
3776 TRACE("iface %p.\n", iface);
3778 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3779 if (shader) IWineD3DPixelShader_AddRef(shader);
3781 TRACE("Returning %p.\n", shader);
3785 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3786 IWineD3DDevice *iface,
3788 CONST BOOL *srcData,
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3794 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3795 iface, srcData, start, count);
3797 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3799 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3800 for (i = 0; i < cnt; i++)
3801 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3803 for (i = start; i < cnt + start; ++i) {
3804 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3807 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3812 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3813 IWineD3DDevice *iface,
3818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3819 int cnt = min(count, MAX_CONST_B - start);
3821 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3822 iface, dstData, start, count);
3824 if (!dstData || cnt < 0)
3825 return WINED3DERR_INVALIDCALL;
3827 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3831 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3832 IWineD3DDevice *iface,
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3840 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3841 iface, srcData, start, count);
3843 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3845 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3846 for (i = 0; i < cnt; i++)
3847 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3848 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3850 for (i = start; i < cnt + start; ++i) {
3851 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3854 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3859 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3860 IWineD3DDevice *iface,
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 int cnt = min(count, MAX_CONST_I - start);
3868 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3869 iface, dstData, start, count);
3871 if (!dstData || cnt < 0)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3878 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3879 IWineD3DDevice *iface,
3881 CONST float *srcData,
3884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3888 iface, srcData, start, count);
3890 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3891 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3892 return WINED3DERR_INVALIDCALL;
3894 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3896 for (i = 0; i < count; i++)
3897 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3898 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3901 if (!This->isRecordingState)
3903 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3907 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3908 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3913 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3914 IWineD3DDevice *iface,
3919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3920 int cnt = min(count, This->d3d_pshader_constantF - start);
3922 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3923 iface, dstData, start, count);
3925 if (!dstData || cnt < 0)
3926 return WINED3DERR_INVALIDCALL;
3928 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3932 /* Context activation is done by the caller. */
3933 /* Do not call while under the GL lock. */
3934 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3935 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3936 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3939 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3940 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3943 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3947 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3949 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3952 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3954 ERR("Source has no position mask\n");
3955 return WINED3DERR_INVALIDCALL;
3958 if (!dest->resource.allocatedMemory)
3959 buffer_get_sysmem(dest, gl_info);
3961 /* Get a pointer into the destination vbo(create one if none exists) and
3962 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3964 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3966 dest->flags |= WINED3D_BUFFER_CREATEBO;
3967 wined3d_buffer_preload(dest);
3970 if (dest->buffer_object)
3972 unsigned char extrabytes = 0;
3973 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3974 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3975 * this may write 4 extra bytes beyond the area that should be written
3977 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3978 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3979 if(!dest_conv_addr) {
3980 ERR("Out of memory\n");
3981 /* Continue without storing converted vertices */
3983 dest_conv = dest_conv_addr;
3986 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3988 static BOOL warned = FALSE;
3990 * The clipping code is not quite correct. Some things need
3991 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3992 * so disable clipping for now.
3993 * (The graphics in Half-Life are broken, and my processvertices
3994 * test crashes with IDirect3DDevice3)
4000 FIXME("Clipping is broken and disabled for now\n");
4002 } else doClip = FALSE;
4003 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4005 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4008 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4009 WINED3DTS_PROJECTION,
4011 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4012 WINED3DTS_WORLDMATRIX(0),
4015 TRACE("View mat:\n");
4016 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);
4017 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);
4018 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);
4019 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);
4021 TRACE("Proj mat:\n");
4022 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);
4023 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);
4024 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);
4025 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);
4027 TRACE("World mat:\n");
4028 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);
4029 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);
4030 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);
4031 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);
4033 /* Get the viewport */
4034 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4035 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4036 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4038 multiply_matrix(&mat,&view_mat,&world_mat);
4039 multiply_matrix(&mat,&proj_mat,&mat);
4041 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4043 for (i = 0; i < dwCount; i+= 1) {
4044 unsigned int tex_index;
4046 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4047 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4048 /* The position first */
4049 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4050 const float *p = (const float *)(element->data + i * element->stride);
4052 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4054 /* Multiplication with world, view and projection matrix */
4055 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);
4056 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);
4057 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);
4058 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);
4060 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4062 /* WARNING: The following things are taken from d3d7 and were not yet checked
4063 * against d3d8 or d3d9!
4066 /* Clipping conditions: From msdn
4068 * A vertex is clipped if it does not match the following requirements
4072 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4074 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4075 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4080 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4081 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4084 /* "Normal" viewport transformation (not clipped)
4085 * 1) The values are divided by rhw
4086 * 2) The y axis is negative, so multiply it with -1
4087 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4088 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4089 * 4) Multiply x with Width/2 and add Width/2
4090 * 5) The same for the height
4091 * 6) Add the viewpoint X and Y to the 2D coordinates and
4092 * The minimum Z value to z
4093 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4095 * Well, basically it's simply a linear transformation into viewport
4107 z *= vp.MaxZ - vp.MinZ;
4109 x += vp.Width / 2 + vp.X;
4110 y += vp.Height / 2 + vp.Y;
4115 /* That vertex got clipped
4116 * Contrary to OpenGL it is not dropped completely, it just
4117 * undergoes a different calculation.
4119 TRACE("Vertex got clipped\n");
4126 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4127 * outside of the main vertex buffer memory. That needs some more
4132 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4135 ( (float *) dest_ptr)[0] = x;
4136 ( (float *) dest_ptr)[1] = y;
4137 ( (float *) dest_ptr)[2] = z;
4138 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4140 dest_ptr += 3 * sizeof(float);
4142 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4143 dest_ptr += sizeof(float);
4148 ( (float *) dest_conv)[0] = x * w;
4149 ( (float *) dest_conv)[1] = y * w;
4150 ( (float *) dest_conv)[2] = z * w;
4151 ( (float *) dest_conv)[3] = w;
4153 dest_conv += 3 * sizeof(float);
4155 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4156 dest_conv += sizeof(float);
4160 if (DestFVF & WINED3DFVF_PSIZE) {
4161 dest_ptr += sizeof(DWORD);
4162 if(dest_conv) dest_conv += sizeof(DWORD);
4164 if (DestFVF & WINED3DFVF_NORMAL) {
4165 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4166 const float *normal = (const float *)(element->data + i * element->stride);
4167 /* AFAIK this should go into the lighting information */
4168 FIXME("Didn't expect the destination to have a normal\n");
4169 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4171 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4175 if (DestFVF & WINED3DFVF_DIFFUSE) {
4176 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4177 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4178 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4180 static BOOL warned = FALSE;
4183 ERR("No diffuse color in source, but destination has one\n");
4187 *( (DWORD *) dest_ptr) = 0xffffffff;
4188 dest_ptr += sizeof(DWORD);
4191 *( (DWORD *) dest_conv) = 0xffffffff;
4192 dest_conv += sizeof(DWORD);
4196 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4198 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4199 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4200 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4201 dest_conv += sizeof(DWORD);
4206 if (DestFVF & WINED3DFVF_SPECULAR)
4208 /* What's the color value in the feedback buffer? */
4209 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4210 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4211 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4213 static BOOL warned = FALSE;
4216 ERR("No specular color in source, but destination has one\n");
4220 *( (DWORD *) dest_ptr) = 0xFF000000;
4221 dest_ptr += sizeof(DWORD);
4224 *( (DWORD *) dest_conv) = 0xFF000000;
4225 dest_conv += sizeof(DWORD);
4229 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4231 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4232 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4233 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4234 dest_conv += sizeof(DWORD);
4239 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4240 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4241 const float *tex_coord = (const float *)(element->data + i * element->stride);
4242 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4244 ERR("No source texture, but destination requests one\n");
4245 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4246 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4249 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4251 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4261 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4262 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4263 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4264 dwCount * get_flexible_vertex_size(DestFVF),
4266 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4270 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4275 #undef copy_and_next
4277 /* Do not call while under the GL lock. */
4278 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
4279 UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, struct wined3d_buffer *dst_buffer,
4280 struct wined3d_vertex_declaration *pVertexDecl, DWORD flags, DWORD DestFVF)
4282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4283 struct wined3d_stream_info stream_info;
4284 const struct wined3d_gl_info *gl_info;
4285 struct wined3d_context *context;
4286 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4289 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, dst_buffer, pVertexDecl, flags);
4292 ERR("Output vertex declaration not implemented yet\n");
4295 /* Need any context to write to the vbo. */
4296 context = context_acquire(This, NULL);
4297 gl_info = context->gl_info;
4299 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4300 * control the streamIsUP flag, thus restore it afterwards.
4302 This->stateBlock->state.user_stream = FALSE;
4303 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4304 This->stateBlock->state.user_stream = streamWasUP;
4306 if(vbo || SrcStartIndex) {
4308 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4309 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4311 * Also get the start index in, but only loop over all elements if there's something to add at all.
4313 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4315 struct wined3d_stream_info_element *e;
4317 if (!(stream_info.use_map & (1 << i))) continue;
4319 e = &stream_info.elements[i];
4320 if (e->buffer_object)
4322 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4323 e->buffer_object = 0;
4324 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4326 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4327 vb->buffer_object = 0;
4330 if (e->data) e->data += e->stride * SrcStartIndex;
4334 hr = process_vertices_strided(This, DestIndex, VertexCount,
4335 &stream_info, dst_buffer, flags, DestFVF);
4337 context_release(context);
4343 * Get / Set Texture Stage States
4344 * TODO: Verify against dx9 definitions
4346 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4349 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4352 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4354 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4356 WARN("Invalid Type %d passed.\n", Type);
4360 if (Stage >= gl_info->limits.texture_stages)
4362 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4363 Stage, gl_info->limits.texture_stages - 1);
4367 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4368 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4369 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4371 if (This->isRecordingState) {
4372 TRACE("Recording... not performing anything\n");
4376 /* Checked after the assignments to allow proper stateblock recording */
4377 if(oldValue == Value) {
4378 TRACE("App is setting the old value over, nothing to do\n");
4382 if (Stage > This->stateBlock->state.lowest_disabled_stage
4383 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4384 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4386 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4387 * Changes in other states are important on disabled stages too
4392 if(Type == WINED3DTSS_COLOROP) {
4395 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4396 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4397 * they have to be disabled
4399 * The current stage is dirtified below.
4401 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4403 TRACE("Additionally dirtifying stage %u\n", i);
4404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4406 This->stateBlock->state.lowest_disabled_stage = Stage;
4407 TRACE("New lowest disabled: %u\n", Stage);
4408 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4409 /* Previously disabled stage enabled. Stages above it may need enabling
4410 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4411 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4413 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4416 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4418 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4420 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4423 This->stateBlock->state.lowest_disabled_stage = i;
4424 TRACE("New lowest disabled: %u\n", i);
4428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4433 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 TRACE("iface %p, stage %u, state %s, value %p.\n",
4438 iface, Stage, debug_d3dtexturestate(Type), pValue);
4440 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4442 WARN("Invalid Type %d passed.\n", Type);
4446 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4447 TRACE("Returning %#x.\n", *pValue);
4455 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4456 DWORD stage, IWineD3DBaseTexture *texture)
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4460 IWineD3DBaseTexture *prev;
4462 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4464 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4465 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4467 /* Windows accepts overflowing this array... we do not. */
4468 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4470 WARN("Ignoring invalid stage %u.\n", stage);
4474 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4475 if (texture && ((IWineD3DBaseTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4477 WARN("Rejecting attempt to set scratch texture.\n");
4478 return WINED3DERR_INVALIDCALL;
4481 This->updateStateBlock->changed.textures |= 1 << stage;
4483 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4484 TRACE("Previous texture %p.\n", prev);
4486 if (texture == prev)
4488 TRACE("App is setting the same texture again, nothing to do.\n");
4492 TRACE("Setting new texture to %p.\n", texture);
4493 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4495 if (This->isRecordingState)
4497 TRACE("Recording... not performing anything\n");
4499 if (texture) IWineD3DBaseTexture_AddRef(texture);
4500 if (prev) IWineD3DBaseTexture_Release(prev);
4507 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4508 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4509 GLenum dimensions = t->baseTexture.target;
4511 IWineD3DBaseTexture_AddRef(texture);
4513 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4516 if (!prev && stage < gl_info->limits.texture_stages)
4518 /* The source arguments for color and alpha ops have different
4519 * meanings when a NULL texture is bound, so the COLOROP and
4520 * ALPHAOP have to be dirtified. */
4521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4525 if (bind_count == 1) t->baseTexture.sampler = stage;
4530 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4531 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4533 IWineD3DBaseTexture_Release(prev);
4535 if (!texture && stage < gl_info->limits.texture_stages)
4537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4541 if (bind_count && t->baseTexture.sampler == stage)
4545 /* Search for other stages the texture is bound to. Shouldn't
4546 * happen if applications bind textures to a single stage only. */
4547 TRACE("Searching for other stages the texture is bound to.\n");
4548 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4550 if (This->updateStateBlock->state.textures[i] == t)
4552 TRACE("Texture is also bound to stage %u.\n", i);
4553 t->baseTexture.sampler = i;
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4565 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4570 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4571 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4574 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4576 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4577 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4580 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4582 IWineD3DBaseTexture_AddRef(*ppTexture);
4584 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4592 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4593 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4595 IWineD3DSwapChain *swapchain;
4598 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4599 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4601 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4604 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4608 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4609 IWineD3DSwapChain_Release(swapchain);
4612 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4619 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4621 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4623 TRACE("iface %p, caps %p.\n", iface, caps);
4625 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4628 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 IWineD3DSwapChain *swapChain;
4633 if(iSwapChain > 0) {
4634 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4635 if (hr == WINED3D_OK) {
4636 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4637 IWineD3DSwapChain_Release(swapChain);
4639 FIXME("(%p) Error getting display mode\n", This);
4642 /* Don't read the real display mode,
4643 but return the stored mode instead. X11 can't change the color
4644 depth, and some apps are pretty angry if they SetDisplayMode from
4645 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4647 Also don't relay to the swapchain because with ddraw it's possible
4648 that there isn't a swapchain at all */
4649 pMode->Width = This->ddraw_width;
4650 pMode->Height = This->ddraw_height;
4651 pMode->Format = This->ddraw_format;
4652 pMode->RefreshRate = 0;
4660 * Stateblock related functions
4663 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 struct wined3d_stateblock *stateblock;
4669 TRACE("(%p)\n", This);
4671 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4673 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4674 if (FAILED(hr)) return hr;
4676 wined3d_stateblock_decref(This->updateStateBlock);
4677 This->updateStateBlock = stateblock;
4678 This->isRecordingState = TRUE;
4680 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4685 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4686 struct wined3d_stateblock **stateblock)
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4689 struct wined3d_stateblock *object = This->updateStateBlock;
4691 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4693 if (!This->isRecordingState) {
4694 WARN("(%p) not recording! returning error\n", This);
4696 return WINED3DERR_INVALIDCALL;
4699 stateblock_init_contained_states(object);
4701 *stateblock = object;
4702 This->isRecordingState = FALSE;
4703 This->updateStateBlock = This->stateBlock;
4704 wined3d_stateblock_incref(This->updateStateBlock);
4706 TRACE("Returning stateblock %p.\n", *stateblock);
4712 * Scene related functions
4714 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4715 /* At the moment we have no need for any functionality at the beginning
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 TRACE("(%p)\n", This);
4721 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4722 return WINED3DERR_INVALIDCALL;
4724 This->inScene = TRUE;
4728 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4731 struct wined3d_context *context;
4733 TRACE("(%p)\n", This);
4735 if(!This->inScene) {
4736 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4737 return WINED3DERR_INVALIDCALL;
4740 context = context_acquire(This, NULL);
4741 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4743 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4745 context_release(context);
4747 This->inScene = FALSE;
4751 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4752 const RECT *pSourceRect, const RECT *pDestRect,
4753 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4755 IWineD3DSwapChain *swapChain = NULL;
4757 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4759 TRACE("iface %p.\n", iface);
4761 for(i = 0 ; i < swapchains ; i ++) {
4763 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4764 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4765 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4766 IWineD3DSwapChain_Release(swapChain);
4772 /* Do not call while under the GL lock. */
4773 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4774 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4776 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4777 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4780 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4781 iface, rect_count, rects, flags, color, depth, stencil);
4783 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4785 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4788 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4789 /* TODO: What about depth stencil buffers without stencil bits? */
4790 return WINED3DERR_INVALIDCALL;
4792 else if (flags & WINED3DCLEAR_TARGET)
4794 if(ds->resource.width < device->render_targets[0]->resource.width ||
4795 ds->resource.height < device->render_targets[0]->resource.height)
4797 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4803 device_get_draw_rect(device, &draw_rect);
4805 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4806 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4813 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4814 WINED3DPRIMITIVETYPE primitive_type)
4816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4820 This->updateStateBlock->changed.primitive_type = TRUE;
4821 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4824 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4825 WINED3DPRIMITIVETYPE *primitive_type)
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4831 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4833 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4836 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4842 if (!This->stateBlock->state.vertex_declaration)
4844 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4845 return WINED3DERR_INVALIDCALL;
4848 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4849 if (This->stateBlock->state.user_stream)
4851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4852 This->stateBlock->state.user_stream = FALSE;
4855 if (This->stateBlock->state.load_base_vertex_index)
4857 This->stateBlock->state.load_base_vertex_index = 0;
4858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4860 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4861 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4865 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4868 struct wined3d_buffer *index_buffer;
4872 index_buffer = This->stateBlock->state.index_buffer;
4875 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4876 * without an index buffer set. (The first time at least...)
4877 * D3D8 simply dies, but I doubt it can do much harm to return
4878 * D3DERR_INVALIDCALL there as well. */
4879 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4880 return WINED3DERR_INVALIDCALL;
4883 if (!This->stateBlock->state.vertex_declaration)
4885 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4886 return WINED3DERR_INVALIDCALL;
4889 if (This->stateBlock->state.user_stream)
4891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4892 This->stateBlock->state.user_stream = FALSE;
4894 vbo = index_buffer->buffer_object;
4896 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4898 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4903 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4905 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4909 drawPrimitive(This, index_count, startIndex, idxStride,
4910 vbo ? NULL : index_buffer->resource.allocatedMemory);
4915 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4916 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 struct wined3d_stream_state *stream;
4920 struct wined3d_buffer *vb;
4922 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4923 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4925 if (!This->stateBlock->state.vertex_declaration)
4927 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4928 return WINED3DERR_INVALIDCALL;
4931 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4932 stream = &This->stateBlock->state.streams[0];
4933 vb = stream->buffer;
4934 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4936 wined3d_buffer_decref(vb);
4938 stream->stride = VertexStreamZeroStride;
4939 This->stateBlock->state.user_stream = TRUE;
4940 This->stateBlock->state.load_base_vertex_index = 0;
4942 /* TODO: Only mark dirty if drawing from a different UP address */
4943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4945 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4947 /* MSDN specifies stream zero settings must be set to NULL */
4948 stream->buffer = NULL;
4951 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4952 * the new stream sources or use UP drawing again
4957 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4958 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4959 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 struct wined3d_stream_state *stream;
4964 struct wined3d_buffer *vb, *ib;
4966 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4967 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4969 if (!This->stateBlock->state.vertex_declaration)
4971 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4972 return WINED3DERR_INVALIDCALL;
4975 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4981 stream = &This->stateBlock->state.streams[0];
4982 vb = stream->buffer;
4983 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4985 wined3d_buffer_decref(vb);
4987 stream->stride = VertexStreamZeroStride;
4988 This->stateBlock->state.user_stream = TRUE;
4990 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4991 This->stateBlock->state.base_vertex_index = 0;
4992 This->stateBlock->state.load_base_vertex_index = 0;
4993 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4997 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4999 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5000 stream->buffer = NULL;
5002 ib = This->stateBlock->state.index_buffer;
5005 wined3d_buffer_decref(ib);
5006 This->stateBlock->state.index_buffer = NULL;
5008 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5009 * SetStreamSource to specify a vertex buffer
5015 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5016 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5020 /* Mark the state dirty until we have nicer tracking
5021 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5026 This->stateBlock->state.base_vertex_index = 0;
5027 This->up_strided = DrawPrimStrideData;
5028 drawPrimitive(This, vertex_count, 0, 0, NULL);
5029 This->up_strided = NULL;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5034 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5035 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5038 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5040 /* Mark the state dirty until we have nicer tracking
5041 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5046 This->stateBlock->state.user_stream = TRUE;
5047 This->stateBlock->state.base_vertex_index = 0;
5048 This->up_strided = DrawPrimStrideData;
5049 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5050 This->up_strided = NULL;
5054 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5055 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5056 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5058 WINED3DLOCKED_BOX src;
5059 WINED3DLOCKED_BOX dst;
5062 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5063 iface, pSourceVolume, pDestinationVolume);
5065 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5066 * dirtification to improve loading performance.
5068 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5069 if (FAILED(hr)) return hr;
5070 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5073 IWineD3DVolume_Unmap(pSourceVolume);
5077 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5079 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5081 IWineD3DVolume_Unmap(pSourceVolume);
5083 hr = IWineD3DVolume_Unmap(pSourceVolume);
5088 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5089 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5091 unsigned int level_count, i;
5092 WINED3DRESOURCETYPE type;
5095 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5097 /* Verify that the source and destination textures are non-NULL. */
5098 if (!src_texture || !dst_texture)
5100 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5101 return WINED3DERR_INVALIDCALL;
5104 if (src_texture == dst_texture)
5106 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5107 return WINED3DERR_INVALIDCALL;
5110 /* Verify that the source and destination textures are the same type. */
5111 type = IWineD3DBaseTexture_GetType(src_texture);
5112 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5114 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5115 return WINED3DERR_INVALIDCALL;
5118 /* Check that both textures have the identical numbers of levels. */
5119 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5120 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5122 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5123 return WINED3DERR_INVALIDCALL;
5126 /* Make sure that the destination texture is loaded. */
5127 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5128 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5130 /* Update every surface level of the texture. */
5133 case WINED3DRTYPE_TEXTURE:
5135 IWineD3DSurface *src_surface;
5136 IWineD3DSurface *dst_surface;
5138 for (i = 0; i < level_count; ++i)
5140 src_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5141 (IWineD3DBaseTextureImpl *)src_texture, i));
5142 dst_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5143 (IWineD3DBaseTextureImpl *)dst_texture, i));
5144 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5147 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5154 case WINED3DRTYPE_CUBETEXTURE:
5156 IWineD3DSurface *src_surface;
5157 IWineD3DSurface *dst_surface;
5159 for (i = 0; i < level_count * 6; ++i)
5161 src_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5162 (IWineD3DBaseTextureImpl *)src_texture, i));
5163 dst_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5164 (IWineD3DBaseTextureImpl *)dst_texture, i));
5165 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5168 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5175 case WINED3DRTYPE_VOLUMETEXTURE:
5177 IWineD3DVolume *src_volume;
5178 IWineD3DVolume *dst_volume;
5180 for (i = 0; i < level_count; ++i)
5182 src_volume = (IWineD3DVolume *)surface_from_resource(basetexture_get_sub_resource(
5183 (IWineD3DBaseTextureImpl *)src_texture, i));
5184 dst_volume = (IWineD3DVolume *)surface_from_resource(basetexture_get_sub_resource(
5185 (IWineD3DBaseTextureImpl *)dst_texture, i));
5186 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5189 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5197 FIXME("Unsupported texture type %#x.\n", type);
5198 return WINED3DERR_INVALIDCALL;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5205 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5207 IWineD3DSwapChain *swapchain;
5210 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5212 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5213 if (FAILED(hr)) return hr;
5215 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5216 IWineD3DSwapChain_Release(swapchain);
5221 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 IWineD3DBaseTextureImpl *texture;
5225 const struct wined3d_state *state = &This->stateBlock->state;
5227 TRACE("(%p) : %p\n", This, pNumPasses);
5229 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5231 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5233 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5234 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5236 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5238 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5239 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5242 texture = state->textures[i];
5243 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5245 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5247 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5250 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5252 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5255 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5256 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5258 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5263 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5264 state->render_states[WINED3DRS_STENCILENABLE])
5266 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5267 IWineD3DSurfaceImpl *target = This->render_targets[0];
5270 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5272 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5273 return WINED3DERR_CONFLICTINGRENDERSTATE;
5277 /* return a sensible default */
5280 TRACE("returning D3D_OK\n");
5284 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5288 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5290 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5291 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5292 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5294 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5299 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5303 PALETTEENTRY **palettes;
5305 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5307 if (PaletteNumber >= MAX_PALETTES) {
5308 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5309 return WINED3DERR_INVALIDCALL;
5312 if (PaletteNumber >= This->NumberOfPalettes) {
5313 NewSize = This->NumberOfPalettes;
5316 } while(PaletteNumber >= NewSize);
5317 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5319 ERR("Out of memory!\n");
5320 return E_OUTOFMEMORY;
5322 This->palettes = palettes;
5323 This->NumberOfPalettes = NewSize;
5326 if (!This->palettes[PaletteNumber]) {
5327 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5328 if (!This->palettes[PaletteNumber]) {
5329 ERR("Out of memory!\n");
5330 return E_OUTOFMEMORY;
5334 for (j = 0; j < 256; ++j) {
5335 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5336 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5337 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5338 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5340 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5341 TRACE("(%p) : returning\n", This);
5345 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5348 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5349 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5350 /* What happens in such situation isn't documented; Native seems to silently abort
5351 on such conditions. Return Invalid Call. */
5352 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5353 return WINED3DERR_INVALIDCALL;
5355 for (j = 0; j < 256; ++j) {
5356 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5357 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5358 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5359 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5361 TRACE("(%p) : returning\n", This);
5365 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5368 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5369 (tested with reference rasterizer). Return Invalid Call. */
5370 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5371 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5372 return WINED3DERR_INVALIDCALL;
5374 /*TODO: stateblocks */
5375 if (This->currentPalette != PaletteNumber) {
5376 This->currentPalette = PaletteNumber;
5377 dirtify_p8_texture_samplers(This);
5379 TRACE("(%p) : returning\n", This);
5383 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 WARN("(%p) : returning Invalid Call\n", This);
5389 return WINED3DERR_INVALIDCALL;
5391 /*TODO: stateblocks */
5392 *PaletteNumber = This->currentPalette;
5393 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5397 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5402 FIXME("(%p) : stub\n", This);
5406 This->softwareVertexProcessing = bSoftware;
5411 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5416 FIXME("(%p) : stub\n", This);
5419 return This->softwareVertexProcessing;
5422 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5423 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5425 IWineD3DSwapChain *swapchain;
5428 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5429 iface, swapchain_idx, raster_status);
5431 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5434 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5438 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5439 IWineD3DSwapChain_Release(swapchain);
5442 WARN("Failed to get raster status, hr %#x.\n", hr);
5449 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5452 if(nSegments != 0.0f) {
5455 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5462 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5467 FIXME("iface %p stub!\n", iface);
5473 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5474 IWineD3DSurface *src_surface, const RECT *src_rect,
5475 IWineD3DSurface *dst_surface, const POINT *dst_point)
5477 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5478 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5480 const struct wined3d_format *src_format;
5481 const struct wined3d_format *dst_format;
5482 const struct wined3d_gl_info *gl_info;
5483 struct wined3d_context *context;
5484 const unsigned char *data;
5485 UINT update_w, update_h;
5486 CONVERT_TYPES convert;
5490 struct wined3d_format format;
5492 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5493 iface, src_surface, wine_dbgstr_rect(src_rect),
5494 dst_surface, wine_dbgstr_point(dst_point));
5496 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5498 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5499 src_surface, dst_surface);
5500 return WINED3DERR_INVALIDCALL;
5503 src_format = src_impl->resource.format;
5504 dst_format = dst_impl->resource.format;
5506 if (src_format->id != dst_format->id)
5508 WARN("Source and destination surfaces should have the same format.\n");
5509 return WINED3DERR_INVALIDCALL;
5512 dst_x = dst_point ? dst_point->x : 0;
5513 dst_y = dst_point ? dst_point->y : 0;
5515 /* This call loads the OpenGL surface directly, instead of copying the
5516 * surface to the destination's sysmem copy. If surface conversion is
5517 * needed, use BltFast instead to copy in sysmem and use regular surface
5519 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5520 if (convert != NO_CONVERSION || format.convert)
5521 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5523 context = context_acquire(This, NULL);
5524 gl_info = context->gl_info;
5527 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5528 checkGLcall("glActiveTextureARB");
5531 /* Make sure the surface is loaded and up to date */
5532 surface_internal_preload(dst_impl, SRGB_RGB);
5533 surface_bind(dst_impl, gl_info, FALSE);
5535 src_w = src_impl->resource.width;
5536 src_h = src_impl->resource.height;
5537 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5538 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5540 data = src_impl->resource.allocatedMemory;
5541 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5545 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5547 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5548 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5549 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5553 data += (src_rect->top / src_format->block_height) * src_pitch;
5554 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5557 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5558 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5559 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5561 if (row_length == src_pitch)
5563 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5564 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5570 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5571 * can't use the unpack row length like below. */
5572 for (row = 0, y = dst_y; row < row_count; ++row)
5574 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5575 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5576 y += src_format->block_height;
5580 checkGLcall("glCompressedTexSubImage2DARB");
5586 data += src_rect->top * src_w * src_format->byte_count;
5587 data += src_rect->left * src_format->byte_count;
5590 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5591 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5592 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5594 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5595 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5596 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5597 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5598 checkGLcall("glTexSubImage2D");
5602 context_release(context);
5604 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5605 sampler = This->rev_tex_unit_map[0];
5606 if (sampler != WINED3D_UNMAPPED_STAGE)
5608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5614 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 struct WineD3DRectPatch *patch;
5617 GLenum old_primitive_type;
5621 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5623 if(!(Handle || pRectPatchInfo)) {
5624 /* TODO: Write a test for the return value, thus the FIXME */
5625 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5626 return WINED3DERR_INVALIDCALL;
5630 i = PATCHMAP_HASHFUNC(Handle);
5632 LIST_FOR_EACH(e, &This->patches[i]) {
5633 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5634 if(patch->Handle == Handle) {
5641 TRACE("Patch does not exist. Creating a new one\n");
5642 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5643 patch->Handle = Handle;
5644 list_add_head(&This->patches[i], &patch->entry);
5646 TRACE("Found existing patch %p\n", patch);
5649 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5650 * attributes we have to tesselate, read back, and draw. This needs a patch
5651 * management structure instance. Create one.
5653 * A possible improvement is to check if a vertex shader is used, and if not directly
5656 FIXME("Drawing an uncached patch. This is slow\n");
5657 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5660 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5661 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5662 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5665 TRACE("Tesselation density or patch info changed, retesselating\n");
5667 if(pRectPatchInfo) {
5668 patch->RectPatchInfo = *pRectPatchInfo;
5670 patch->numSegs[0] = pNumSegs[0];
5671 patch->numSegs[1] = pNumSegs[1];
5672 patch->numSegs[2] = pNumSegs[2];
5673 patch->numSegs[3] = pNumSegs[3];
5675 hr = tesselate_rectpatch(This, patch);
5677 WARN("Patch tesselation failed\n");
5679 /* Do not release the handle to store the params of the patch */
5681 HeapFree(GetProcessHeap(), 0, patch);
5687 This->currentPatch = patch;
5688 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5689 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5690 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5691 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5692 This->currentPatch = NULL;
5694 /* Destroy uncached patches */
5696 HeapFree(GetProcessHeap(), 0, patch->mem);
5697 HeapFree(GetProcessHeap(), 0, patch);
5702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5703 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5705 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5706 iface, handle, segment_count, patch_info);
5711 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5714 struct WineD3DRectPatch *patch;
5716 TRACE("(%p) Handle(%d)\n", This, Handle);
5718 i = PATCHMAP_HASHFUNC(Handle);
5719 LIST_FOR_EACH(e, &This->patches[i]) {
5720 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5721 if(patch->Handle == Handle) {
5722 TRACE("Deleting patch %p\n", patch);
5723 list_remove(&patch->entry);
5724 HeapFree(GetProcessHeap(), 0, patch->mem);
5725 HeapFree(GetProcessHeap(), 0, patch);
5730 /* TODO: Write a test for the return value */
5731 FIXME("Attempt to destroy nonexistent patch\n");
5732 return WINED3DERR_INVALIDCALL;
5735 /* Do not call while under the GL lock. */
5736 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5737 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5739 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5741 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5742 iface, surface, wine_dbgstr_rect(rect),
5743 color->r, color->g, color->b, color->a);
5745 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5747 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5748 return WINED3DERR_INVALIDCALL;
5751 return surface_color_fill(s, rect, color);
5754 /* Do not call while under the GL lock. */
5755 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5756 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5758 struct wined3d_resource *resource;
5761 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5764 ERR("Failed to get resource, hr %#x\n", hr);
5768 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5770 FIXME("Only supported on surface resources\n");
5774 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5775 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5778 /* rendertarget and depth stencil functions */
5779 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5780 DWORD render_target_idx, IWineD3DSurface **render_target)
5782 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5784 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5785 iface, render_target_idx, render_target);
5787 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5789 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5790 return WINED3DERR_INVALIDCALL;
5793 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5794 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5796 TRACE("Returning render target %p.\n", *render_target);
5801 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5803 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5805 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5807 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5808 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5809 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5810 IWineD3DSurface_AddRef(*depth_stencil);
5815 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5816 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5818 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5819 IWineD3DSurfaceImpl *prev;
5821 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5822 iface, render_target_idx, render_target, set_viewport);
5824 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5826 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5827 return WINED3DERR_INVALIDCALL;
5830 prev = device->render_targets[render_target_idx];
5831 if (render_target == (IWineD3DSurface *)prev)
5833 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5837 /* Render target 0 can't be set to NULL. */
5838 if (!render_target && !render_target_idx)
5840 WARN("Trying to set render target 0 to NULL.\n");
5841 return WINED3DERR_INVALIDCALL;
5844 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5846 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5847 return WINED3DERR_INVALIDCALL;
5850 if (render_target) IWineD3DSurface_AddRef(render_target);
5851 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5852 /* Release after the assignment, to prevent device_resource_released()
5853 * from seeing the surface as still in use. */
5854 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5856 /* Render target 0 is special. */
5857 if (!render_target_idx && set_viewport)
5859 /* Set the viewport and scissor rectangles, if requested. Tests show
5860 * that stateblock recording is ignored, the change goes directly
5861 * into the primary stateblock. */
5862 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5863 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5864 device->stateBlock->state.viewport.X = 0;
5865 device->stateBlock->state.viewport.Y = 0;
5866 device->stateBlock->state.viewport.MaxZ = 1.0f;
5867 device->stateBlock->state.viewport.MinZ = 0.0f;
5868 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5870 device->stateBlock->state.scissor_rect.top = 0;
5871 device->stateBlock->state.scissor_rect.left = 0;
5872 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5873 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5874 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5880 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 IWineD3DSurfaceImpl *tmp;
5885 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5887 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5889 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5893 if (This->depth_stencil)
5895 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5896 || This->depth_stencil->flags & SFLAG_DISCARD)
5898 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5899 This->depth_stencil->resource.width,
5900 This->depth_stencil->resource.height);
5901 if (This->depth_stencil == This->onscreen_depth_stencil)
5903 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5904 This->onscreen_depth_stencil = NULL;
5909 tmp = This->depth_stencil;
5910 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5911 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5912 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5914 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5916 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5925 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5926 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5929 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5930 WINED3DLOCKED_RECT lockedRect;
5932 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5933 iface, XHotSpot, YHotSpot, cursor_image);
5935 /* some basic validation checks */
5936 if (This->cursorTexture)
5938 struct wined3d_context *context = context_acquire(This, NULL);
5940 glDeleteTextures(1, &This->cursorTexture);
5942 context_release(context);
5943 This->cursorTexture = 0;
5946 if (s->resource.width == 32 && s->resource.height == 32)
5947 This->haveHardwareCursor = TRUE;
5949 This->haveHardwareCursor = FALSE;
5953 WINED3DLOCKED_RECT rect;
5955 /* MSDN: Cursor must be A8R8G8B8 */
5956 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5958 WARN("surface %p has an invalid format.\n", cursor_image);
5959 return WINED3DERR_INVALIDCALL;
5962 /* MSDN: Cursor must be smaller than the display mode */
5963 if (s->resource.width > This->ddraw_width
5964 || s->resource.height > This->ddraw_height)
5966 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5967 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5968 return WINED3DERR_INVALIDCALL;
5971 if (!This->haveHardwareCursor) {
5972 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5974 /* Do not store the surface's pointer because the application may
5975 * release it after setting the cursor image. Windows doesn't
5976 * addref the set surface, so we can't do this either without
5977 * creating circular refcount dependencies. Copy out the gl texture
5980 This->cursorWidth = s->resource.width;
5981 This->cursorHeight = s->resource.height;
5982 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5984 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5985 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5986 struct wined3d_context *context;
5987 char *mem, *bits = rect.pBits;
5988 GLint intfmt = format->glInternal;
5989 GLint gl_format = format->glFormat;
5990 GLint type = format->glType;
5991 INT height = This->cursorHeight;
5992 INT width = This->cursorWidth;
5993 INT bpp = format->byte_count;
5997 /* Reformat the texture memory (pitch and width can be
5999 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6000 for(i = 0; i < height; i++)
6001 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6002 IWineD3DSurface_Unmap(cursor_image);
6004 context = context_acquire(This, NULL);
6008 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6010 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6011 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6014 /* Make sure that a proper texture unit is selected */
6015 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6016 checkGLcall("glActiveTextureARB");
6017 sampler = This->rev_tex_unit_map[0];
6018 if (sampler != WINED3D_UNMAPPED_STAGE)
6020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6022 /* Create a new cursor texture */
6023 glGenTextures(1, &This->cursorTexture);
6024 checkGLcall("glGenTextures");
6025 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6026 checkGLcall("glBindTexture");
6027 /* Copy the bitmap memory into the cursor texture */
6028 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6029 checkGLcall("glTexImage2D");
6030 HeapFree(GetProcessHeap(), 0, mem);
6032 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6040 context_release(context);
6044 FIXME("A cursor texture was not returned.\n");
6045 This->cursorTexture = 0;
6050 /* Draw a hardware cursor */
6051 ICONINFO cursorInfo;
6053 /* Create and clear maskBits because it is not needed for
6054 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6056 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6057 (s->resource.width * s->resource.height / 8));
6058 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6059 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6060 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6062 cursorInfo.fIcon = FALSE;
6063 cursorInfo.xHotspot = XHotSpot;
6064 cursorInfo.yHotspot = YHotSpot;
6065 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6066 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6067 IWineD3DSurface_Unmap(cursor_image);
6068 /* Create our cursor and clean up. */
6069 cursor = CreateIconIndirect(&cursorInfo);
6071 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6072 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6073 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6074 This->hardwareCursor = cursor;
6075 HeapFree(GetProcessHeap(), 0, maskBits);
6079 This->xHotSpot = XHotSpot;
6080 This->yHotSpot = YHotSpot;
6084 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6085 int XScreenSpace, int YScreenSpace, DWORD flags)
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6089 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6090 iface, XScreenSpace, YScreenSpace, flags);
6092 This->xScreenSpace = XScreenSpace;
6093 This->yScreenSpace = YScreenSpace;
6096 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6098 BOOL oldVisible = This->bCursorVisible;
6101 TRACE("(%p) : visible(%d)\n", This, bShow);
6104 * When ShowCursor is first called it should make the cursor appear at the OS's last
6105 * known cursor position. Because of this, some applications just repetitively call
6106 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6109 This->xScreenSpace = pt.x;
6110 This->yScreenSpace = pt.y;
6112 if (This->haveHardwareCursor) {
6113 This->bCursorVisible = bShow;
6115 SetCursor(This->hardwareCursor);
6121 if (This->cursorTexture)
6122 This->bCursorVisible = bShow;
6128 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6130 TRACE("checking resource %p for eviction\n", resource);
6132 if (resource->pool == WINED3DPOOL_MANAGED)
6134 TRACE("Evicting %p.\n", resource);
6135 resource->resource_ops->resource_unload(resource);
6141 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6143 TRACE("iface %p.\n", iface);
6145 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6146 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6147 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6152 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6154 IWineD3DDeviceImpl *device = surface->resource.device;
6155 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6157 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6158 if (surface->flags & SFLAG_DIBSECTION)
6160 /* Release the DC */
6161 SelectObject(surface->hDC, surface->dib.holdbitmap);
6162 DeleteDC(surface->hDC);
6163 /* Release the DIB section */
6164 DeleteObject(surface->dib.DIBsection);
6165 surface->dib.bitmap_data = NULL;
6166 surface->resource.allocatedMemory = NULL;
6167 surface->flags &= ~SFLAG_DIBSECTION;
6169 surface->resource.width = pPresentationParameters->BackBufferWidth;
6170 surface->resource.height = pPresentationParameters->BackBufferHeight;
6171 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6172 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6174 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6175 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6177 surface->pow2Width = surface->pow2Height = 1;
6178 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6179 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6182 if (surface->texture_name)
6184 struct wined3d_context *context = context_acquire(device, NULL);
6186 glDeleteTextures(1, &surface->texture_name);
6188 context_release(context);
6189 surface->texture_name = 0;
6190 surface->flags &= ~SFLAG_CLIENT;
6192 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6193 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6195 surface->flags |= SFLAG_NONPOW2;
6199 surface->flags &= ~SFLAG_NONPOW2;
6201 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6202 surface->resource.allocatedMemory = NULL;
6203 surface->resource.heapMemory = NULL;
6204 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6206 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6208 if (!surface_init_sysmem(surface))
6210 return E_OUTOFMEMORY;
6215 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6218 WINED3DDISPLAYMODE m;
6221 /* All Windowed modes are supported, as is leaving the current mode */
6222 if(pp->Windowed) return TRUE;
6223 if(!pp->BackBufferWidth) return TRUE;
6224 if(!pp->BackBufferHeight) return TRUE;
6226 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6227 for (i = 0; i < count; ++i)
6229 memset(&m, 0, sizeof(m));
6230 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6232 ERR("Failed to enumerate adapter mode.\n");
6233 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6234 /* Mode found, it is supported. */
6237 /* Mode not found -> not supported */
6241 /* Do not call while under the GL lock. */
6242 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6244 const struct wined3d_gl_info *gl_info;
6245 struct wined3d_context *context;
6246 IWineD3DBaseShaderImpl *shader;
6248 context = context_acquire(device, NULL);
6249 gl_info = context->gl_info;
6251 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6252 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6254 device->shader_backend->shader_destroy(shader);
6258 if (device->depth_blt_texture)
6260 glDeleteTextures(1, &device->depth_blt_texture);
6261 device->depth_blt_texture = 0;
6263 if (device->depth_blt_rb)
6265 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6266 device->depth_blt_rb = 0;
6267 device->depth_blt_rb_w = 0;
6268 device->depth_blt_rb_h = 0;
6272 device->blitter->free_private(device);
6273 device->frag_pipe->free_private(device);
6274 device->shader_backend->shader_free_private(device);
6275 destroy_dummy_textures(device, gl_info);
6277 context_release(context);
6279 while (device->numContexts)
6281 context_destroy(device, device->contexts[0]);
6283 HeapFree(GetProcessHeap(), 0, swapchain->context);
6284 swapchain->context = NULL;
6285 swapchain->num_contexts = 0;
6288 /* Do not call while under the GL lock. */
6289 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6291 struct wined3d_context *context;
6293 IWineD3DSurfaceImpl *target;
6295 /* Recreate the primary swapchain's context */
6296 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6297 if (!swapchain->context)
6299 ERR("Failed to allocate memory for swapchain context array.\n");
6300 return E_OUTOFMEMORY;
6303 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6304 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6306 WARN("Failed to create context.\n");
6307 HeapFree(GetProcessHeap(), 0, swapchain->context);
6311 swapchain->context[0] = context;
6312 swapchain->num_contexts = 1;
6313 create_dummy_textures(device);
6314 context_release(context);
6316 hr = device->shader_backend->shader_alloc_private(device);
6319 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6323 hr = device->frag_pipe->alloc_private(device);
6326 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6327 device->shader_backend->shader_free_private(device);
6331 hr = device->blitter->alloc_private(device);
6334 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6335 device->frag_pipe->free_private(device);
6336 device->shader_backend->shader_free_private(device);
6343 context_acquire(device, NULL);
6344 destroy_dummy_textures(device, context->gl_info);
6345 context_release(context);
6346 context_destroy(device, context);
6347 HeapFree(GetProcessHeap(), 0, swapchain->context);
6348 swapchain->num_contexts = 0;
6352 /* Do not call while under the GL lock. */
6353 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6354 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6357 IWineD3DSwapChainImpl *swapchain;
6359 BOOL DisplayModeChanged = FALSE;
6360 WINED3DDISPLAYMODE mode;
6361 TRACE("(%p)\n", This);
6363 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6365 ERR("Failed to get the first implicit swapchain\n");
6369 if(!is_display_mode_supported(This, pPresentationParameters)) {
6370 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6371 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6372 pPresentationParameters->BackBufferHeight);
6373 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6374 return WINED3DERR_INVALIDCALL;
6377 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6378 * on an existing gl context, so there's no real need for recreation.
6380 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6382 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6384 TRACE("New params:\n");
6385 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6386 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6387 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6388 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6389 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6390 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6391 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6392 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6393 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6394 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6395 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6396 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6397 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6399 /* No special treatment of these parameters. Just store them */
6400 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6401 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6402 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6403 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6405 /* What to do about these? */
6406 if (pPresentationParameters->BackBufferCount
6407 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6408 ERR("Cannot change the back buffer count yet\n");
6410 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6411 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6412 ERR("Cannot change the back buffer format yet\n");
6415 if (pPresentationParameters->hDeviceWindow
6416 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6417 ERR("Cannot change the device window yet\n");
6419 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6423 TRACE("Creating the depth stencil buffer\n");
6425 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6426 pPresentationParameters->BackBufferWidth,
6427 pPresentationParameters->BackBufferHeight,
6428 pPresentationParameters->AutoDepthStencilFormat,
6429 pPresentationParameters->MultiSampleType,
6430 pPresentationParameters->MultiSampleQuality,
6432 (IWineD3DSurface **)&This->auto_depth_stencil);
6435 ERR("Failed to create the depth stencil buffer\n");
6436 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6437 return WINED3DERR_INVALIDCALL;
6441 if (This->onscreen_depth_stencil)
6443 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6444 This->onscreen_depth_stencil = NULL;
6447 /* Reset the depth stencil */
6448 if (pPresentationParameters->EnableAutoDepthStencil)
6449 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6451 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6453 TRACE("Resetting stateblock\n");
6454 wined3d_stateblock_decref(This->updateStateBlock);
6455 wined3d_stateblock_decref(This->stateBlock);
6457 delete_opengl_contexts(This, swapchain);
6459 if(pPresentationParameters->Windowed) {
6460 mode.Width = swapchain->orig_width;
6461 mode.Height = swapchain->orig_height;
6462 mode.RefreshRate = 0;
6463 mode.Format = swapchain->presentParms.BackBufferFormat;
6465 mode.Width = pPresentationParameters->BackBufferWidth;
6466 mode.Height = pPresentationParameters->BackBufferHeight;
6467 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6468 mode.Format = swapchain->presentParms.BackBufferFormat;
6471 /* Should Width == 800 && Height == 0 set 800x600? */
6472 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6473 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6474 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6478 if(!pPresentationParameters->Windowed) {
6479 DisplayModeChanged = TRUE;
6481 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6482 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6484 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6487 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6491 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6493 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6496 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6500 if (This->auto_depth_stencil)
6502 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6505 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6511 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6512 || DisplayModeChanged)
6514 BOOL filter = This->filter_messages;
6515 This->filter_messages = TRUE;
6517 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6519 if (!pPresentationParameters->Windowed)
6521 if (swapchain->presentParms.Windowed)
6523 HWND focus_window = This->createParms.hFocusWindow;
6524 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6525 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6527 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6528 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6532 /* switch from windowed to fs */
6533 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6534 pPresentationParameters->BackBufferWidth,
6535 pPresentationParameters->BackBufferHeight);
6539 /* Fullscreen -> fullscreen mode change */
6540 MoveWindow(swapchain->device_window, 0, 0,
6541 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6545 else if (!swapchain->presentParms.Windowed)
6547 /* Fullscreen -> windowed switch */
6548 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6549 IWineD3DDevice_ReleaseFocusWindow(iface);
6551 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6553 This->filter_messages = filter;
6555 else if (!pPresentationParameters->Windowed)
6557 DWORD style = This->style, exStyle = This->exStyle;
6558 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6559 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6560 * Reset to clear up their mess. Guild Wars also loses the device during that.
6564 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6565 pPresentationParameters->BackBufferWidth,
6566 pPresentationParameters->BackBufferHeight);
6567 This->style = style;
6568 This->exStyle = exStyle;
6571 /* Note: No parent needed for initial internal stateblock */
6572 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6573 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6574 else TRACE("Created stateblock %p\n", This->stateBlock);
6575 This->updateStateBlock = This->stateBlock;
6576 wined3d_stateblock_incref(This->updateStateBlock);
6578 stateblock_init_default_state(This->stateBlock);
6580 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6583 GetClientRect(swapchain->win_handle, &client_rect);
6585 if(!swapchain->presentParms.BackBufferCount)
6587 TRACE("Single buffered rendering\n");
6588 swapchain->render_to_fbo = FALSE;
6590 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6591 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6593 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6594 swapchain->presentParms.BackBufferWidth,
6595 swapchain->presentParms.BackBufferHeight,
6596 client_rect.right, client_rect.bottom);
6597 swapchain->render_to_fbo = TRUE;
6601 TRACE("Rendering directly to GL_BACK\n");
6602 swapchain->render_to_fbo = FALSE;
6606 hr = create_primary_opengl_context(This, swapchain);
6607 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6609 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6615 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6617 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6619 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6625 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6627 TRACE("(%p) : pParameters %p\n", This, pParameters);
6629 *pParameters = This->createParms;
6633 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6634 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6636 IWineD3DSwapChain *swapchain;
6638 TRACE("Relaying to swapchain\n");
6640 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6642 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6643 IWineD3DSwapChain_Release(swapchain);
6647 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6648 IWineD3DSwapChain *swapchain;
6650 TRACE("Relaying to swapchain\n");
6652 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6653 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6654 IWineD3DSwapChain_Release(swapchain);
6658 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6660 TRACE("device %p, resource %p.\n", device, resource);
6662 list_add_head(&device->resources, &resource->resource_list_entry);
6665 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6667 TRACE("device %p, resource %p.\n", device, resource);
6669 list_remove(&resource->resource_list_entry);
6672 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6674 WINED3DRESOURCETYPE type = resource->resourceType;
6677 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6679 context_resource_released(device, resource, type);
6683 case WINED3DRTYPE_SURFACE:
6685 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6687 if (!device->d3d_initialized) break;
6689 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6691 if (device->render_targets[i] == surface)
6693 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6694 device->render_targets[i] = NULL;
6698 if (device->depth_stencil == surface)
6700 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6701 device->depth_stencil = NULL;
6706 case WINED3DRTYPE_TEXTURE:
6707 case WINED3DRTYPE_CUBETEXTURE:
6708 case WINED3DRTYPE_VOLUMETEXTURE:
6709 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6711 IWineD3DBaseTextureImpl *texture = basetexture_from_resource(resource);
6713 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6715 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6716 texture, device->stateBlock, i);
6717 device->stateBlock->state.textures[i] = NULL;
6720 if (device->updateStateBlock != device->stateBlock
6721 && device->updateStateBlock->state.textures[i] == texture)
6723 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6724 texture, device->updateStateBlock, i);
6725 device->updateStateBlock->state.textures[i] = NULL;
6730 case WINED3DRTYPE_BUFFER:
6732 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6734 for (i = 0; i < MAX_STREAMS; ++i)
6736 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6738 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6739 buffer, device->stateBlock, i);
6740 device->stateBlock->state.streams[i].buffer = NULL;
6743 if (device->updateStateBlock != device->stateBlock
6744 && device->updateStateBlock->state.streams[i].buffer == buffer)
6746 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6747 buffer, device->updateStateBlock, i);
6748 device->updateStateBlock->state.streams[i].buffer = NULL;
6753 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6755 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6756 buffer, device->stateBlock);
6757 device->stateBlock->state.index_buffer = NULL;
6760 if (device->updateStateBlock != device->stateBlock
6761 && device->updateStateBlock->state.index_buffer == buffer)
6763 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6764 buffer, device->updateStateBlock);
6765 device->updateStateBlock->state.index_buffer = NULL;
6774 /* Remove the resource from the resourceStore */
6775 device_resource_remove(device, resource);
6777 TRACE("Resource released.\n");
6780 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6781 D3DCB_ENUMRESOURCES callback, void *data)
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 struct wined3d_resource *resource, *cursor;
6786 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6788 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6790 TRACE("enumerating resource %p.\n", resource);
6791 if (callback(resource, data) == S_FALSE)
6793 TRACE("Canceling enumeration.\n");
6801 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6804 struct wined3d_resource *resource;
6806 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6808 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6810 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6814 TRACE("Found surface %p for dc %p.\n", s, dc);
6815 *surface = (IWineD3DSurface *)s;
6821 return WINED3DERR_INVALIDCALL;
6824 /**********************************************************
6825 * IWineD3DDevice VTbl follows
6826 **********************************************************/
6828 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6830 /*** IUnknown methods ***/
6831 IWineD3DDeviceImpl_QueryInterface,
6832 IWineD3DDeviceImpl_AddRef,
6833 IWineD3DDeviceImpl_Release,
6834 /*** IWineD3DDevice methods ***/
6835 /*** Creation methods**/
6836 IWineD3DDeviceImpl_CreateBuffer,
6837 IWineD3DDeviceImpl_CreateVertexBuffer,
6838 IWineD3DDeviceImpl_CreateIndexBuffer,
6839 IWineD3DDeviceImpl_CreateStateBlock,
6840 IWineD3DDeviceImpl_CreateSurface,
6841 IWineD3DDeviceImpl_CreateRendertargetView,
6842 IWineD3DDeviceImpl_CreateTexture,
6843 IWineD3DDeviceImpl_CreateVolumeTexture,
6844 IWineD3DDeviceImpl_CreateVolume,
6845 IWineD3DDeviceImpl_CreateCubeTexture,
6846 IWineD3DDeviceImpl_CreateQuery,
6847 IWineD3DDeviceImpl_CreateSwapChain,
6848 IWineD3DDeviceImpl_CreateVertexDeclaration,
6849 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6850 IWineD3DDeviceImpl_CreateVertexShader,
6851 IWineD3DDeviceImpl_CreateGeometryShader,
6852 IWineD3DDeviceImpl_CreatePixelShader,
6853 IWineD3DDeviceImpl_CreatePalette,
6854 /*** Odd functions **/
6855 IWineD3DDeviceImpl_Init3D,
6856 IWineD3DDeviceImpl_InitGDI,
6857 IWineD3DDeviceImpl_Uninit3D,
6858 IWineD3DDeviceImpl_UninitGDI,
6859 IWineD3DDeviceImpl_SetMultithreaded,
6860 IWineD3DDeviceImpl_EvictManagedResources,
6861 IWineD3DDeviceImpl_GetAvailableTextureMem,
6862 IWineD3DDeviceImpl_GetBackBuffer,
6863 IWineD3DDeviceImpl_GetCreationParameters,
6864 IWineD3DDeviceImpl_GetDeviceCaps,
6865 IWineD3DDeviceImpl_GetDirect3D,
6866 IWineD3DDeviceImpl_GetDisplayMode,
6867 IWineD3DDeviceImpl_SetDisplayMode,
6868 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6869 IWineD3DDeviceImpl_GetRasterStatus,
6870 IWineD3DDeviceImpl_GetSwapChain,
6871 IWineD3DDeviceImpl_Reset,
6872 IWineD3DDeviceImpl_SetDialogBoxMode,
6873 IWineD3DDeviceImpl_SetCursorProperties,
6874 IWineD3DDeviceImpl_SetCursorPosition,
6875 IWineD3DDeviceImpl_ShowCursor,
6876 /*** Getters and setters **/
6877 IWineD3DDeviceImpl_SetClipPlane,
6878 IWineD3DDeviceImpl_GetClipPlane,
6879 IWineD3DDeviceImpl_SetClipStatus,
6880 IWineD3DDeviceImpl_GetClipStatus,
6881 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6882 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6883 IWineD3DDeviceImpl_SetDepthStencilSurface,
6884 IWineD3DDeviceImpl_GetDepthStencilSurface,
6885 IWineD3DDeviceImpl_SetGammaRamp,
6886 IWineD3DDeviceImpl_GetGammaRamp,
6887 IWineD3DDeviceImpl_SetIndexBuffer,
6888 IWineD3DDeviceImpl_GetIndexBuffer,
6889 IWineD3DDeviceImpl_SetBaseVertexIndex,
6890 IWineD3DDeviceImpl_GetBaseVertexIndex,
6891 IWineD3DDeviceImpl_SetLight,
6892 IWineD3DDeviceImpl_GetLight,
6893 IWineD3DDeviceImpl_SetLightEnable,
6894 IWineD3DDeviceImpl_GetLightEnable,
6895 IWineD3DDeviceImpl_SetMaterial,
6896 IWineD3DDeviceImpl_GetMaterial,
6897 IWineD3DDeviceImpl_SetNPatchMode,
6898 IWineD3DDeviceImpl_GetNPatchMode,
6899 IWineD3DDeviceImpl_SetPaletteEntries,
6900 IWineD3DDeviceImpl_GetPaletteEntries,
6901 IWineD3DDeviceImpl_SetPixelShader,
6902 IWineD3DDeviceImpl_GetPixelShader,
6903 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6904 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6905 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6906 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6907 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6908 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6909 IWineD3DDeviceImpl_SetRenderState,
6910 IWineD3DDeviceImpl_GetRenderState,
6911 IWineD3DDeviceImpl_SetRenderTarget,
6912 IWineD3DDeviceImpl_GetRenderTarget,
6913 IWineD3DDeviceImpl_SetSamplerState,
6914 IWineD3DDeviceImpl_GetSamplerState,
6915 IWineD3DDeviceImpl_SetScissorRect,
6916 IWineD3DDeviceImpl_GetScissorRect,
6917 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6918 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6919 IWineD3DDeviceImpl_SetStreamSource,
6920 IWineD3DDeviceImpl_GetStreamSource,
6921 IWineD3DDeviceImpl_SetStreamSourceFreq,
6922 IWineD3DDeviceImpl_GetStreamSourceFreq,
6923 IWineD3DDeviceImpl_SetTexture,
6924 IWineD3DDeviceImpl_GetTexture,
6925 IWineD3DDeviceImpl_SetTextureStageState,
6926 IWineD3DDeviceImpl_GetTextureStageState,
6927 IWineD3DDeviceImpl_SetTransform,
6928 IWineD3DDeviceImpl_GetTransform,
6929 IWineD3DDeviceImpl_SetVertexDeclaration,
6930 IWineD3DDeviceImpl_GetVertexDeclaration,
6931 IWineD3DDeviceImpl_SetVertexShader,
6932 IWineD3DDeviceImpl_GetVertexShader,
6933 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6934 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6935 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6936 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6939 IWineD3DDeviceImpl_SetViewport,
6940 IWineD3DDeviceImpl_GetViewport,
6941 IWineD3DDeviceImpl_MultiplyTransform,
6942 IWineD3DDeviceImpl_ValidateDevice,
6943 IWineD3DDeviceImpl_ProcessVertices,
6944 /*** State block ***/
6945 IWineD3DDeviceImpl_BeginStateBlock,
6946 IWineD3DDeviceImpl_EndStateBlock,
6947 /*** Scene management ***/
6948 IWineD3DDeviceImpl_BeginScene,
6949 IWineD3DDeviceImpl_EndScene,
6950 IWineD3DDeviceImpl_Present,
6951 IWineD3DDeviceImpl_Clear,
6952 IWineD3DDeviceImpl_ClearRendertargetView,
6954 IWineD3DDeviceImpl_SetPrimitiveType,
6955 IWineD3DDeviceImpl_GetPrimitiveType,
6956 IWineD3DDeviceImpl_DrawPrimitive,
6957 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6958 IWineD3DDeviceImpl_DrawPrimitiveUP,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6960 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6962 IWineD3DDeviceImpl_DrawRectPatch,
6963 IWineD3DDeviceImpl_DrawTriPatch,
6964 IWineD3DDeviceImpl_DeletePatch,
6965 IWineD3DDeviceImpl_ColorFill,
6966 IWineD3DDeviceImpl_UpdateTexture,
6967 IWineD3DDeviceImpl_UpdateSurface,
6968 IWineD3DDeviceImpl_GetFrontBufferData,
6969 /*** object tracking ***/
6970 IWineD3DDeviceImpl_EnumResources,
6971 IWineD3DDeviceImpl_GetSurfaceFromDC,
6972 IWineD3DDeviceImpl_AcquireFocusWindow,
6973 IWineD3DDeviceImpl_ReleaseFocusWindow,
6974 IWineD3DDeviceImpl_SetupFullscreenWindow,
6975 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6978 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6979 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6980 IWineD3DDeviceParent *device_parent)
6982 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6983 const struct fragment_pipeline *fragment_pipeline;
6984 struct shader_caps shader_caps;
6985 struct fragment_caps ffp_caps;
6986 WINED3DDISPLAYMODE mode;
6990 device->lpVtbl = &IWineD3DDevice_Vtbl;
6992 device->wined3d = wined3d;
6993 wined3d_incref(device->wined3d);
6994 device->adapter = wined3d->adapter_count ? adapter : NULL;
6995 device->device_parent = device_parent;
6996 list_init(&device->resources);
6997 list_init(&device->shaders);
6999 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7001 /* Get the initial screen setup for ddraw. */
7002 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7005 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7006 wined3d_decref(device->wined3d);
7009 device->ddraw_width = mode.Width;
7010 device->ddraw_height = mode.Height;
7011 device->ddraw_format = mode.Format;
7013 /* Save the creation parameters. */
7014 device->createParms.AdapterOrdinal = adapter_idx;
7015 device->createParms.DeviceType = device_type;
7016 device->createParms.hFocusWindow = focus_window;
7017 device->createParms.BehaviorFlags = flags;
7019 device->devType = device_type;
7020 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7022 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7023 device->shader_backend = adapter->shader_backend;
7025 if (device->shader_backend)
7027 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7028 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7029 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7030 device->vs_clipping = shader_caps.VSClipping;
7032 fragment_pipeline = adapter->fragment_pipe;
7033 device->frag_pipe = fragment_pipeline;
7034 if (fragment_pipeline)
7036 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7037 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7039 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7040 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7043 ERR("Failed to compile state table, hr %#x.\n", hr);
7044 wined3d_decref(device->wined3d);
7048 device->blitter = adapter->blitter;
7054 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7055 DWORD rep = This->StateTable[state].representative;
7056 struct wined3d_context *context;
7061 for(i = 0; i < This->numContexts; i++) {
7062 context = This->contexts[i];
7063 if(isStateDirty(context, rep)) continue;
7065 context->dirtyArray[context->numDirtyEntries++] = rep;
7066 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7067 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7068 context->isStateDirty[idx] |= (1 << shift);
7072 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7074 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7075 *width = context->current_rt->pow2Width;
7076 *height = context->current_rt->pow2Height;
7079 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7081 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7082 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7083 * current context's drawable, which is the size of the back buffer of the swapchain
7084 * the active context belongs to. */
7085 *width = swapchain->presentParms.BackBufferWidth;
7086 *height = swapchain->presentParms.BackBufferHeight;
7089 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7090 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7092 if (device->filter_messages)
7094 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7095 window, message, wparam, lparam);
7097 return DefWindowProcW(window, message, wparam, lparam);
7099 return DefWindowProcA(window, message, wparam, lparam);
7102 if (message == WM_DESTROY)
7104 TRACE("unregister window %p.\n", window);
7105 wined3d_unregister_window(window);
7107 if (device->focus_window == window) device->focus_window = NULL;
7108 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7112 return CallWindowProcW(proc, window, message, wparam, lparam);
7114 return CallWindowProcA(proc, window, message, wparam, lparam);