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 IWineD3DVertexDeclarationImpl *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 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)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 IWineD3DStateBlockImpl *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->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.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 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, (IWineD3DResourceImpl *)resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1114 ERR("Out of memory\n");
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1183 ERR("Out of memory\n");
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if (iSwapChain < This->NumberOfSwapChains)
1310 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1311 IWineD3DSwapChain_AddRef(*pSwapChain);
1312 TRACE("(%p) returning %p\n", This, *pSwapChain);
1315 TRACE("Swapchain out of range\n");
1317 return WINED3DERR_INVALIDCALL;
1321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1322 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1323 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 IWineD3DVertexDeclarationImpl *object = NULL;
1329 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1330 iface, declaration, parent, elements, element_count);
1332 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1335 ERR("Failed to allocate vertex declaration memory.\n");
1336 return E_OUTOFMEMORY;
1339 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1342 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1343 HeapFree(GetProcessHeap(), 0, object);
1347 TRACE("Created vertex declaration %p.\n", object);
1348 *declaration = (IWineD3DVertexDeclaration *)object;
1353 struct wined3d_fvf_convert_state
1355 const struct wined3d_gl_info *gl_info;
1356 WINED3DVERTEXELEMENT *elements;
1361 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1362 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1364 WINED3DVERTEXELEMENT *elements = state->elements;
1365 const struct wined3d_format *format;
1366 UINT offset = state->offset;
1367 UINT idx = state->idx;
1369 elements[idx].format = format_id;
1370 elements[idx].input_slot = 0;
1371 elements[idx].offset = offset;
1372 elements[idx].output_slot = 0;
1373 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1374 elements[idx].usage = usage;
1375 elements[idx].usage_idx = usage_idx;
1377 format = wined3d_get_format(state->gl_info, format_id);
1378 state->offset += format->component_count * format->component_size;
1382 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1383 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1385 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1386 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1387 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1388 BOOL has_blend_idx = has_blend &&
1389 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1390 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1391 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1392 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1393 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1394 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1395 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1397 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1398 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1399 struct wined3d_fvf_convert_state state;
1402 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1403 if (has_blend_idx) num_blends--;
1405 /* Compute declaration size */
1406 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1407 has_psize + has_diffuse + has_specular + num_textures;
1409 state.gl_info = gl_info;
1410 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1411 if (!state.elements) return ~0U;
1417 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1418 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1419 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1420 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1422 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1425 if (has_blend && (num_blends > 0))
1427 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1428 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 ERR("Unexpected amount of blend values: %u\n", num_blends);
1453 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1454 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1455 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1456 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1457 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1459 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1463 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1464 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1465 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1467 for (idx = 0; idx < num_textures; ++idx)
1469 switch ((texcoords >> (idx * 2)) & 0x03)
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1486 *ppVertexElements = state.elements;
1490 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1491 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1492 IWineD3DVertexDeclaration **declaration)
1494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1495 WINED3DVERTEXELEMENT *elements;
1499 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1501 size = ConvertFvfToDeclaration(This, fvf, &elements);
1502 if (size == ~0U) return E_OUTOFMEMORY;
1504 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1505 HeapFree(GetProcessHeap(), 0, elements);
1509 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1510 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1511 void *parent, const struct wined3d_parent_ops *parent_ops,
1512 IWineD3DVertexShader **ppVertexShader)
1514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1515 IWineD3DVertexShaderImpl *object;
1518 if (This->vs_selected_mode == SHADER_NONE)
1519 return WINED3DERR_INVALIDCALL;
1521 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1524 ERR("Failed to allocate shader memory.\n");
1525 return E_OUTOFMEMORY;
1528 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1531 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1532 HeapFree(GetProcessHeap(), 0, object);
1536 TRACE("Created vertex shader %p.\n", object);
1537 *ppVertexShader = (IWineD3DVertexShader *)object;
1542 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1543 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1544 void *parent, const struct wined3d_parent_ops *parent_ops,
1545 IWineD3DGeometryShader **shader)
1547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1548 struct wined3d_geometryshader *object;
1551 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1554 ERR("Failed to allocate shader memory.\n");
1555 return E_OUTOFMEMORY;
1558 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1561 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1562 HeapFree(GetProcessHeap(), 0, object);
1566 TRACE("Created geometry shader %p.\n", object);
1567 *shader = (IWineD3DGeometryShader *)object;
1572 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1573 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1574 void *parent, const struct wined3d_parent_ops *parent_ops,
1575 IWineD3DPixelShader **ppPixelShader)
1577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1578 IWineD3DPixelShaderImpl *object;
1581 if (This->ps_selected_mode == SHADER_NONE)
1582 return WINED3DERR_INVALIDCALL;
1584 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1587 ERR("Failed to allocate shader memory.\n");
1588 return E_OUTOFMEMORY;
1591 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1594 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1595 HeapFree(GetProcessHeap(), 0, object);
1599 TRACE("Created pixel shader %p.\n", object);
1600 *ppPixelShader = (IWineD3DPixelShader *)object;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1606 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1609 IWineD3DPaletteImpl *object;
1612 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1613 iface, flags, PalEnt, Palette, parent);
1615 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1618 ERR("Failed to allocate palette memory.\n");
1619 return E_OUTOFMEMORY;
1622 hr = wined3d_palette_init(object, This, flags, PalEnt, parent);
1625 WARN("Failed to initialize palette, hr %#x.\n", hr);
1626 HeapFree(GetProcessHeap(), 0, object);
1630 TRACE("Created palette %p.\n", object);
1631 *Palette = (IWineD3DPalette *)object;
1636 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1640 HDC dcb = NULL, dcs = NULL;
1641 WINEDDCOLORKEY colorkey;
1643 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1646 GetObjectA(hbm, sizeof(BITMAP), &bm);
1647 dcb = CreateCompatibleDC(NULL);
1649 SelectObject(dcb, hbm);
1653 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1654 * couldn't be loaded
1656 memset(&bm, 0, sizeof(bm));
1661 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1662 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1663 &wined3d_null_parent_ops, &This->logo_surface);
1666 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1671 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1672 if(FAILED(hr)) goto out;
1673 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1674 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1676 colorkey.dwColorSpaceLowValue = 0;
1677 colorkey.dwColorSpaceHighValue = 0;
1678 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1682 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1683 /* Fill the surface with a white color to show that wined3d is there */
1684 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1688 if (dcb) DeleteDC(dcb);
1689 if (hbm) DeleteObject(hbm);
1692 /* Context activation is done by the caller. */
1693 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1695 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1697 /* Under DirectX you can have texture stage operations even if no texture is
1698 bound, whereas opengl will only do texture operations when a valid texture is
1699 bound. We emulate this by creating dummy textures and binding them to each
1700 texture stage, but disable all stages by default. Hence if a stage is enabled
1701 then the default texture will kick in until replaced by a SetTexture call */
1704 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1706 /* The dummy texture does not have client storage backing */
1707 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1708 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1711 for (i = 0; i < gl_info->limits.textures; ++i)
1713 GLubyte white = 255;
1715 /* Make appropriate texture active */
1716 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1717 checkGLcall("glActiveTextureARB");
1719 /* Generate an opengl texture name */
1720 glGenTextures(1, &This->dummyTextureName[i]);
1721 checkGLcall("glGenTextures");
1722 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1724 /* Generate a dummy 2d texture (not using 1d because they cause many
1725 * DRI drivers fall back to sw) */
1726 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1727 checkGLcall("glBindTexture");
1729 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1730 checkGLcall("glTexImage2D");
1733 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1735 /* Reenable because if supported it is enabled by default */
1736 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1737 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1743 /* Context activation is done by the caller. */
1744 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1747 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1748 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1751 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1754 static LONG fullscreen_style(LONG style)
1756 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1757 style |= WS_POPUP | WS_SYSMENU;
1758 style &= ~(WS_CAPTION | WS_THICKFRAME);
1763 static LONG fullscreen_exstyle(LONG exstyle)
1765 /* Filter out window decorations. */
1766 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1771 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1774 BOOL filter_messages;
1775 LONG style, exstyle;
1777 TRACE("Setting up window %p for fullscreen mode.\n", window);
1779 if (device->style || device->exStyle)
1781 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1782 window, device->style, device->exStyle);
1785 device->style = GetWindowLongW(window, GWL_STYLE);
1786 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1788 style = fullscreen_style(device->style);
1789 exstyle = fullscreen_exstyle(device->exStyle);
1791 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1792 device->style, device->exStyle, style, exstyle);
1794 filter_messages = device->filter_messages;
1795 device->filter_messages = TRUE;
1797 SetWindowLongW(window, GWL_STYLE, style);
1798 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1799 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1801 device->filter_messages = filter_messages;
1804 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1806 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1807 BOOL filter_messages;
1808 LONG style, exstyle;
1810 if (!device->style && !device->exStyle) return;
1812 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1813 window, device->style, device->exStyle);
1815 style = GetWindowLongW(window, GWL_STYLE);
1816 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1818 filter_messages = device->filter_messages;
1819 device->filter_messages = TRUE;
1821 /* Only restore the style if the application didn't modify it during the
1822 * fullscreen phase. Some applications change it before calling Reset()
1823 * when switching between windowed and fullscreen modes (HL2), some
1824 * depend on the original style (Eve Online). */
1825 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1827 SetWindowLongW(window, GWL_STYLE, device->style);
1828 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1830 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1832 device->filter_messages = filter_messages;
1834 /* Delete the old values. */
1836 device->exStyle = 0;
1839 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1841 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1843 TRACE("iface %p, window %p.\n", iface, window);
1845 if (!wined3d_register_window(window, device))
1847 ERR("Failed to register window %p.\n", window);
1851 device->focus_window = window;
1852 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1857 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1859 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1861 TRACE("iface %p.\n", iface);
1863 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1864 device->focus_window = NULL;
1867 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1868 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1871 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1872 IWineD3DSwapChainImpl *swapchain = NULL;
1873 struct wined3d_context *context;
1878 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1880 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1881 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1883 TRACE("(%p) : Creating stateblock\n", This);
1884 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1887 WARN("Failed to create stateblock\n");
1890 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1891 This->updateStateBlock = This->stateBlock;
1892 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1894 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1895 sizeof(*This->render_targets) * gl_info->limits.buffers);
1897 This->NumberOfPalettes = 1;
1898 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1899 if (!This->palettes || !This->render_targets)
1901 ERR("Out of memory!\n");
1905 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1906 if(!This->palettes[0]) {
1907 ERR("Out of memory!\n");
1911 for (i = 0; i < 256; ++i) {
1912 This->palettes[0][i].peRed = 0xFF;
1913 This->palettes[0][i].peGreen = 0xFF;
1914 This->palettes[0][i].peBlue = 0xFF;
1915 This->palettes[0][i].peFlags = 0xFF;
1917 This->currentPalette = 0;
1919 /* Initialize the texture unit mapping to a 1:1 mapping */
1920 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1922 if (state < gl_info->limits.fragment_samplers)
1924 This->texUnitMap[state] = state;
1925 This->rev_tex_unit_map[state] = state;
1927 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1928 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1932 /* Setup the implicit swapchain. This also initializes a context. */
1933 TRACE("Creating implicit swapchain\n");
1934 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1935 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1938 WARN("Failed to create implicit swapchain\n");
1942 This->NumberOfSwapChains = 1;
1943 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1944 if (!This->swapchains)
1946 ERR("Out of memory!\n");
1949 This->swapchains[0] = swapchain;
1951 if (swapchain->back_buffers && swapchain->back_buffers[0])
1953 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1954 This->render_targets[0] = swapchain->back_buffers[0];
1958 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1959 This->render_targets[0] = swapchain->front_buffer;
1961 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1963 /* Depth Stencil support */
1964 This->depth_stencil = This->auto_depth_stencil;
1965 if (This->depth_stencil)
1966 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1968 hr = This->shader_backend->shader_alloc_private(This);
1970 TRACE("Shader private data couldn't be allocated\n");
1973 hr = This->frag_pipe->alloc_private(This);
1975 TRACE("Fragment pipeline private data couldn't be allocated\n");
1978 hr = This->blitter->alloc_private(This);
1980 TRACE("Blitter private data couldn't be allocated\n");
1984 /* Set up some starting GL setup */
1986 /* Setup all the devices defaults */
1987 stateblock_init_default_state(This->stateBlock);
1989 context = context_acquire(This, swapchain->front_buffer);
1991 create_dummy_textures(This);
1995 /* Initialize the current view state */
1996 This->view_ident = 1;
1997 This->contexts[0]->last_was_rhw = 0;
1998 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1999 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2001 switch(wined3d_settings.offscreen_rendering_mode) {
2003 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2006 case ORM_BACKBUFFER:
2008 if (context_get_current()->aux_buffers > 0)
2010 TRACE("Using auxilliary buffer for offscreen rendering\n");
2011 This->offscreenBuffer = GL_AUX0;
2013 TRACE("Using back buffer for offscreen rendering\n");
2014 This->offscreenBuffer = GL_BACK;
2019 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2022 context_release(context);
2024 /* Clear the screen */
2025 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2026 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2029 This->d3d_initialized = TRUE;
2031 if(wined3d_settings.logo) {
2032 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2034 This->highest_dirty_ps_const = 0;
2035 This->highest_dirty_vs_const = 0;
2039 HeapFree(GetProcessHeap(), 0, This->render_targets);
2040 HeapFree(GetProcessHeap(), 0, This->swapchains);
2041 This->NumberOfSwapChains = 0;
2042 if(This->palettes) {
2043 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2044 HeapFree(GetProcessHeap(), 0, This->palettes);
2046 This->NumberOfPalettes = 0;
2048 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2050 if(This->stateBlock) {
2051 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2052 This->stateBlock = NULL;
2054 if (This->blit_priv) {
2055 This->blitter->free_private(This);
2057 if (This->fragment_priv) {
2058 This->frag_pipe->free_private(This);
2060 if (This->shader_priv) {
2061 This->shader_backend->shader_free_private(This);
2066 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2067 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2070 IWineD3DSwapChainImpl *swapchain = NULL;
2073 /* Setup the implicit swapchain */
2074 TRACE("Creating implicit swapchain\n");
2075 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2076 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2079 WARN("Failed to create implicit swapchain\n");
2083 This->NumberOfSwapChains = 1;
2084 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2085 if (!This->swapchains)
2087 ERR("Out of memory!\n");
2090 This->swapchains[0] = swapchain;
2094 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2098 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2100 IWineD3DResource_UnLoad(resource);
2101 IWineD3DResource_Release(resource);
2105 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2106 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2109 const struct wined3d_gl_info *gl_info;
2110 struct wined3d_context *context;
2113 TRACE("(%p)\n", This);
2115 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2117 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2118 * it was created. Thus make sure a context is active for the glDelete* calls
2120 context = context_acquire(This, NULL);
2121 gl_info = context->gl_info;
2123 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2125 /* Unload resources */
2126 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2128 TRACE("Deleting high order patches\n");
2129 for(i = 0; i < PATCHMAP_SIZE; i++) {
2130 struct list *e1, *e2;
2131 struct WineD3DRectPatch *patch;
2132 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2133 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2134 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2138 /* Delete the mouse cursor texture */
2139 if(This->cursorTexture) {
2141 glDeleteTextures(1, &This->cursorTexture);
2143 This->cursorTexture = 0;
2146 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2147 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2149 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2150 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2153 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2154 * private data, it might contain opengl pointers
2156 if(This->depth_blt_texture) {
2158 glDeleteTextures(1, &This->depth_blt_texture);
2160 This->depth_blt_texture = 0;
2162 if (This->depth_blt_rb) {
2164 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2166 This->depth_blt_rb = 0;
2167 This->depth_blt_rb_w = 0;
2168 This->depth_blt_rb_h = 0;
2171 /* Release the update stateblock */
2172 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2173 if(This->updateStateBlock != This->stateBlock)
2174 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2176 This->updateStateBlock = NULL;
2178 { /* because were not doing proper internal refcounts releasing the primary state block
2179 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2180 to set this->stateBlock = NULL; first */
2181 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2182 This->stateBlock = NULL;
2184 /* Release the stateblock */
2185 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2186 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2190 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2191 This->blitter->free_private(This);
2192 This->frag_pipe->free_private(This);
2193 This->shader_backend->shader_free_private(This);
2195 /* Release the buffers (with sanity checks)*/
2196 if (This->onscreen_depth_stencil)
2198 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2199 This->onscreen_depth_stencil = NULL;
2202 if (This->depth_stencil)
2204 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2206 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2208 This->depth_stencil = NULL;
2209 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2210 && ds != This->auto_depth_stencil)
2212 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2216 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2217 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2219 TRACE("Setting rendertarget to NULL\n");
2220 This->render_targets[0] = NULL;
2222 if (This->auto_depth_stencil)
2224 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2226 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2228 This->auto_depth_stencil = NULL;
2231 context_release(context);
2233 for (i = 0; i < This->NumberOfSwapChains; ++i)
2235 TRACE("Releasing the implicit swapchain %u.\n", i);
2236 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2238 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2242 HeapFree(GetProcessHeap(), 0, This->swapchains);
2243 This->swapchains = NULL;
2244 This->NumberOfSwapChains = 0;
2246 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2247 HeapFree(GetProcessHeap(), 0, This->palettes);
2248 This->palettes = NULL;
2249 This->NumberOfPalettes = 0;
2251 HeapFree(GetProcessHeap(), 0, This->render_targets);
2252 This->render_targets = NULL;
2254 This->d3d_initialized = FALSE;
2259 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2263 for (i = 0; i < This->NumberOfSwapChains; ++i)
2265 TRACE("Releasing the implicit swapchain %u.\n", i);
2266 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2268 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2272 HeapFree(GetProcessHeap(), 0, This->swapchains);
2273 This->swapchains = NULL;
2274 This->NumberOfSwapChains = 0;
2278 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2279 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2280 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2282 * There is no way to deactivate thread safety once it is enabled.
2284 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2287 /*For now just store the flag(needed in case of ddraw) */
2288 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2291 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2292 const WINED3DDISPLAYMODE* pMode) {
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2295 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2299 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2301 /* Resize the screen even without a window:
2302 * The app could have unset it with SetCooperativeLevel, but not called
2303 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2304 * but we don't have any hwnd
2307 memset(&devmode, 0, sizeof(devmode));
2308 devmode.dmSize = sizeof(devmode);
2309 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2310 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2311 devmode.dmPelsWidth = pMode->Width;
2312 devmode.dmPelsHeight = pMode->Height;
2314 devmode.dmDisplayFrequency = pMode->RefreshRate;
2315 if (pMode->RefreshRate)
2316 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2318 /* Only change the mode if necessary */
2319 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2320 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2323 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2324 if (ret != DISP_CHANGE_SUCCESSFUL)
2326 if (devmode.dmDisplayFrequency)
2328 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2329 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2330 devmode.dmDisplayFrequency = 0;
2331 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2333 if(ret != DISP_CHANGE_SUCCESSFUL) {
2334 return WINED3DERR_NOTAVAILABLE;
2338 /* Store the new values */
2339 This->ddraw_width = pMode->Width;
2340 This->ddraw_height = pMode->Height;
2341 This->ddraw_format = pMode->Format;
2343 /* And finally clip mouse to our screen */
2344 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2345 ClipCursor(&clip_rc);
2350 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 *ppD3D = This->wined3d;
2353 TRACE("Returning %p.\n", *ppD3D);
2354 IWineD3D_AddRef(*ppD3D);
2358 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2361 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2362 (This->adapter->TextureRam/(1024*1024)),
2363 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2364 /* return simulated texture memory left */
2365 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2369 * Get / Set Stream Source
2371 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2372 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 struct wined3d_stream_state *stream;
2376 IWineD3DBuffer *oldSrc;
2378 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2379 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2381 if (StreamNumber >= MAX_STREAMS) {
2382 WARN("Stream out of range %d\n", StreamNumber);
2383 return WINED3DERR_INVALIDCALL;
2384 } else if(OffsetInBytes & 0x3) {
2385 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2386 return WINED3DERR_INVALIDCALL;
2389 stream = &This->updateStateBlock->state.streams[StreamNumber];
2390 oldSrc = (IWineD3DBuffer *)stream->buffer;
2392 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2394 if (oldSrc == pStreamData
2395 && stream->stride == Stride
2396 && stream->offset == OffsetInBytes)
2398 TRACE("Application is setting the old values over, nothing to do\n");
2402 stream->buffer = (struct wined3d_buffer *)pStreamData;
2405 stream->stride = Stride;
2406 stream->offset = OffsetInBytes;
2409 /* Handle recording of state blocks */
2410 if (This->isRecordingState) {
2411 TRACE("Recording... not performing anything\n");
2412 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2413 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2419 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2420 IWineD3DBuffer_AddRef(pStreamData);
2424 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2425 IWineD3DBuffer_Release(oldSrc);
2428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2434 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 struct wined3d_stream_state *stream;
2439 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2440 iface, StreamNumber, pStream, pOffset, pStride);
2442 if (StreamNumber >= MAX_STREAMS)
2444 WARN("Stream out of range %d\n", StreamNumber);
2445 return WINED3DERR_INVALIDCALL;
2448 stream = &This->stateBlock->state.streams[StreamNumber];
2449 *pStream = (IWineD3DBuffer *)stream->buffer;
2450 *pStride = stream->stride;
2451 if (pOffset) *pOffset = stream->offset;
2453 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2458 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 struct wined3d_stream_state *stream;
2461 UINT old_flags, oldFreq;
2463 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2465 /* Verify input at least in d3d9 this is invalid. */
2466 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2468 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2469 return WINED3DERR_INVALIDCALL;
2471 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2473 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2474 return WINED3DERR_INVALIDCALL;
2478 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2479 return WINED3DERR_INVALIDCALL;
2482 stream = &This->updateStateBlock->state.streams[StreamNumber];
2483 old_flags = stream->flags;
2484 oldFreq = stream->frequency;
2486 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2487 stream->frequency = Divider & 0x7FFFFF;
2489 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2491 if (stream->frequency != oldFreq || stream->flags != old_flags)
2492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2497 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2499 struct wined3d_stream_state *stream;
2501 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2503 stream = &This->updateStateBlock->state.streams[StreamNumber];
2504 *Divider = stream->flags | stream->frequency;
2506 TRACE("Returning %#x.\n", *Divider);
2512 * Get / Set & Multiply Transform
2514 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 /* Most of this routine, comments included copied from ddraw tree initially: */
2518 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2520 /* Handle recording of state blocks */
2521 if (This->isRecordingState) {
2522 TRACE("Recording... not performing anything\n");
2523 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2524 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2529 * If the new matrix is the same as the current one,
2530 * we cut off any further processing. this seems to be a reasonable
2531 * optimization because as was noticed, some apps (warcraft3 for example)
2532 * tend towards setting the same matrix repeatedly for some reason.
2534 * From here on we assume that the new matrix is different, wherever it matters.
2536 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2538 TRACE("The app is setting the same matrix over again\n");
2543 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2547 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2548 where ViewMat = Camera space, WorldMat = world space.
2550 In OpenGL, camera and world space is combined into GL_MODELVIEW
2551 matrix. The Projection matrix stay projection matrix.
2554 /* Capture the times we can just ignore the change for now */
2555 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2556 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2557 /* Handled by the state manager */
2560 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2567 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2568 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2570 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2572 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2574 *matrix = device->stateBlock->state.transforms[state];
2579 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2580 const WINED3DMATRIX *mat = NULL;
2583 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2584 * below means it will be recorded in a state block change, but it
2585 * works regardless where it is recorded.
2586 * If this is found to be wrong, change to StateBlock.
2588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2591 if (State <= HIGHEST_TRANSFORMSTATE)
2593 mat = &This->updateStateBlock->state.transforms[State];
2597 FIXME("Unhandled transform state!!\n");
2600 multiply_matrix(&temp, mat, pMatrix);
2602 /* Apply change via set transform - will reapply to eg. lights this way */
2603 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2609 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2610 you can reference any indexes you want as long as that number max are enabled at any
2611 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2612 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2613 but when recording, just build a chain pretty much of commands to be replayed. */
2615 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2617 struct wined3d_light_info *object = NULL;
2618 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2622 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2624 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2628 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2629 return WINED3DERR_INVALIDCALL;
2632 switch(pLight->Type) {
2633 case WINED3DLIGHT_POINT:
2634 case WINED3DLIGHT_SPOT:
2635 case WINED3DLIGHT_PARALLELPOINT:
2636 case WINED3DLIGHT_GLSPOT:
2637 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2640 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2642 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2643 return WINED3DERR_INVALIDCALL;
2647 case WINED3DLIGHT_DIRECTIONAL:
2648 /* Ignores attenuation */
2652 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2653 return WINED3DERR_INVALIDCALL;
2656 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2658 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2659 if(object->OriginalIndex == Index) break;
2664 TRACE("Adding new light\n");
2665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2667 ERR("Out of memory error when allocating a light\n");
2668 return E_OUTOFMEMORY;
2670 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2671 object->glIndex = -1;
2672 object->OriginalIndex = Index;
2675 /* Initialize the object */
2676 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,
2677 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2678 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2679 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2680 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2681 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2682 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2684 /* Save away the information */
2685 object->OriginalParms = *pLight;
2687 switch (pLight->Type) {
2688 case WINED3DLIGHT_POINT:
2690 object->lightPosn[0] = pLight->Position.x;
2691 object->lightPosn[1] = pLight->Position.y;
2692 object->lightPosn[2] = pLight->Position.z;
2693 object->lightPosn[3] = 1.0f;
2694 object->cutoff = 180.0f;
2698 case WINED3DLIGHT_DIRECTIONAL:
2700 object->lightPosn[0] = -pLight->Direction.x;
2701 object->lightPosn[1] = -pLight->Direction.y;
2702 object->lightPosn[2] = -pLight->Direction.z;
2703 object->lightPosn[3] = 0.0f;
2704 object->exponent = 0.0f;
2705 object->cutoff = 180.0f;
2708 case WINED3DLIGHT_SPOT:
2710 object->lightPosn[0] = pLight->Position.x;
2711 object->lightPosn[1] = pLight->Position.y;
2712 object->lightPosn[2] = pLight->Position.z;
2713 object->lightPosn[3] = 1.0f;
2716 object->lightDirn[0] = pLight->Direction.x;
2717 object->lightDirn[1] = pLight->Direction.y;
2718 object->lightDirn[2] = pLight->Direction.z;
2719 object->lightDirn[3] = 1.0f;
2722 * opengl-ish and d3d-ish spot lights use too different models for the
2723 * light "intensity" as a function of the angle towards the main light direction,
2724 * so we only can approximate very roughly.
2725 * however spot lights are rather rarely used in games (if ever used at all).
2726 * furthermore if still used, probably nobody pays attention to such details.
2728 if (!pLight->Falloff)
2730 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2731 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2732 * will always be 1.0 for both of them, and we don't have to care for the
2733 * rest of the rather complex calculation
2735 object->exponent = 0.0f;
2737 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2738 if (rho < 0.0001f) rho = 0.0001f;
2739 object->exponent = -0.3f/logf(cosf(rho/2));
2741 if (object->exponent > 128.0f)
2743 object->exponent = 128.0f;
2745 object->cutoff = (float) (pLight->Phi*90/M_PI);
2751 FIXME("Unrecognized light type %d\n", pLight->Type);
2754 /* Update the live definitions if the light is currently assigned a glIndex */
2755 if (object->glIndex != -1 && !This->isRecordingState) {
2756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2761 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2763 struct wined3d_light_info *lightInfo = NULL;
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2767 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2769 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2771 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2772 if(lightInfo->OriginalIndex == Index) break;
2778 TRACE("Light information requested but light not defined\n");
2779 return WINED3DERR_INVALIDCALL;
2782 *pLight = lightInfo->OriginalParms;
2787 * Get / Set Light Enable
2788 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2790 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2792 struct wined3d_light_info *lightInfo = NULL;
2793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2794 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2796 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2798 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2800 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2801 if(lightInfo->OriginalIndex == Index) break;
2804 TRACE("Found light: %p\n", lightInfo);
2806 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2809 TRACE("Light enabled requested but light not defined, so defining one!\n");
2810 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2812 /* Search for it again! Should be fairly quick as near head of list */
2813 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2815 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2816 if(lightInfo->OriginalIndex == Index) break;
2821 FIXME("Adding default lights has failed dismally\n");
2822 return WINED3DERR_INVALIDCALL;
2827 if(lightInfo->glIndex != -1) {
2828 if(!This->isRecordingState) {
2829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2832 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2833 lightInfo->glIndex = -1;
2835 TRACE("Light already disabled, nothing to do\n");
2837 lightInfo->enabled = FALSE;
2839 lightInfo->enabled = TRUE;
2840 if (lightInfo->glIndex != -1) {
2842 TRACE("Nothing to do as light was enabled\n");
2845 /* Find a free gl light */
2846 for (i = 0; i < This->maxConcurrentLights; ++i)
2848 if (!This->updateStateBlock->state.lights[i])
2850 This->updateStateBlock->state.lights[i] = lightInfo;
2851 lightInfo->glIndex = i;
2855 if(lightInfo->glIndex == -1) {
2856 /* Our tests show that Windows returns D3D_OK in this situation, even with
2857 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2858 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2859 * as well for those lights.
2861 * TODO: Test how this affects rendering
2863 WARN("Too many concurrently active lights\n");
2867 /* i == lightInfo->glIndex */
2868 if(!This->isRecordingState) {
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2879 struct wined3d_light_info *lightInfo = NULL;
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2883 TRACE("(%p) : for idx(%d)\n", This, Index);
2885 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2887 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2888 if(lightInfo->OriginalIndex == Index) break;
2894 TRACE("Light enabled state requested but light not defined\n");
2895 return WINED3DERR_INVALIDCALL;
2897 /* true is 128 according to SetLightEnable */
2898 *pEnable = lightInfo->enabled ? 128 : 0;
2903 * Get / Set Clip Planes
2905 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2909 /* Validate Index */
2910 if (Index >= This->adapter->gl_info.limits.clipplanes)
2912 TRACE("Application has requested clipplane this device doesn't support\n");
2913 return WINED3DERR_INVALIDCALL;
2916 This->updateStateBlock->changed.clipplane |= 1 << Index;
2918 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2919 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2920 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2921 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2923 TRACE("Application is setting old values over, nothing to do\n");
2927 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2928 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2929 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2930 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2932 /* Handle recording of state blocks */
2933 if (This->isRecordingState) {
2934 TRACE("Recording... not performing anything\n");
2938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2943 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 TRACE("(%p) : for idx %d\n", This, Index);
2947 /* Validate Index */
2948 if (Index >= This->adapter->gl_info.limits.clipplanes)
2950 TRACE("Application has requested clipplane this device doesn't support\n");
2951 return WINED3DERR_INVALIDCALL;
2954 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2955 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2956 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2957 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2962 * Get / Set Clip Plane Status
2963 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2965 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 FIXME("(%p) : stub\n", This);
2970 return WINED3DERR_INVALIDCALL;
2972 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2973 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 FIXME("(%p) : stub\n", This);
2982 return WINED3DERR_INVALIDCALL;
2984 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2985 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2990 * Get / Set Material
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 This->updateStateBlock->changed.material = TRUE;
2996 This->updateStateBlock->state.material = *pMaterial;
2998 /* Handle recording of state blocks */
2999 if (This->isRecordingState) {
3000 TRACE("Recording... not performing anything\n");
3004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3008 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 *pMaterial = This->updateStateBlock->state.material;
3011 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3012 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3013 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3014 pMaterial->Ambient.b, pMaterial->Ambient.a);
3015 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3016 pMaterial->Specular.b, pMaterial->Specular.a);
3017 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3018 pMaterial->Emissive.b, pMaterial->Emissive.a);
3019 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3027 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3028 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 IWineD3DBuffer *oldIdxs;
3033 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3034 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3036 This->updateStateBlock->changed.indices = TRUE;
3037 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3038 This->updateStateBlock->state.index_format = fmt;
3040 /* Handle recording of state blocks */
3041 if (This->isRecordingState) {
3042 TRACE("Recording... not performing anything\n");
3043 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3044 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3048 if(oldIdxs != pIndexData) {
3049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3051 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3052 IWineD3DBuffer_AddRef(pIndexData);
3055 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3056 IWineD3DBuffer_Release(oldIdxs);
3063 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3069 /* up ref count on ppindexdata */
3071 IWineD3DBuffer_AddRef(*ppIndexData);
3072 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3074 TRACE("(%p) No index data set\n", This);
3076 TRACE("Returning %p\n", *ppIndexData);
3081 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 TRACE("(%p)->(%d)\n", This, BaseIndex);
3086 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3088 TRACE("Application is setting the old value over, nothing to do\n");
3092 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3094 if (This->isRecordingState) {
3095 TRACE("Recording... not performing anything\n");
3098 /* The base vertex index affects the stream sources */
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3103 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 TRACE("(%p) : base_index %p\n", This, base_index);
3107 *base_index = This->stateBlock->state.base_vertex_index;
3109 TRACE("Returning %u\n", *base_index);
3115 * Get / Set Viewports
3117 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 TRACE("(%p)\n", This);
3121 This->updateStateBlock->changed.viewport = TRUE;
3122 This->updateStateBlock->state.viewport = *pViewport;
3124 /* Handle recording of state blocks */
3125 if (This->isRecordingState) {
3126 TRACE("Recording... not performing anything\n");
3130 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3131 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3138 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 TRACE("(%p)\n", This);
3141 *pViewport = This->stateBlock->state.viewport;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3146 WINED3DRENDERSTATETYPE State, DWORD Value)
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 DWORD oldValue = This->stateBlock->state.render_states[State];
3151 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3153 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3154 This->updateStateBlock->state.render_states[State] = Value;
3156 /* Handle recording of state blocks */
3157 if (This->isRecordingState) {
3158 TRACE("Recording... not performing anything\n");
3162 /* Compared here and not before the assignment to allow proper stateblock recording */
3163 if(Value == oldValue) {
3164 TRACE("Application is setting the old value over, nothing to do\n");
3166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3172 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3173 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3179 *pValue = This->stateBlock->state.render_states[State];
3184 * Get / Set Sampler States
3185 * TODO: Verify against dx9 definitions
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3193 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3195 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3196 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3199 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3201 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3202 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3205 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3206 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3207 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3209 /* Handle recording of state blocks */
3210 if (This->isRecordingState) {
3211 TRACE("Recording... not performing anything\n");
3215 if(oldValue == Value) {
3216 TRACE("Application is setting the old value over, nothing to do\n");
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3229 This, Sampler, debug_d3dsamplerstate(Type), Type);
3231 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3232 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3235 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3237 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3238 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3240 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3241 TRACE("(%p) : Returning %#x\n", This, *Value);
3246 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 This->updateStateBlock->changed.scissorRect = TRUE;
3250 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3252 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3255 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3257 if(This->isRecordingState) {
3258 TRACE("Recording... not performing anything\n");
3262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3267 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3270 *pRect = This->updateStateBlock->state.scissor_rect;
3271 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3275 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3277 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3279 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3281 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3282 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3284 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3285 This->updateStateBlock->changed.vertexDecl = TRUE;
3287 if (This->isRecordingState) {
3288 TRACE("Recording... not performing anything\n");
3290 } else if(pDecl == oldDecl) {
3291 /* Checked after the assignment to allow proper stateblock recording */
3292 TRACE("Application is setting the old declaration over, nothing to do\n");
3296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3300 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3303 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3305 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3306 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3310 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3315 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3316 This->updateStateBlock->changed.vertexShader = TRUE;
3318 if (This->isRecordingState) {
3319 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3320 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3321 TRACE("Recording... not performing anything\n");
3323 } else if(oldShader == pShader) {
3324 /* Checked here to allow proper stateblock recording */
3325 TRACE("App is setting the old shader over, nothing to do\n");
3329 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3330 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3331 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3338 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3340 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3341 IWineD3DVertexShader *shader;
3343 TRACE("iface %p.\n", iface);
3345 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3346 if (shader) IWineD3DVertexShader_AddRef(shader);
3348 TRACE("Returning %p.\n", shader);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3353 IWineD3DDevice *iface,
3355 CONST BOOL *srcData,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3361 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3362 iface, srcData, start, count);
3364 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3366 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3367 for (i = 0; i < cnt; i++)
3368 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3370 for (i = start; i < cnt + start; ++i) {
3371 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3374 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3380 IWineD3DDevice *iface,
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int cnt = min(count, MAX_CONST_B - start);
3388 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3389 iface, dstData, start, count);
3391 if (!dstData || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3399 IWineD3DDevice *iface,
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3407 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3408 iface, srcData, start, count);
3410 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3412 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3413 for (i = 0; i < cnt; i++)
3414 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3415 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3417 for (i = start; i < cnt + start; ++i) {
3418 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3421 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3427 IWineD3DDevice *iface,
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int cnt = min(count, MAX_CONST_I - start);
3435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3436 iface, dstData, start, count);
3438 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3439 return WINED3DERR_INVALIDCALL;
3441 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3445 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3446 IWineD3DDevice *iface,
3448 CONST float *srcData,
3451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3455 iface, srcData, start, count);
3457 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3458 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3463 for (i = 0; i < count; i++)
3464 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3465 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3468 if (!This->isRecordingState)
3470 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3474 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3475 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3480 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3481 IWineD3DDevice *iface,
3486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 int cnt = min(count, This->d3d_vshader_constantF - start);
3489 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3490 iface, dstData, start, count);
3492 if (!dstData || cnt < 0)
3493 return WINED3DERR_INVALIDCALL;
3495 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3499 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3501 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3507 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3509 DWORD i = This->rev_tex_unit_map[unit];
3510 DWORD j = This->texUnitMap[stage];
3512 This->texUnitMap[stage] = unit;
3513 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3515 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3518 This->rev_tex_unit_map[unit] = stage;
3519 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3521 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3525 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3528 This->fixed_function_usage_map = 0;
3529 for (i = 0; i < MAX_TEXTURES; ++i)
3531 const struct wined3d_state *state = &This->stateBlock->state;
3532 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3533 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3534 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3535 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3536 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3537 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3538 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3539 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3541 if (color_op == WINED3DTOP_DISABLE) {
3542 /* Not used, and disable higher stages */
3546 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3547 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3548 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3549 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3550 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3551 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3552 This->fixed_function_usage_map |= (1 << i);
3555 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3556 This->fixed_function_usage_map |= (1 << (i + 1));
3561 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3563 unsigned int i, tex;
3566 device_update_fixed_function_usage_map(This);
3567 ffu_map = This->fixed_function_usage_map;
3569 if (This->max_ffp_textures == gl_info->limits.texture_stages
3570 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3572 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3574 if (!(ffu_map & 1)) continue;
3576 if (This->texUnitMap[i] != i) {
3577 device_map_stage(This, i, i);
3578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3579 markTextureStagesDirty(This, i);
3585 /* Now work out the mapping */
3587 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3589 if (!(ffu_map & 1)) continue;
3591 if (This->texUnitMap[i] != tex) {
3592 device_map_stage(This, i, tex);
3593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3594 markTextureStagesDirty(This, i);
3601 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3603 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3604 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3607 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3608 if (sampler_type[i] && This->texUnitMap[i] != i)
3610 device_map_stage(This, i, i);
3611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3612 if (i < gl_info->limits.texture_stages)
3614 markTextureStagesDirty(This, i);
3620 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3621 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3623 DWORD current_mapping = This->rev_tex_unit_map[unit];
3625 /* Not currently used */
3626 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3628 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3629 /* Used by a fragment sampler */
3631 if (!pshader_sampler_tokens) {
3632 /* No pixel shader, check fixed function */
3633 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3636 /* Pixel shader, check the shader's sampler map */
3637 return !pshader_sampler_tokens[current_mapping];
3640 /* Used by a vertex sampler */
3641 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3644 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3646 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3647 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3648 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3649 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3654 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3656 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3657 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3658 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3661 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3662 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3663 if (vshader_sampler_type[i])
3665 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3667 /* Already mapped somewhere */
3671 while (start >= 0) {
3672 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3674 device_map_stage(This, vsampler_idx, start);
3675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3687 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3689 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3690 const struct wined3d_state *state = &This->stateBlock->state;
3691 BOOL vs = use_vs(state);
3692 BOOL ps = use_ps(state);
3695 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3696 * that would be really messy and require shader recompilation
3697 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3698 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3700 if (ps) device_map_psamplers(This, gl_info);
3701 else device_map_fixed_function_samplers(This, gl_info);
3703 if (vs) device_map_vsamplers(This, ps, gl_info);
3706 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3709 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3710 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3711 This->updateStateBlock->changed.pixelShader = TRUE;
3713 /* Handle recording of state blocks */
3714 if (This->isRecordingState) {
3715 TRACE("Recording... not performing anything\n");
3718 if (This->isRecordingState) {
3719 TRACE("Recording... not performing anything\n");
3720 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3721 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3725 if(pShader == oldShader) {
3726 TRACE("App is setting the old pixel shader over, nothing to do\n");
3730 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3731 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3733 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3739 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3741 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3742 IWineD3DPixelShader *shader;
3744 TRACE("iface %p.\n", iface);
3746 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3747 if (shader) IWineD3DPixelShader_AddRef(shader);
3749 TRACE("Returning %p.\n", shader);
3753 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3754 IWineD3DDevice *iface,
3756 CONST BOOL *srcData,
3759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3760 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3762 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3763 iface, srcData, start, count);
3765 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3768 for (i = 0; i < cnt; i++)
3769 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3771 for (i = start; i < cnt + start; ++i) {
3772 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3775 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3780 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3781 IWineD3DDevice *iface,
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int cnt = min(count, MAX_CONST_B - start);
3789 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3790 iface, dstData, start, count);
3792 if (!dstData || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3799 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3800 IWineD3DDevice *iface,
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3808 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3809 iface, srcData, start, count);
3811 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3813 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3814 for (i = 0; i < cnt; i++)
3815 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3816 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3818 for (i = start; i < cnt + start; ++i) {
3819 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3822 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3827 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3828 IWineD3DDevice *iface,
3833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3834 int cnt = min(count, MAX_CONST_I - start);
3836 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3837 iface, dstData, start, count);
3839 if (!dstData || cnt < 0)
3840 return WINED3DERR_INVALIDCALL;
3842 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3846 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3847 IWineD3DDevice *iface,
3849 CONST float *srcData,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3855 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3856 iface, srcData, start, count);
3858 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3859 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3860 return WINED3DERR_INVALIDCALL;
3862 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3864 for (i = 0; i < count; i++)
3865 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3866 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3869 if (!This->isRecordingState)
3871 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3875 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3876 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3881 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3882 IWineD3DDevice *iface,
3887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3888 int cnt = min(count, This->d3d_pshader_constantF - start);
3890 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3891 iface, dstData, start, count);
3893 if (!dstData || cnt < 0)
3894 return WINED3DERR_INVALIDCALL;
3896 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3900 /* Context activation is done by the caller. */
3901 /* Do not call while under the GL lock. */
3902 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3903 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3904 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3907 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3908 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3911 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3915 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3917 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3920 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3922 ERR("Source has no position mask\n");
3923 return WINED3DERR_INVALIDCALL;
3926 if (!dest->resource.allocatedMemory)
3927 buffer_get_sysmem(dest, gl_info);
3929 /* Get a pointer into the destination vbo(create one if none exists) and
3930 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3932 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3934 dest->flags |= WINED3D_BUFFER_CREATEBO;
3935 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3938 if (dest->buffer_object)
3940 unsigned char extrabytes = 0;
3941 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3942 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3943 * this may write 4 extra bytes beyond the area that should be written
3945 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3946 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3947 if(!dest_conv_addr) {
3948 ERR("Out of memory\n");
3949 /* Continue without storing converted vertices */
3951 dest_conv = dest_conv_addr;
3954 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3956 static BOOL warned = FALSE;
3958 * The clipping code is not quite correct. Some things need
3959 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3960 * so disable clipping for now.
3961 * (The graphics in Half-Life are broken, and my processvertices
3962 * test crashes with IDirect3DDevice3)
3968 FIXME("Clipping is broken and disabled for now\n");
3970 } else doClip = FALSE;
3971 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3973 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3976 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3977 WINED3DTS_PROJECTION,
3979 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3980 WINED3DTS_WORLDMATRIX(0),
3983 TRACE("View mat:\n");
3984 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);
3985 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);
3986 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);
3987 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);
3989 TRACE("Proj mat:\n");
3990 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);
3991 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);
3992 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);
3993 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);
3995 TRACE("World mat:\n");
3996 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);
3997 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);
3998 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);
3999 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);
4001 /* Get the viewport */
4002 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4003 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4004 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4006 multiply_matrix(&mat,&view_mat,&world_mat);
4007 multiply_matrix(&mat,&proj_mat,&mat);
4009 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4011 for (i = 0; i < dwCount; i+= 1) {
4012 unsigned int tex_index;
4014 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4015 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4016 /* The position first */
4017 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4018 const float *p = (const float *)(element->data + i * element->stride);
4020 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4022 /* Multiplication with world, view and projection matrix */
4023 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);
4024 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);
4025 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);
4026 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);
4028 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4030 /* WARNING: The following things are taken from d3d7 and were not yet checked
4031 * against d3d8 or d3d9!
4034 /* Clipping conditions: From msdn
4036 * A vertex is clipped if it does not match the following requirements
4040 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4042 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4043 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4048 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4049 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4052 /* "Normal" viewport transformation (not clipped)
4053 * 1) The values are divided by rhw
4054 * 2) The y axis is negative, so multiply it with -1
4055 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4056 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4057 * 4) Multiply x with Width/2 and add Width/2
4058 * 5) The same for the height
4059 * 6) Add the viewpoint X and Y to the 2D coordinates and
4060 * The minimum Z value to z
4061 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4063 * Well, basically it's simply a linear transformation into viewport
4075 z *= vp.MaxZ - vp.MinZ;
4077 x += vp.Width / 2 + vp.X;
4078 y += vp.Height / 2 + vp.Y;
4083 /* That vertex got clipped
4084 * Contrary to OpenGL it is not dropped completely, it just
4085 * undergoes a different calculation.
4087 TRACE("Vertex got clipped\n");
4094 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4095 * outside of the main vertex buffer memory. That needs some more
4100 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4103 ( (float *) dest_ptr)[0] = x;
4104 ( (float *) dest_ptr)[1] = y;
4105 ( (float *) dest_ptr)[2] = z;
4106 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4108 dest_ptr += 3 * sizeof(float);
4110 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4111 dest_ptr += sizeof(float);
4116 ( (float *) dest_conv)[0] = x * w;
4117 ( (float *) dest_conv)[1] = y * w;
4118 ( (float *) dest_conv)[2] = z * w;
4119 ( (float *) dest_conv)[3] = w;
4121 dest_conv += 3 * sizeof(float);
4123 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4124 dest_conv += sizeof(float);
4128 if (DestFVF & WINED3DFVF_PSIZE) {
4129 dest_ptr += sizeof(DWORD);
4130 if(dest_conv) dest_conv += sizeof(DWORD);
4132 if (DestFVF & WINED3DFVF_NORMAL) {
4133 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4134 const float *normal = (const float *)(element->data + i * element->stride);
4135 /* AFAIK this should go into the lighting information */
4136 FIXME("Didn't expect the destination to have a normal\n");
4137 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4139 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4143 if (DestFVF & WINED3DFVF_DIFFUSE) {
4144 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4145 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4146 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4148 static BOOL warned = FALSE;
4151 ERR("No diffuse color in source, but destination has one\n");
4155 *( (DWORD *) dest_ptr) = 0xffffffff;
4156 dest_ptr += sizeof(DWORD);
4159 *( (DWORD *) dest_conv) = 0xffffffff;
4160 dest_conv += sizeof(DWORD);
4164 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4166 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4167 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4168 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4169 dest_conv += sizeof(DWORD);
4174 if (DestFVF & WINED3DFVF_SPECULAR)
4176 /* What's the color value in the feedback buffer? */
4177 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4178 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4179 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4181 static BOOL warned = FALSE;
4184 ERR("No specular color in source, but destination has one\n");
4188 *( (DWORD *) dest_ptr) = 0xFF000000;
4189 dest_ptr += sizeof(DWORD);
4192 *( (DWORD *) dest_conv) = 0xFF000000;
4193 dest_conv += sizeof(DWORD);
4197 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4199 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4200 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4201 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4202 dest_conv += sizeof(DWORD);
4207 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4208 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4209 const float *tex_coord = (const float *)(element->data + i * element->stride);
4210 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4212 ERR("No source texture, but destination requests one\n");
4213 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4214 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4217 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4219 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4229 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4230 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4231 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4232 dwCount * get_flexible_vertex_size(DestFVF),
4234 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4238 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4243 #undef copy_and_next
4245 /* Do not call while under the GL lock. */
4246 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4247 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD flags,
4250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4251 struct wined3d_stream_info stream_info;
4252 const struct wined3d_gl_info *gl_info;
4253 struct wined3d_context *context;
4254 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4257 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4260 ERR("Output vertex declaration not implemented yet\n");
4263 /* Need any context to write to the vbo. */
4264 context = context_acquire(This, NULL);
4265 gl_info = context->gl_info;
4267 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4268 * control the streamIsUP flag, thus restore it afterwards.
4270 This->stateBlock->state.user_stream = FALSE;
4271 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4272 This->stateBlock->state.user_stream = streamWasUP;
4274 if(vbo || SrcStartIndex) {
4276 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4277 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4279 * Also get the start index in, but only loop over all elements if there's something to add at all.
4281 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4283 struct wined3d_stream_info_element *e;
4285 if (!(stream_info.use_map & (1 << i))) continue;
4287 e = &stream_info.elements[i];
4288 if (e->buffer_object)
4290 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4291 e->buffer_object = 0;
4292 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4294 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4295 vb->buffer_object = 0;
4298 if (e->data) e->data += e->stride * SrcStartIndex;
4302 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4303 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4305 context_release(context);
4311 * Get / Set Texture Stage States
4312 * TODO: Verify against dx9 definitions
4314 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4320 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4322 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4324 WARN("Invalid Type %d passed.\n", Type);
4328 if (Stage >= gl_info->limits.texture_stages)
4330 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4331 Stage, gl_info->limits.texture_stages - 1);
4335 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4336 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4337 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4339 if (This->isRecordingState) {
4340 TRACE("Recording... not performing anything\n");
4344 /* Checked after the assignments to allow proper stateblock recording */
4345 if(oldValue == Value) {
4346 TRACE("App is setting the old value over, nothing to do\n");
4350 if (Stage > This->stateBlock->state.lowest_disabled_stage
4351 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4352 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4354 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4355 * Changes in other states are important on disabled stages too
4360 if(Type == WINED3DTSS_COLOROP) {
4363 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4364 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4365 * they have to be disabled
4367 * The current stage is dirtified below.
4369 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4371 TRACE("Additionally dirtifying stage %u\n", i);
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4374 This->stateBlock->state.lowest_disabled_stage = Stage;
4375 TRACE("New lowest disabled: %u\n", Stage);
4376 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4377 /* Previously disabled stage enabled. Stages above it may need enabling
4378 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4379 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4381 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4384 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4386 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4388 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4391 This->stateBlock->state.lowest_disabled_stage = i;
4392 TRACE("New lowest disabled: %u\n", i);
4396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4401 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 TRACE("iface %p, stage %u, state %s, value %p.\n",
4406 iface, Stage, debug_d3dtexturestate(Type), pValue);
4408 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4410 WARN("Invalid Type %d passed.\n", Type);
4414 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4415 TRACE("Returning %#x.\n", *pValue);
4423 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4424 DWORD stage, IWineD3DBaseTexture *texture)
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4427 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4428 IWineD3DBaseTexture *prev;
4430 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4432 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4433 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4435 /* Windows accepts overflowing this array... we do not. */
4436 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4438 WARN("Ignoring invalid stage %u.\n", stage);
4442 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4443 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4445 WARN("Rejecting attempt to set scratch texture.\n");
4446 return WINED3DERR_INVALIDCALL;
4449 This->updateStateBlock->changed.textures |= 1 << stage;
4451 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4452 TRACE("Previous texture %p.\n", prev);
4454 if (texture == prev)
4456 TRACE("App is setting the same texture again, nothing to do.\n");
4460 TRACE("Setting new texture to %p.\n", texture);
4461 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4463 if (This->isRecordingState)
4465 TRACE("Recording... not performing anything\n");
4467 if (texture) IWineD3DBaseTexture_AddRef(texture);
4468 if (prev) IWineD3DBaseTexture_Release(prev);
4475 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4476 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4477 GLenum dimensions = t->baseTexture.target;
4479 IWineD3DBaseTexture_AddRef(texture);
4481 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4484 if (!prev && stage < gl_info->limits.texture_stages)
4486 /* The source arguments for color and alpha ops have different
4487 * meanings when a NULL texture is bound, so the COLOROP and
4488 * ALPHAOP have to be dirtified. */
4489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4493 if (bind_count == 1) t->baseTexture.sampler = stage;
4498 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4499 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4501 IWineD3DBaseTexture_Release(prev);
4503 if (!texture && stage < gl_info->limits.texture_stages)
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4509 if (bind_count && t->baseTexture.sampler == stage)
4513 /* Search for other stages the texture is bound to. Shouldn't
4514 * happen if applications bind textures to a single stage only. */
4515 TRACE("Searching for other stages the texture is bound to.\n");
4516 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4518 if (This->updateStateBlock->state.textures[i] == t)
4520 TRACE("Texture is also bound to stage %u.\n", i);
4521 t->baseTexture.sampler = i;
4528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4533 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4536 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4538 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4539 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4542 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4544 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4545 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4548 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4550 IWineD3DBaseTexture_AddRef(*ppTexture);
4552 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4560 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4561 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4563 IWineD3DSwapChain *swapchain;
4566 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4567 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4569 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4572 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4576 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4577 IWineD3DSwapChain_Release(swapchain);
4580 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4587 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4589 WARN("(%p) : stub, calling idirect3d for now\n", This);
4590 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4593 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4595 IWineD3DSwapChain *swapChain;
4598 if(iSwapChain > 0) {
4599 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4600 if (hr == WINED3D_OK) {
4601 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4602 IWineD3DSwapChain_Release(swapChain);
4604 FIXME("(%p) Error getting display mode\n", This);
4607 /* Don't read the real display mode,
4608 but return the stored mode instead. X11 can't change the color
4609 depth, and some apps are pretty angry if they SetDisplayMode from
4610 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4612 Also don't relay to the swapchain because with ddraw it's possible
4613 that there isn't a swapchain at all */
4614 pMode->Width = This->ddraw_width;
4615 pMode->Height = This->ddraw_height;
4616 pMode->Format = This->ddraw_format;
4617 pMode->RefreshRate = 0;
4625 * Stateblock related functions
4628 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 IWineD3DStateBlock *stateblock;
4633 TRACE("(%p)\n", This);
4635 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4637 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4638 if (FAILED(hr)) return hr;
4640 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4641 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4642 This->isRecordingState = TRUE;
4644 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4649 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4653 if (!This->isRecordingState) {
4654 WARN("(%p) not recording! returning error\n", This);
4655 *ppStateBlock = NULL;
4656 return WINED3DERR_INVALIDCALL;
4659 stateblock_init_contained_states(object);
4661 *ppStateBlock = (IWineD3DStateBlock*) object;
4662 This->isRecordingState = FALSE;
4663 This->updateStateBlock = This->stateBlock;
4664 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4665 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4666 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4671 * Scene related functions
4673 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4674 /* At the moment we have no need for any functionality at the beginning
4676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4677 TRACE("(%p)\n", This);
4680 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4681 return WINED3DERR_INVALIDCALL;
4683 This->inScene = TRUE;
4687 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4690 struct wined3d_context *context;
4692 TRACE("(%p)\n", This);
4694 if(!This->inScene) {
4695 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4696 return WINED3DERR_INVALIDCALL;
4699 context = context_acquire(This, NULL);
4700 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4702 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4704 context_release(context);
4706 This->inScene = FALSE;
4710 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4711 const RECT *pSourceRect, const RECT *pDestRect,
4712 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4714 IWineD3DSwapChain *swapChain = NULL;
4716 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4718 TRACE("iface %p.\n", iface);
4720 for(i = 0 ; i < swapchains ; i ++) {
4722 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4723 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4724 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4725 IWineD3DSwapChain_Release(swapChain);
4731 /* Do not call while under the GL lock. */
4732 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4733 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4735 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4736 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4739 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4740 iface, rect_count, rects, flags, color, depth, stencil);
4742 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4744 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4745 /* TODO: What about depth stencil buffers without stencil bits? */
4746 return WINED3DERR_INVALIDCALL;
4749 device_get_draw_rect(device, &draw_rect);
4751 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4752 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4759 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4760 WINED3DPRIMITIVETYPE primitive_type)
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4766 This->updateStateBlock->changed.primitive_type = TRUE;
4767 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4770 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4771 WINED3DPRIMITIVETYPE *primitive_type)
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4775 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4777 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4779 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4782 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4788 if (!This->stateBlock->state.vertex_declaration)
4790 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4791 return WINED3DERR_INVALIDCALL;
4794 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4795 if (This->stateBlock->state.user_stream)
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4798 This->stateBlock->state.user_stream = FALSE;
4801 if (This->stateBlock->state.load_base_vertex_index)
4803 This->stateBlock->state.load_base_vertex_index = 0;
4804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4806 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4807 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4811 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4814 struct wined3d_buffer *index_buffer;
4818 index_buffer = This->stateBlock->state.index_buffer;
4821 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4822 * without an index buffer set. (The first time at least...)
4823 * D3D8 simply dies, but I doubt it can do much harm to return
4824 * D3DERR_INVALIDCALL there as well. */
4825 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4826 return WINED3DERR_INVALIDCALL;
4829 if (!This->stateBlock->state.vertex_declaration)
4831 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4832 return WINED3DERR_INVALIDCALL;
4835 if (This->stateBlock->state.user_stream)
4837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4838 This->stateBlock->state.user_stream = FALSE;
4840 vbo = index_buffer->buffer_object;
4842 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4844 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4849 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4851 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4855 drawPrimitive(This, index_count, startIndex, idxStride,
4856 vbo ? NULL : index_buffer->resource.allocatedMemory);
4861 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4862 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 struct wined3d_stream_state *stream;
4868 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4869 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4871 if (!This->stateBlock->state.vertex_declaration)
4873 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4874 return WINED3DERR_INVALIDCALL;
4877 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4878 stream = &This->stateBlock->state.streams[0];
4879 vb = (IWineD3DBuffer *)stream->buffer;
4880 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4881 if (vb) IWineD3DBuffer_Release(vb);
4883 stream->stride = VertexStreamZeroStride;
4884 This->stateBlock->state.user_stream = TRUE;
4885 This->stateBlock->state.load_base_vertex_index = 0;
4887 /* TODO: Only mark dirty if drawing from a different UP address */
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4890 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4892 /* MSDN specifies stream zero settings must be set to NULL */
4893 stream->buffer = NULL;
4896 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4897 * the new stream sources or use UP drawing again
4902 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4903 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4904 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4908 struct wined3d_stream_state *stream;
4912 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4913 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4915 if (!This->stateBlock->state.vertex_declaration)
4917 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4918 return WINED3DERR_INVALIDCALL;
4921 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4927 stream = &This->stateBlock->state.streams[0];
4928 vb = (IWineD3DBuffer *)stream->buffer;
4929 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4930 if (vb) IWineD3DBuffer_Release(vb);
4932 stream->stride = VertexStreamZeroStride;
4933 This->stateBlock->state.user_stream = TRUE;
4935 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4936 This->stateBlock->state.base_vertex_index = 0;
4937 This->stateBlock->state.load_base_vertex_index = 0;
4938 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4942 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4944 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4945 stream->buffer = NULL;
4947 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4950 IWineD3DBuffer_Release(ib);
4951 This->stateBlock->state.index_buffer = NULL;
4953 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4954 * SetStreamSource to specify a vertex buffer
4960 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4961 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4965 /* Mark the state dirty until we have nicer tracking
4966 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4971 This->stateBlock->state.base_vertex_index = 0;
4972 This->up_strided = DrawPrimStrideData;
4973 drawPrimitive(This, vertex_count, 0, 0, NULL);
4974 This->up_strided = NULL;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4979 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4980 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4983 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4985 /* Mark the state dirty until we have nicer tracking
4986 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4991 This->stateBlock->state.user_stream = TRUE;
4992 This->stateBlock->state.base_vertex_index = 0;
4993 This->up_strided = DrawPrimStrideData;
4994 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4995 This->up_strided = NULL;
4999 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5000 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5001 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5003 WINED3DLOCKED_BOX src;
5004 WINED3DLOCKED_BOX dst;
5007 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5008 iface, pSourceVolume, pDestinationVolume);
5010 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5011 * dirtification to improve loading performance.
5013 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5014 if (FAILED(hr)) return hr;
5015 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5018 IWineD3DVolume_Unmap(pSourceVolume);
5022 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5024 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5026 IWineD3DVolume_Unmap(pSourceVolume);
5028 hr = IWineD3DVolume_Unmap(pSourceVolume);
5033 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5034 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5036 unsigned int level_count, i;
5037 WINED3DRESOURCETYPE type;
5040 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5042 /* Verify that the source and destination textures are non-NULL. */
5043 if (!src_texture || !dst_texture)
5045 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5046 return WINED3DERR_INVALIDCALL;
5049 if (src_texture == dst_texture)
5051 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5052 return WINED3DERR_INVALIDCALL;
5055 /* Verify that the source and destination textures are the same type. */
5056 type = IWineD3DBaseTexture_GetType(src_texture);
5057 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5059 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5060 return WINED3DERR_INVALIDCALL;
5063 /* Check that both textures have the identical numbers of levels. */
5064 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5065 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5067 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5068 return WINED3DERR_INVALIDCALL;
5071 /* Make sure that the destination texture is loaded. */
5072 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5073 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5075 /* Update every surface level of the texture. */
5078 case WINED3DRTYPE_TEXTURE:
5080 IWineD3DSurface *src_surface;
5081 IWineD3DSurface *dst_surface;
5083 for (i = 0; i < level_count; ++i)
5085 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5086 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5087 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5088 IWineD3DSurface_Release(dst_surface);
5089 IWineD3DSurface_Release(src_surface);
5092 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5099 case WINED3DRTYPE_CUBETEXTURE:
5101 IWineD3DSurface *src_surface;
5102 IWineD3DSurface *dst_surface;
5104 for (i = 0; i < level_count * 6; ++i)
5106 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5107 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5108 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5109 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5110 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5111 IWineD3DSurface_Release(dst_surface);
5112 IWineD3DSurface_Release(src_surface);
5115 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5122 case WINED3DRTYPE_VOLUMETEXTURE:
5124 IWineD3DVolume *src_volume;
5125 IWineD3DVolume *dst_volume;
5127 for (i = 0; i < level_count; ++i)
5129 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5130 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5131 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5132 IWineD3DVolume_Release(dst_volume);
5133 IWineD3DVolume_Release(src_volume);
5136 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5144 FIXME("Unsupported texture type %#x.\n", type);
5145 return WINED3DERR_INVALIDCALL;
5151 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5152 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5154 IWineD3DSwapChain *swapchain;
5157 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5159 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5160 if (FAILED(hr)) return hr;
5162 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5163 IWineD3DSwapChain_Release(swapchain);
5168 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5170 IWineD3DBaseTextureImpl *texture;
5173 TRACE("(%p) : %p\n", This, pNumPasses);
5175 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5177 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5179 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5180 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5182 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5184 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5185 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5188 texture = This->stateBlock->state.textures[i];
5189 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5191 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5193 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5196 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5198 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5201 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5202 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5204 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5209 /* return a sensible default */
5212 TRACE("returning D3D_OK\n");
5216 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5220 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5222 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5223 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5224 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5226 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5231 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 PALETTEENTRY **palettes;
5237 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5239 if (PaletteNumber >= MAX_PALETTES) {
5240 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5241 return WINED3DERR_INVALIDCALL;
5244 if (PaletteNumber >= This->NumberOfPalettes) {
5245 NewSize = This->NumberOfPalettes;
5248 } while(PaletteNumber >= NewSize);
5249 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5251 ERR("Out of memory!\n");
5252 return E_OUTOFMEMORY;
5254 This->palettes = palettes;
5255 This->NumberOfPalettes = NewSize;
5258 if (!This->palettes[PaletteNumber]) {
5259 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5260 if (!This->palettes[PaletteNumber]) {
5261 ERR("Out of memory!\n");
5262 return E_OUTOFMEMORY;
5266 for (j = 0; j < 256; ++j) {
5267 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5268 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5269 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5270 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5272 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5273 TRACE("(%p) : returning\n", This);
5277 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5281 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5282 /* What happens in such situation isn't documented; Native seems to silently abort
5283 on such conditions. Return Invalid Call. */
5284 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5285 return WINED3DERR_INVALIDCALL;
5287 for (j = 0; j < 256; ++j) {
5288 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5289 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5290 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5291 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5293 TRACE("(%p) : returning\n", This);
5297 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5299 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5300 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5301 (tested with reference rasterizer). Return Invalid Call. */
5302 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5303 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5304 return WINED3DERR_INVALIDCALL;
5306 /*TODO: stateblocks */
5307 if (This->currentPalette != PaletteNumber) {
5308 This->currentPalette = PaletteNumber;
5309 dirtify_p8_texture_samplers(This);
5311 TRACE("(%p) : returning\n", This);
5315 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 WARN("(%p) : returning Invalid Call\n", This);
5321 return WINED3DERR_INVALIDCALL;
5323 /*TODO: stateblocks */
5324 *PaletteNumber = This->currentPalette;
5325 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5329 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5334 FIXME("(%p) : stub\n", This);
5338 This->softwareVertexProcessing = bSoftware;
5343 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5348 FIXME("(%p) : stub\n", This);
5351 return This->softwareVertexProcessing;
5354 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5355 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5357 IWineD3DSwapChain *swapchain;
5360 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5361 iface, swapchain_idx, raster_status);
5363 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5366 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5370 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5371 IWineD3DSwapChain_Release(swapchain);
5374 WARN("Failed to get raster status, hr %#x.\n", hr);
5381 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5384 if(nSegments != 0.0f) {
5387 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5394 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5399 FIXME("iface %p stub!\n", iface);
5405 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5406 IWineD3DSurface *src_surface, const RECT *src_rect,
5407 IWineD3DSurface *dst_surface, const POINT *dst_point)
5409 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5410 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5412 const struct wined3d_format *src_format;
5413 const struct wined3d_format *dst_format;
5414 const struct wined3d_gl_info *gl_info;
5415 struct wined3d_context *context;
5416 const unsigned char *data;
5417 UINT update_w, update_h;
5418 CONVERT_TYPES convert;
5422 struct wined3d_format format;
5424 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5425 iface, src_surface, wine_dbgstr_rect(src_rect),
5426 dst_surface, wine_dbgstr_point(dst_point));
5428 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5430 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5431 src_surface, dst_surface);
5432 return WINED3DERR_INVALIDCALL;
5435 src_format = src_impl->resource.format;
5436 dst_format = dst_impl->resource.format;
5438 if (src_format->id != dst_format->id)
5440 WARN("Source and destination surfaces should have the same format.\n");
5441 return WINED3DERR_INVALIDCALL;
5444 dst_x = dst_point ? dst_point->x : 0;
5445 dst_y = dst_point ? dst_point->y : 0;
5447 /* This call loads the OpenGL surface directly, instead of copying the
5448 * surface to the destination's sysmem copy. If surface conversion is
5449 * needed, use BltFast instead to copy in sysmem and use regular surface
5451 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5452 if (convert != NO_CONVERSION || format.convert)
5453 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5455 context = context_acquire(This, NULL);
5456 gl_info = context->gl_info;
5459 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5460 checkGLcall("glActiveTextureARB");
5463 /* Make sure the surface is loaded and up to date */
5464 surface_internal_preload(dst_impl, SRGB_RGB);
5465 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5467 src_w = src_impl->currentDesc.Width;
5468 src_h = src_impl->currentDesc.Height;
5469 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5470 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5472 data = IWineD3DSurface_GetData(src_surface);
5473 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5477 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5479 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5480 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5481 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5485 data += (src_rect->top / src_format->block_height) * src_pitch;
5486 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5489 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5490 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5491 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5493 if (row_length == src_pitch)
5495 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5496 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5502 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5503 * can't use the unpack row length like below. */
5504 for (row = 0, y = dst_y; row < row_count; ++row)
5506 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5507 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5508 y += src_format->block_height;
5512 checkGLcall("glCompressedTexSubImage2DARB");
5518 data += src_rect->top * src_w * src_format->byte_count;
5519 data += src_rect->left * src_format->byte_count;
5522 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5523 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5524 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5526 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5527 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5528 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5529 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5530 checkGLcall("glTexSubImage2D");
5534 context_release(context);
5536 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5537 sampler = This->rev_tex_unit_map[0];
5538 if (sampler != WINED3D_UNMAPPED_STAGE)
5540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5546 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5548 struct WineD3DRectPatch *patch;
5549 GLenum old_primitive_type;
5553 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5555 if(!(Handle || pRectPatchInfo)) {
5556 /* TODO: Write a test for the return value, thus the FIXME */
5557 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5558 return WINED3DERR_INVALIDCALL;
5562 i = PATCHMAP_HASHFUNC(Handle);
5564 LIST_FOR_EACH(e, &This->patches[i]) {
5565 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5566 if(patch->Handle == Handle) {
5573 TRACE("Patch does not exist. Creating a new one\n");
5574 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5575 patch->Handle = Handle;
5576 list_add_head(&This->patches[i], &patch->entry);
5578 TRACE("Found existing patch %p\n", patch);
5581 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5582 * attributes we have to tesselate, read back, and draw. This needs a patch
5583 * management structure instance. Create one.
5585 * A possible improvement is to check if a vertex shader is used, and if not directly
5588 FIXME("Drawing an uncached patch. This is slow\n");
5589 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5592 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5593 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5594 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5597 TRACE("Tesselation density or patch info changed, retesselating\n");
5599 if(pRectPatchInfo) {
5600 patch->RectPatchInfo = *pRectPatchInfo;
5602 patch->numSegs[0] = pNumSegs[0];
5603 patch->numSegs[1] = pNumSegs[1];
5604 patch->numSegs[2] = pNumSegs[2];
5605 patch->numSegs[3] = pNumSegs[3];
5607 hr = tesselate_rectpatch(This, patch);
5609 WARN("Patch tesselation failed\n");
5611 /* Do not release the handle to store the params of the patch */
5613 HeapFree(GetProcessHeap(), 0, patch);
5619 This->currentPatch = patch;
5620 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5621 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5622 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5623 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5624 This->currentPatch = NULL;
5626 /* Destroy uncached patches */
5628 HeapFree(GetProcessHeap(), 0, patch->mem);
5629 HeapFree(GetProcessHeap(), 0, patch);
5634 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5635 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5637 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5638 iface, handle, segment_count, patch_info);
5643 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 struct WineD3DRectPatch *patch;
5648 TRACE("(%p) Handle(%d)\n", This, Handle);
5650 i = PATCHMAP_HASHFUNC(Handle);
5651 LIST_FOR_EACH(e, &This->patches[i]) {
5652 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5653 if(patch->Handle == Handle) {
5654 TRACE("Deleting patch %p\n", patch);
5655 list_remove(&patch->entry);
5656 HeapFree(GetProcessHeap(), 0, patch->mem);
5657 HeapFree(GetProcessHeap(), 0, patch);
5662 /* TODO: Write a test for the return value */
5663 FIXME("Attempt to destroy nonexistent patch\n");
5664 return WINED3DERR_INVALIDCALL;
5667 /* Do not call while under the GL lock. */
5668 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5669 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5671 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5673 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5674 iface, surface, wine_dbgstr_rect(rect),
5675 color->r, color->g, color->b, color->a);
5677 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5679 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5680 return WINED3DERR_INVALIDCALL;
5683 return surface_color_fill(s, rect, color);
5686 /* Do not call while under the GL lock. */
5687 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5688 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5690 IWineD3DResource *resource;
5693 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5696 ERR("Failed to get resource, hr %#x\n", hr);
5700 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5702 FIXME("Only supported on surface resources\n");
5703 IWineD3DResource_Release(resource);
5707 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5708 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5710 IWineD3DResource_Release(resource);
5713 /* rendertarget and depth stencil functions */
5714 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5715 DWORD render_target_idx, IWineD3DSurface **render_target)
5717 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5719 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5720 iface, render_target_idx, render_target);
5722 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5724 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5725 return WINED3DERR_INVALIDCALL;
5728 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5729 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5731 TRACE("Returning render target %p.\n", *render_target);
5736 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5738 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5740 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5742 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5743 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5744 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5745 IWineD3DSurface_AddRef(*depth_stencil);
5750 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5751 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5753 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5754 IWineD3DSurfaceImpl *prev;
5756 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5757 iface, render_target_idx, render_target, set_viewport);
5759 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5761 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5762 return WINED3DERR_INVALIDCALL;
5765 prev = device->render_targets[render_target_idx];
5766 if (render_target == (IWineD3DSurface *)prev)
5768 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5772 /* Render target 0 can't be set to NULL. */
5773 if (!render_target && !render_target_idx)
5775 WARN("Trying to set render target 0 to NULL.\n");
5776 return WINED3DERR_INVALIDCALL;
5779 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5781 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5782 return WINED3DERR_INVALIDCALL;
5785 if (render_target) IWineD3DSurface_AddRef(render_target);
5786 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5787 /* Release after the assignment, to prevent device_resource_released()
5788 * from seeing the surface as still in use. */
5789 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5791 /* Render target 0 is special. */
5792 if (!render_target_idx && set_viewport)
5794 /* Set the viewport and scissor rectangles, if requested. Tests show
5795 * that stateblock recording is ignored, the change goes directly
5796 * into the primary stateblock. */
5797 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5798 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5799 device->stateBlock->state.viewport.X = 0;
5800 device->stateBlock->state.viewport.Y = 0;
5801 device->stateBlock->state.viewport.MaxZ = 1.0f;
5802 device->stateBlock->state.viewport.MinZ = 0.0f;
5803 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5805 device->stateBlock->state.scissor_rect.top = 0;
5806 device->stateBlock->state.scissor_rect.left = 0;
5807 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5808 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5809 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5815 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5818 IWineD3DSurfaceImpl *tmp;
5820 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5822 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5824 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5828 if (This->depth_stencil)
5830 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5831 || This->depth_stencil->flags & SFLAG_DISCARD)
5833 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5834 This->depth_stencil->currentDesc.Width,
5835 This->depth_stencil->currentDesc.Height);
5836 if (This->depth_stencil == This->onscreen_depth_stencil)
5838 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5839 This->onscreen_depth_stencil = NULL;
5844 tmp = This->depth_stencil;
5845 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5846 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5847 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5849 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5851 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5860 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5861 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5864 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5865 WINED3DLOCKED_RECT lockedRect;
5867 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5868 iface, XHotSpot, YHotSpot, cursor_image);
5870 /* some basic validation checks */
5871 if (This->cursorTexture)
5873 struct wined3d_context *context = context_acquire(This, NULL);
5875 glDeleteTextures(1, &This->cursorTexture);
5877 context_release(context);
5878 This->cursorTexture = 0;
5881 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5882 This->haveHardwareCursor = TRUE;
5884 This->haveHardwareCursor = FALSE;
5888 WINED3DLOCKED_RECT rect;
5890 /* MSDN: Cursor must be A8R8G8B8 */
5891 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5893 WARN("surface %p has an invalid format.\n", cursor_image);
5894 return WINED3DERR_INVALIDCALL;
5897 /* MSDN: Cursor must be smaller than the display mode */
5898 if (s->currentDesc.Width > This->ddraw_width
5899 || s->currentDesc.Height > This->ddraw_height)
5901 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5902 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5903 return WINED3DERR_INVALIDCALL;
5906 if (!This->haveHardwareCursor) {
5907 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5909 /* Do not store the surface's pointer because the application may
5910 * release it after setting the cursor image. Windows doesn't
5911 * addref the set surface, so we can't do this either without
5912 * creating circular refcount dependencies. Copy out the gl texture
5915 This->cursorWidth = s->currentDesc.Width;
5916 This->cursorHeight = s->currentDesc.Height;
5917 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5919 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5920 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5921 struct wined3d_context *context;
5922 char *mem, *bits = rect.pBits;
5923 GLint intfmt = format->glInternal;
5924 GLint gl_format = format->glFormat;
5925 GLint type = format->glType;
5926 INT height = This->cursorHeight;
5927 INT width = This->cursorWidth;
5928 INT bpp = format->byte_count;
5932 /* Reformat the texture memory (pitch and width can be
5934 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5935 for(i = 0; i < height; i++)
5936 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5937 IWineD3DSurface_Unmap(cursor_image);
5939 context = context_acquire(This, NULL);
5943 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5945 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5946 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5949 /* Make sure that a proper texture unit is selected */
5950 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5951 checkGLcall("glActiveTextureARB");
5952 sampler = This->rev_tex_unit_map[0];
5953 if (sampler != WINED3D_UNMAPPED_STAGE)
5955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5957 /* Create a new cursor texture */
5958 glGenTextures(1, &This->cursorTexture);
5959 checkGLcall("glGenTextures");
5960 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5961 checkGLcall("glBindTexture");
5962 /* Copy the bitmap memory into the cursor texture */
5963 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5964 checkGLcall("glTexImage2D");
5965 HeapFree(GetProcessHeap(), 0, mem);
5967 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5969 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5970 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5975 context_release(context);
5979 FIXME("A cursor texture was not returned.\n");
5980 This->cursorTexture = 0;
5985 /* Draw a hardware cursor */
5986 ICONINFO cursorInfo;
5988 /* Create and clear maskBits because it is not needed for
5989 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5991 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5992 (s->currentDesc.Width * s->currentDesc.Height / 8));
5993 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5994 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5995 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5997 cursorInfo.fIcon = FALSE;
5998 cursorInfo.xHotspot = XHotSpot;
5999 cursorInfo.yHotspot = YHotSpot;
6000 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
6001 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
6002 IWineD3DSurface_Unmap(cursor_image);
6003 /* Create our cursor and clean up. */
6004 cursor = CreateIconIndirect(&cursorInfo);
6006 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6007 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6008 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6009 This->hardwareCursor = cursor;
6010 HeapFree(GetProcessHeap(), 0, maskBits);
6014 This->xHotSpot = XHotSpot;
6015 This->yHotSpot = YHotSpot;
6019 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6020 int XScreenSpace, int YScreenSpace, DWORD flags)
6022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6024 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6025 iface, XScreenSpace, YScreenSpace, flags);
6027 This->xScreenSpace = XScreenSpace;
6028 This->yScreenSpace = YScreenSpace;
6031 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6033 BOOL oldVisible = This->bCursorVisible;
6036 TRACE("(%p) : visible(%d)\n", This, bShow);
6039 * When ShowCursor is first called it should make the cursor appear at the OS's last
6040 * known cursor position. Because of this, some applications just repetitively call
6041 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6044 This->xScreenSpace = pt.x;
6045 This->yScreenSpace = pt.y;
6047 if (This->haveHardwareCursor) {
6048 This->bCursorVisible = bShow;
6050 SetCursor(This->hardwareCursor);
6056 if (This->cursorTexture)
6057 This->bCursorVisible = bShow;
6063 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6064 TRACE("checking resource %p for eviction\n", resource);
6065 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6066 TRACE("Evicting %p\n", resource);
6067 IWineD3DResource_UnLoad(resource);
6069 IWineD3DResource_Release(resource);
6073 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6075 TRACE("iface %p.\n", iface);
6077 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6078 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6079 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6084 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6086 IWineD3DDeviceImpl *device = surface->resource.device;
6087 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6089 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6090 if (surface->flags & SFLAG_DIBSECTION)
6092 /* Release the DC */
6093 SelectObject(surface->hDC, surface->dib.holdbitmap);
6094 DeleteDC(surface->hDC);
6095 /* Release the DIB section */
6096 DeleteObject(surface->dib.DIBsection);
6097 surface->dib.bitmap_data = NULL;
6098 surface->resource.allocatedMemory = NULL;
6099 surface->flags &= ~SFLAG_DIBSECTION;
6101 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6102 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6103 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6104 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6106 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6107 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6109 surface->pow2Width = surface->pow2Height = 1;
6110 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6111 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6114 if (surface->texture_name)
6116 struct wined3d_context *context = context_acquire(device, NULL);
6118 glDeleteTextures(1, &surface->texture_name);
6120 context_release(context);
6121 surface->texture_name = 0;
6122 surface->flags &= ~SFLAG_CLIENT;
6124 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6125 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6127 surface->flags |= SFLAG_NONPOW2;
6131 surface->flags &= ~SFLAG_NONPOW2;
6133 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6134 surface->resource.allocatedMemory = NULL;
6135 surface->resource.heapMemory = NULL;
6136 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6138 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6140 if (!surface_init_sysmem(surface))
6142 return E_OUTOFMEMORY;
6147 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6148 TRACE("Unloading resource %p\n", resource);
6149 IWineD3DResource_UnLoad(resource);
6150 IWineD3DResource_Release(resource);
6154 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6157 WINED3DDISPLAYMODE m;
6160 /* All Windowed modes are supported, as is leaving the current mode */
6161 if(pp->Windowed) return TRUE;
6162 if(!pp->BackBufferWidth) return TRUE;
6163 if(!pp->BackBufferHeight) return TRUE;
6165 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6166 for(i = 0; i < count; i++) {
6167 memset(&m, 0, sizeof(m));
6168 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6170 ERR("EnumAdapterModes failed\n");
6172 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6173 /* Mode found, it is supported */
6177 /* Mode not found -> not supported */
6181 /* Do not call while under the GL lock. */
6182 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6184 const struct wined3d_gl_info *gl_info;
6185 struct wined3d_context *context;
6186 IWineD3DBaseShaderImpl *shader;
6188 context = context_acquire(device, NULL);
6189 gl_info = context->gl_info;
6191 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, reset_unload_resources, NULL);
6192 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6194 device->shader_backend->shader_destroy(shader);
6198 if (device->depth_blt_texture)
6200 glDeleteTextures(1, &device->depth_blt_texture);
6201 device->depth_blt_texture = 0;
6203 if (device->depth_blt_rb)
6205 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6206 device->depth_blt_rb = 0;
6207 device->depth_blt_rb_w = 0;
6208 device->depth_blt_rb_h = 0;
6212 device->blitter->free_private(device);
6213 device->frag_pipe->free_private(device);
6214 device->shader_backend->shader_free_private(device);
6215 destroy_dummy_textures(device, gl_info);
6217 context_release(context);
6219 while (device->numContexts)
6221 context_destroy(device, device->contexts[0]);
6223 HeapFree(GetProcessHeap(), 0, swapchain->context);
6224 swapchain->context = NULL;
6225 swapchain->num_contexts = 0;
6228 /* Do not call while under the GL lock. */
6229 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6231 struct wined3d_context *context;
6233 IWineD3DSurfaceImpl *target;
6235 /* Recreate the primary swapchain's context */
6236 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6237 if (!swapchain->context)
6239 ERR("Failed to allocate memory for swapchain context array.\n");
6240 return E_OUTOFMEMORY;
6243 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6244 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6246 WARN("Failed to create context.\n");
6247 HeapFree(GetProcessHeap(), 0, swapchain->context);
6251 swapchain->context[0] = context;
6252 swapchain->num_contexts = 1;
6253 create_dummy_textures(device);
6254 context_release(context);
6256 hr = device->shader_backend->shader_alloc_private(device);
6259 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6263 hr = device->frag_pipe->alloc_private(device);
6266 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6267 device->shader_backend->shader_free_private(device);
6271 hr = device->blitter->alloc_private(device);
6274 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6275 device->frag_pipe->free_private(device);
6276 device->shader_backend->shader_free_private(device);
6283 context_acquire(device, NULL);
6284 destroy_dummy_textures(device, context->gl_info);
6285 context_release(context);
6286 context_destroy(device, context);
6287 HeapFree(GetProcessHeap(), 0, swapchain->context);
6288 swapchain->num_contexts = 0;
6292 /* Do not call while under the GL lock. */
6293 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6294 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6297 IWineD3DSwapChainImpl *swapchain;
6299 BOOL DisplayModeChanged = FALSE;
6300 WINED3DDISPLAYMODE mode;
6301 TRACE("(%p)\n", This);
6303 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6305 ERR("Failed to get the first implicit swapchain\n");
6309 if(!is_display_mode_supported(This, pPresentationParameters)) {
6310 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6311 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6312 pPresentationParameters->BackBufferHeight);
6313 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6314 return WINED3DERR_INVALIDCALL;
6317 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6318 * on an existing gl context, so there's no real need for recreation.
6320 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6322 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6324 TRACE("New params:\n");
6325 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6326 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6327 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6328 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6329 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6330 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6331 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6332 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6333 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6334 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6335 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6336 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6337 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6339 /* No special treatment of these parameters. Just store them */
6340 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6341 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6342 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6343 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6345 /* What to do about these? */
6346 if (pPresentationParameters->BackBufferCount
6347 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6348 ERR("Cannot change the back buffer count yet\n");
6350 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6351 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6352 ERR("Cannot change the back buffer format yet\n");
6355 if (pPresentationParameters->hDeviceWindow
6356 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6357 ERR("Cannot change the device window yet\n");
6359 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6363 TRACE("Creating the depth stencil buffer\n");
6365 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6366 pPresentationParameters->BackBufferWidth,
6367 pPresentationParameters->BackBufferHeight,
6368 pPresentationParameters->AutoDepthStencilFormat,
6369 pPresentationParameters->MultiSampleType,
6370 pPresentationParameters->MultiSampleQuality,
6372 (IWineD3DSurface **)&This->auto_depth_stencil);
6375 ERR("Failed to create the depth stencil buffer\n");
6376 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6377 return WINED3DERR_INVALIDCALL;
6381 if (This->onscreen_depth_stencil)
6383 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6384 This->onscreen_depth_stencil = NULL;
6387 /* Reset the depth stencil */
6388 if (pPresentationParameters->EnableAutoDepthStencil)
6389 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6391 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6393 TRACE("Resetting stateblock\n");
6394 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6395 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6397 delete_opengl_contexts(This, swapchain);
6399 if(pPresentationParameters->Windowed) {
6400 mode.Width = swapchain->orig_width;
6401 mode.Height = swapchain->orig_height;
6402 mode.RefreshRate = 0;
6403 mode.Format = swapchain->presentParms.BackBufferFormat;
6405 mode.Width = pPresentationParameters->BackBufferWidth;
6406 mode.Height = pPresentationParameters->BackBufferHeight;
6407 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6408 mode.Format = swapchain->presentParms.BackBufferFormat;
6411 /* Should Width == 800 && Height == 0 set 800x600? */
6412 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6413 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6414 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6418 if(!pPresentationParameters->Windowed) {
6419 DisplayModeChanged = TRUE;
6421 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6422 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6424 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6427 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6431 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6433 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6436 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6440 if (This->auto_depth_stencil)
6442 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6445 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6451 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6452 || DisplayModeChanged)
6454 BOOL filter = This->filter_messages;
6455 This->filter_messages = TRUE;
6457 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6459 if (!pPresentationParameters->Windowed)
6461 if (swapchain->presentParms.Windowed)
6463 HWND focus_window = This->createParms.hFocusWindow;
6464 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6465 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6467 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6468 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6472 /* switch from windowed to fs */
6473 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6474 pPresentationParameters->BackBufferWidth,
6475 pPresentationParameters->BackBufferHeight);
6479 /* Fullscreen -> fullscreen mode change */
6480 MoveWindow(swapchain->device_window, 0, 0,
6481 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6485 else if (!swapchain->presentParms.Windowed)
6487 /* Fullscreen -> windowed switch */
6488 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6489 IWineD3DDevice_ReleaseFocusWindow(iface);
6491 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6493 This->filter_messages = filter;
6495 else if (!pPresentationParameters->Windowed)
6497 DWORD style = This->style, exStyle = This->exStyle;
6498 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6499 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6500 * Reset to clear up their mess. Guild Wars also loses the device during that.
6504 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6505 pPresentationParameters->BackBufferWidth,
6506 pPresentationParameters->BackBufferHeight);
6507 This->style = style;
6508 This->exStyle = exStyle;
6511 /* Note: No parent needed for initial internal stateblock */
6512 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6513 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6514 else TRACE("Created stateblock %p\n", This->stateBlock);
6515 This->updateStateBlock = This->stateBlock;
6516 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6518 stateblock_init_default_state(This->stateBlock);
6520 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6523 GetClientRect(swapchain->win_handle, &client_rect);
6525 if(!swapchain->presentParms.BackBufferCount)
6527 TRACE("Single buffered rendering\n");
6528 swapchain->render_to_fbo = FALSE;
6530 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6531 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6533 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6534 swapchain->presentParms.BackBufferWidth,
6535 swapchain->presentParms.BackBufferHeight,
6536 client_rect.right, client_rect.bottom);
6537 swapchain->render_to_fbo = TRUE;
6541 TRACE("Rendering directly to GL_BACK\n");
6542 swapchain->render_to_fbo = FALSE;
6546 hr = create_primary_opengl_context(This, swapchain);
6547 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6549 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6555 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6557 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6559 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6565 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6567 TRACE("(%p) : pParameters %p\n", This, pParameters);
6569 *pParameters = This->createParms;
6573 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6574 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6576 IWineD3DSwapChain *swapchain;
6578 TRACE("Relaying to swapchain\n");
6580 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6582 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6583 IWineD3DSwapChain_Release(swapchain);
6587 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6588 IWineD3DSwapChain *swapchain;
6590 TRACE("Relaying to swapchain\n");
6592 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6593 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6594 IWineD3DSwapChain_Release(swapchain);
6598 void device_resource_add(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6600 TRACE("device %p, resource %p.\n", device, resource);
6602 list_add_head(&device->resources, &resource->resource.resource_list_entry);
6605 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6607 TRACE("device %p, resource %p.\n", device, resource);
6609 list_remove(&resource->resource.resource_list_entry);
6612 void device_resource_released(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6614 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6617 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6619 context_resource_released(device, resource, type);
6623 case WINED3DRTYPE_SURFACE:
6624 if (!device->d3d_initialized) break;
6626 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6628 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6630 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6631 device->render_targets[i] = NULL;
6635 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6637 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6638 device->depth_stencil = NULL;
6642 case WINED3DRTYPE_TEXTURE:
6643 case WINED3DRTYPE_CUBETEXTURE:
6644 case WINED3DRTYPE_VOLUMETEXTURE:
6645 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6647 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6649 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6650 resource, device->stateBlock, i);
6651 device->stateBlock->state.textures[i] = NULL;
6654 if (device->updateStateBlock != device->stateBlock
6655 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6657 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6658 resource, device->updateStateBlock, i);
6659 device->updateStateBlock->state.textures[i] = NULL;
6664 case WINED3DRTYPE_BUFFER:
6665 for (i = 0; i < MAX_STREAMS; ++i)
6667 if (device->stateBlock
6668 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6670 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6671 resource, device->stateBlock, i);
6672 device->stateBlock->state.streams[i].buffer = NULL;
6675 if (device->updateStateBlock != device->stateBlock
6676 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6678 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6679 resource, device->updateStateBlock, i);
6680 device->updateStateBlock->state.streams[i].buffer = NULL;
6685 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6687 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6688 resource, device->stateBlock);
6689 device->stateBlock->state.index_buffer = NULL;
6692 if (device->updateStateBlock != device->stateBlock
6693 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6695 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6696 resource, device->updateStateBlock);
6697 device->updateStateBlock->state.index_buffer = NULL;
6705 /* Remove the resource from the resourceStore */
6706 device_resource_remove(device, resource);
6708 TRACE("Resource released.\n");
6711 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6713 IWineD3DResourceImpl *resource, *cursor;
6715 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6717 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6718 TRACE("enumerating resource %p\n", resource);
6719 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6720 ret = pCallback((IWineD3DResource *) resource, pData);
6721 if(ret == S_FALSE) {
6722 TRACE("Canceling enumeration\n");
6729 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6732 IWineD3DResourceImpl *resource;
6734 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6736 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6737 if (type == WINED3DRTYPE_SURFACE)
6739 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6741 TRACE("Found surface %p for dc %p.\n", resource, dc);
6742 *surface = (IWineD3DSurface *)resource;
6748 return WINED3DERR_INVALIDCALL;
6751 /**********************************************************
6752 * IWineD3DDevice VTbl follows
6753 **********************************************************/
6755 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6757 /*** IUnknown methods ***/
6758 IWineD3DDeviceImpl_QueryInterface,
6759 IWineD3DDeviceImpl_AddRef,
6760 IWineD3DDeviceImpl_Release,
6761 /*** IWineD3DDevice methods ***/
6762 /*** Creation methods**/
6763 IWineD3DDeviceImpl_CreateBuffer,
6764 IWineD3DDeviceImpl_CreateVertexBuffer,
6765 IWineD3DDeviceImpl_CreateIndexBuffer,
6766 IWineD3DDeviceImpl_CreateStateBlock,
6767 IWineD3DDeviceImpl_CreateSurface,
6768 IWineD3DDeviceImpl_CreateRendertargetView,
6769 IWineD3DDeviceImpl_CreateTexture,
6770 IWineD3DDeviceImpl_CreateVolumeTexture,
6771 IWineD3DDeviceImpl_CreateVolume,
6772 IWineD3DDeviceImpl_CreateCubeTexture,
6773 IWineD3DDeviceImpl_CreateQuery,
6774 IWineD3DDeviceImpl_CreateSwapChain,
6775 IWineD3DDeviceImpl_CreateVertexDeclaration,
6776 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6777 IWineD3DDeviceImpl_CreateVertexShader,
6778 IWineD3DDeviceImpl_CreateGeometryShader,
6779 IWineD3DDeviceImpl_CreatePixelShader,
6780 IWineD3DDeviceImpl_CreatePalette,
6781 /*** Odd functions **/
6782 IWineD3DDeviceImpl_Init3D,
6783 IWineD3DDeviceImpl_InitGDI,
6784 IWineD3DDeviceImpl_Uninit3D,
6785 IWineD3DDeviceImpl_UninitGDI,
6786 IWineD3DDeviceImpl_SetMultithreaded,
6787 IWineD3DDeviceImpl_EvictManagedResources,
6788 IWineD3DDeviceImpl_GetAvailableTextureMem,
6789 IWineD3DDeviceImpl_GetBackBuffer,
6790 IWineD3DDeviceImpl_GetCreationParameters,
6791 IWineD3DDeviceImpl_GetDeviceCaps,
6792 IWineD3DDeviceImpl_GetDirect3D,
6793 IWineD3DDeviceImpl_GetDisplayMode,
6794 IWineD3DDeviceImpl_SetDisplayMode,
6795 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6796 IWineD3DDeviceImpl_GetRasterStatus,
6797 IWineD3DDeviceImpl_GetSwapChain,
6798 IWineD3DDeviceImpl_Reset,
6799 IWineD3DDeviceImpl_SetDialogBoxMode,
6800 IWineD3DDeviceImpl_SetCursorProperties,
6801 IWineD3DDeviceImpl_SetCursorPosition,
6802 IWineD3DDeviceImpl_ShowCursor,
6803 /*** Getters and setters **/
6804 IWineD3DDeviceImpl_SetClipPlane,
6805 IWineD3DDeviceImpl_GetClipPlane,
6806 IWineD3DDeviceImpl_SetClipStatus,
6807 IWineD3DDeviceImpl_GetClipStatus,
6808 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6809 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6810 IWineD3DDeviceImpl_SetDepthStencilSurface,
6811 IWineD3DDeviceImpl_GetDepthStencilSurface,
6812 IWineD3DDeviceImpl_SetGammaRamp,
6813 IWineD3DDeviceImpl_GetGammaRamp,
6814 IWineD3DDeviceImpl_SetIndexBuffer,
6815 IWineD3DDeviceImpl_GetIndexBuffer,
6816 IWineD3DDeviceImpl_SetBaseVertexIndex,
6817 IWineD3DDeviceImpl_GetBaseVertexIndex,
6818 IWineD3DDeviceImpl_SetLight,
6819 IWineD3DDeviceImpl_GetLight,
6820 IWineD3DDeviceImpl_SetLightEnable,
6821 IWineD3DDeviceImpl_GetLightEnable,
6822 IWineD3DDeviceImpl_SetMaterial,
6823 IWineD3DDeviceImpl_GetMaterial,
6824 IWineD3DDeviceImpl_SetNPatchMode,
6825 IWineD3DDeviceImpl_GetNPatchMode,
6826 IWineD3DDeviceImpl_SetPaletteEntries,
6827 IWineD3DDeviceImpl_GetPaletteEntries,
6828 IWineD3DDeviceImpl_SetPixelShader,
6829 IWineD3DDeviceImpl_GetPixelShader,
6830 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6831 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6832 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6833 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6834 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6835 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6836 IWineD3DDeviceImpl_SetRenderState,
6837 IWineD3DDeviceImpl_GetRenderState,
6838 IWineD3DDeviceImpl_SetRenderTarget,
6839 IWineD3DDeviceImpl_GetRenderTarget,
6840 IWineD3DDeviceImpl_SetSamplerState,
6841 IWineD3DDeviceImpl_GetSamplerState,
6842 IWineD3DDeviceImpl_SetScissorRect,
6843 IWineD3DDeviceImpl_GetScissorRect,
6844 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6845 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6846 IWineD3DDeviceImpl_SetStreamSource,
6847 IWineD3DDeviceImpl_GetStreamSource,
6848 IWineD3DDeviceImpl_SetStreamSourceFreq,
6849 IWineD3DDeviceImpl_GetStreamSourceFreq,
6850 IWineD3DDeviceImpl_SetTexture,
6851 IWineD3DDeviceImpl_GetTexture,
6852 IWineD3DDeviceImpl_SetTextureStageState,
6853 IWineD3DDeviceImpl_GetTextureStageState,
6854 IWineD3DDeviceImpl_SetTransform,
6855 IWineD3DDeviceImpl_GetTransform,
6856 IWineD3DDeviceImpl_SetVertexDeclaration,
6857 IWineD3DDeviceImpl_GetVertexDeclaration,
6858 IWineD3DDeviceImpl_SetVertexShader,
6859 IWineD3DDeviceImpl_GetVertexShader,
6860 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6861 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6862 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6863 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6864 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6865 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6866 IWineD3DDeviceImpl_SetViewport,
6867 IWineD3DDeviceImpl_GetViewport,
6868 IWineD3DDeviceImpl_MultiplyTransform,
6869 IWineD3DDeviceImpl_ValidateDevice,
6870 IWineD3DDeviceImpl_ProcessVertices,
6871 /*** State block ***/
6872 IWineD3DDeviceImpl_BeginStateBlock,
6873 IWineD3DDeviceImpl_EndStateBlock,
6874 /*** Scene management ***/
6875 IWineD3DDeviceImpl_BeginScene,
6876 IWineD3DDeviceImpl_EndScene,
6877 IWineD3DDeviceImpl_Present,
6878 IWineD3DDeviceImpl_Clear,
6879 IWineD3DDeviceImpl_ClearRendertargetView,
6881 IWineD3DDeviceImpl_SetPrimitiveType,
6882 IWineD3DDeviceImpl_GetPrimitiveType,
6883 IWineD3DDeviceImpl_DrawPrimitive,
6884 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6885 IWineD3DDeviceImpl_DrawPrimitiveUP,
6886 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6887 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6888 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6889 IWineD3DDeviceImpl_DrawRectPatch,
6890 IWineD3DDeviceImpl_DrawTriPatch,
6891 IWineD3DDeviceImpl_DeletePatch,
6892 IWineD3DDeviceImpl_ColorFill,
6893 IWineD3DDeviceImpl_UpdateTexture,
6894 IWineD3DDeviceImpl_UpdateSurface,
6895 IWineD3DDeviceImpl_GetFrontBufferData,
6896 /*** object tracking ***/
6897 IWineD3DDeviceImpl_EnumResources,
6898 IWineD3DDeviceImpl_GetSurfaceFromDC,
6899 IWineD3DDeviceImpl_AcquireFocusWindow,
6900 IWineD3DDeviceImpl_ReleaseFocusWindow,
6901 IWineD3DDeviceImpl_SetupFullscreenWindow,
6902 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6905 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6906 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6907 IWineD3DDeviceParent *device_parent)
6909 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6910 const struct fragment_pipeline *fragment_pipeline;
6911 struct shader_caps shader_caps;
6912 struct fragment_caps ffp_caps;
6913 WINED3DDISPLAYMODE mode;
6917 device->lpVtbl = &IWineD3DDevice_Vtbl;
6919 device->wined3d = (IWineD3D *)wined3d;
6920 IWineD3D_AddRef(device->wined3d);
6921 device->adapter = wined3d->adapter_count ? adapter : NULL;
6922 device->device_parent = device_parent;
6923 list_init(&device->resources);
6924 list_init(&device->shaders);
6926 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6928 /* Get the initial screen setup for ddraw. */
6929 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6932 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6933 IWineD3D_Release(device->wined3d);
6936 device->ddraw_width = mode.Width;
6937 device->ddraw_height = mode.Height;
6938 device->ddraw_format = mode.Format;
6940 /* Save the creation parameters. */
6941 device->createParms.AdapterOrdinal = adapter_idx;
6942 device->createParms.DeviceType = device_type;
6943 device->createParms.hFocusWindow = focus_window;
6944 device->createParms.BehaviorFlags = flags;
6946 device->devType = device_type;
6947 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6949 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6950 device->shader_backend = adapter->shader_backend;
6952 if (device->shader_backend)
6954 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6955 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6956 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6957 device->vs_clipping = shader_caps.VSClipping;
6959 fragment_pipeline = adapter->fragment_pipe;
6960 device->frag_pipe = fragment_pipeline;
6961 if (fragment_pipeline)
6963 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6964 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6966 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6967 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6970 ERR("Failed to compile state table, hr %#x.\n", hr);
6971 IWineD3D_Release(device->wined3d);
6975 device->blitter = adapter->blitter;
6981 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6982 DWORD rep = This->StateTable[state].representative;
6983 struct wined3d_context *context;
6988 for(i = 0; i < This->numContexts; i++) {
6989 context = This->contexts[i];
6990 if(isStateDirty(context, rep)) continue;
6992 context->dirtyArray[context->numDirtyEntries++] = rep;
6993 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6994 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6995 context->isStateDirty[idx] |= (1 << shift);
6999 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7001 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7002 *width = context->current_rt->pow2Width;
7003 *height = context->current_rt->pow2Height;
7006 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7008 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7009 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7010 * current context's drawable, which is the size of the back buffer of the swapchain
7011 * the active context belongs to. */
7012 *width = swapchain->presentParms.BackBufferWidth;
7013 *height = swapchain->presentParms.BackBufferHeight;
7016 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7017 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7019 if (device->filter_messages)
7021 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7022 window, message, wparam, lparam);
7024 return DefWindowProcW(window, message, wparam, lparam);
7026 return DefWindowProcA(window, message, wparam, lparam);
7029 if (message == WM_DESTROY)
7031 TRACE("unregister window %p.\n", window);
7032 wined3d_unregister_window(window);
7034 if (device->focus_window == window) device->focus_window = NULL;
7035 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7039 return CallWindowProcW(proc, window, message, wparam, lparam);
7041 return CallWindowProcA(proc, window, message, wparam, lparam);