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 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((IWineD3DBuffer *)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 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
412 BOOL vs = stateblock->state.vertex_shader && device->vs_selected_mode != SHADER_NONE;
415 if (device->up_strided)
417 /* Note: this is a ddraw fixed-function code path. */
418 TRACE("=============================== Strided Input ================================\n");
419 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
420 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
424 TRACE("============================= Vertex Declaration =============================\n");
425 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
428 if (vs && !stream_info->position_transformed)
430 if (stateblock->state.vertex_declaration->half_float_conv_needed && !fixup)
432 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
433 device->useDrawStridedSlow = TRUE;
437 device->useDrawStridedSlow = FALSE;
442 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
443 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
444 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
446 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
448 device->useDrawStridedSlow = TRUE;
452 device->useDrawStridedSlow = FALSE;
457 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
459 IWineD3DBaseTextureImpl *texture;
460 enum WINED3DSRGB srgb;
462 if (!(texture = stateblock->state.textures[idx])) return;
463 srgb = stateblock->state.sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
464 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
467 void device_preload_textures(IWineD3DDeviceImpl *device)
469 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
472 if (use_vs(stateblock))
474 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
476 if (stateblock->state.vertex_shader->baseShader.reg_maps.sampler_type[i])
477 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
481 if (use_ps(stateblock))
483 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
485 if (stateblock->state.pixel_shader->baseShader.reg_maps.sampler_type[i])
486 device_preload_texture(stateblock, i);
491 WORD ffu_map = device->fixed_function_usage_map;
493 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
496 device_preload_texture(stateblock, i);
501 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
503 struct wined3d_context **new_array;
505 TRACE("Adding context %p.\n", context);
507 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
508 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
512 ERR("Failed to grow the context array.\n");
516 new_array[device->numContexts++] = context;
517 device->contexts = new_array;
521 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
523 struct wined3d_context **new_array;
527 TRACE("Removing context %p.\n", context);
529 for (i = 0; i < device->numContexts; ++i)
531 if (device->contexts[i] == context)
540 ERR("Context %p doesn't exist in context array.\n", context);
544 if (!--device->numContexts)
546 HeapFree(GetProcessHeap(), 0, device->contexts);
547 device->contexts = NULL;
551 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
552 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
555 ERR("Failed to shrink context array. Oh well.\n");
559 device->contexts = new_array;
562 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
564 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
565 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
567 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
569 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
571 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
575 /* Do not call while under the GL lock. */
576 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
577 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
579 if (device->onscreen_depth_stencil)
581 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
582 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
583 device->onscreen_depth_stencil->ds_current_size.cx,
584 device->onscreen_depth_stencil->ds_current_size.cy);
585 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
587 device->onscreen_depth_stencil = depth_stencil;
588 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
591 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
593 /* partial draw rect */
594 if (draw_rect->left || draw_rect->top
595 || draw_rect->right < target->currentDesc.Width
596 || draw_rect->bottom < target->currentDesc.Height)
599 /* partial clear rect */
600 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
601 || clear_rect->right < target->currentDesc.Width
602 || clear_rect->bottom < target->currentDesc.Height))
608 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
609 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
611 RECT current_rect, r;
613 if (ds->Flags & location)
614 SetRect(¤t_rect, 0, 0,
615 ds->ds_current_size.cx,
616 ds->ds_current_size.cy);
618 SetRectEmpty(¤t_rect);
620 IntersectRect(&r, draw_rect, ¤t_rect);
621 if (EqualRect(&r, draw_rect))
623 /* current_rect ⊇ draw_rect, modify only. */
624 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
628 if (EqualRect(&r, ¤t_rect))
630 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
634 /* Full clear, modify only. */
635 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
639 IntersectRect(&r, draw_rect, clear_rect);
640 if (EqualRect(&r, draw_rect))
642 /* clear_rect ⊇ draw_rect, modify only. */
643 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
649 surface_load_ds_location(ds, context, location);
650 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
653 /* Do not call while under the GL lock. */
654 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
655 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
656 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
658 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
659 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
660 IWineD3DSurfaceImpl *target = rts[0];
661 UINT drawable_width, drawable_height;
662 struct wined3d_context *context;
663 GLbitfield clear_mask = 0;
666 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
667 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
668 * for the cleared parts, and the untouched parts.
670 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
671 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
672 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
673 * checking all this if the dest surface is in the drawable anyway. */
674 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
676 for (i = 0; i < rt_count; ++i)
678 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
682 context = context_acquire(device, target);
685 context_release(context);
686 WARN("Invalid context, skipping clear.\n");
690 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
692 target->get_drawable_size(context, &drawable_width, &drawable_height);
696 /* Only set the values up once, as they are not changing. */
697 if (flags & WINED3DCLEAR_STENCIL)
699 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
701 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
702 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
705 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
706 glClearStencil(stencil);
707 checkGLcall("glClearStencil");
708 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
711 if (flags & WINED3DCLEAR_ZBUFFER)
713 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
715 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
718 device_switch_onscreen_ds(device, context, depth_stencil);
721 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
722 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
724 glDepthMask(GL_TRUE);
725 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
727 checkGLcall("glClearDepth");
728 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
731 if (flags & WINED3DCLEAR_TARGET)
733 for (i = 0; i < rt_count; ++i)
735 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
738 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
743 glClearColor(color->r, color->g, color->b, color->a);
744 checkGLcall("glClearColor");
745 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
750 if (context->render_offscreen)
752 glScissor(draw_rect->left, draw_rect->top,
753 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
757 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
758 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
760 checkGLcall("glScissor");
762 checkGLcall("glClear");
768 /* Now process each rect in turn. */
769 for (i = 0; i < rect_count; ++i)
771 /* Note that GL uses lower left, width/height. */
772 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
774 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
775 wine_dbgstr_rect(&clear_rect[i]),
776 wine_dbgstr_rect(¤t_rect));
778 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
779 * The rectangle is not cleared, no error is returned, but further rectanlges are
780 * still cleared if they are valid. */
781 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
783 TRACE("Rectangle with negative dimensions, ignoring.\n");
787 if (context->render_offscreen)
789 glScissor(current_rect.left, current_rect.top,
790 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
794 glScissor(current_rect.left, drawable_height - current_rect.bottom,
795 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
797 checkGLcall("glScissor");
800 checkGLcall("glClear");
806 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
807 && target->container.u.swapchain->front_buffer == target))
808 wglFlush(); /* Flush to ensure ordering across contexts. */
810 context_release(context);
816 /**********************************************************
817 * IUnknown parts follows
818 **********************************************************/
820 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
822 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
824 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
825 || IsEqualGUID(riid, &IID_IUnknown))
827 IUnknown_AddRef(iface);
832 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
835 return E_NOINTERFACE;
838 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
840 ULONG refCount = InterlockedIncrement(&This->ref);
842 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
846 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 ULONG refCount = InterlockedDecrement(&This->ref);
850 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
855 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
856 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
857 This->multistate_funcs[i] = NULL;
860 /* TODO: Clean up all the surfaces and textures! */
861 /* NOTE: You must release the parent if the object was created via a callback
862 ** ***************************/
864 if (!list_empty(&This->resources))
866 IWineD3DResourceImpl *resource;
867 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
869 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
871 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
872 FIXME("Leftover resource %p with type %s (%#x).\n",
873 resource, debug_d3dresourcetype(type), type);
877 if(This->contexts) ERR("Context array not freed!\n");
878 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
879 This->haveHardwareCursor = FALSE;
881 IWineD3D_Release(This->wined3d);
882 This->wined3d = NULL;
883 HeapFree(GetProcessHeap(), 0, This);
884 TRACE("Freed device %p\n", This);
890 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
891 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
894 struct wined3d_buffer *object;
897 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
899 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
902 ERR("Failed to allocate memory\n");
903 return E_OUTOFMEMORY;
906 FIXME("Ignoring access flags (pool)\n");
908 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
909 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
912 WARN("Failed to initialize buffer, hr %#x.\n", hr);
913 HeapFree(GetProcessHeap(), 0, object);
916 object->desc = *desc;
918 TRACE("Created buffer %p.\n", object);
920 *buffer = (IWineD3DBuffer *)object;
925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
926 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
927 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
930 struct wined3d_buffer *object;
933 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
934 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
936 if (Pool == WINED3DPOOL_SCRATCH)
938 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
939 * anyway, SCRATCH vertex buffers aren't usable anywhere
941 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
942 *ppVertexBuffer = NULL;
943 return WINED3DERR_INVALIDCALL;
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 ERR("Out of memory\n");
950 *ppVertexBuffer = NULL;
951 return WINED3DERR_OUTOFVIDEOMEMORY;
954 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
955 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
958 WARN("Failed to initialize buffer, hr %#x.\n", hr);
959 HeapFree(GetProcessHeap(), 0, object);
963 TRACE("Created buffer %p.\n", object);
964 *ppVertexBuffer = (IWineD3DBuffer *)object;
969 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
970 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
971 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
974 struct wined3d_buffer *object;
977 TRACE("(%p) Creating index buffer\n", This);
979 /* Allocate the storage for the device */
980 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
983 ERR("Out of memory\n");
984 *ppIndexBuffer = NULL;
985 return WINED3DERR_OUTOFVIDEOMEMORY;
988 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
989 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
993 WARN("Failed to initialize buffer, hr %#x\n", hr);
994 HeapFree(GetProcessHeap(), 0, object);
998 TRACE("Created buffer %p.\n", object);
1000 *ppIndexBuffer = (IWineD3DBuffer *) object;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1006 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DStateBlockImpl *object;
1012 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1015 ERR("Failed to allocate stateblock memory.\n");
1016 return E_OUTOFMEMORY;
1019 hr = stateblock_init(object, This, type);
1022 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1023 HeapFree(GetProcessHeap(), 0, object);
1027 TRACE("Created stateblock %p.\n", object);
1028 *stateblock = (IWineD3DStateBlock *)object;
1033 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1034 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1035 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1036 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1039 IWineD3DSurfaceImpl *object;
1042 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1043 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1044 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1045 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1046 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1048 if (Impl == SURFACE_OPENGL && !This->adapter)
1050 ERR("OpenGL surfaces are not available without OpenGL.\n");
1051 return WINED3DERR_NOTAVAILABLE;
1054 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1057 ERR("Failed to allocate surface memory.\n");
1058 return WINED3DERR_OUTOFVIDEOMEMORY;
1061 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1062 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1065 WARN("Failed to initialize surface, returning %#x.\n", hr);
1066 HeapFree(GetProcessHeap(), 0, object);
1070 TRACE("(%p) : Created surface %p\n", This, object);
1072 *surface = (IWineD3DSurface *)object;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1078 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1080 struct wined3d_rendertarget_view *object;
1082 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1083 iface, resource, parent, rendertarget_view);
1085 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1088 ERR("Failed to allocate memory\n");
1089 return E_OUTOFMEMORY;
1092 wined3d_rendertarget_view_init(object, resource, parent);
1094 TRACE("Created render target view %p.\n", object);
1095 *rendertarget_view = (IWineD3DRendertargetView *)object;
1100 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1101 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1102 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1105 IWineD3DTextureImpl *object;
1108 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1109 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1110 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1112 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1115 ERR("Out of memory\n");
1117 return WINED3DERR_OUTOFVIDEOMEMORY;
1120 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1123 WARN("Failed to initialize texture, returning %#x\n", hr);
1124 HeapFree(GetProcessHeap(), 0, object);
1129 *ppTexture = (IWineD3DTexture *)object;
1131 TRACE("(%p) : Created texture %p\n", This, object);
1136 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1137 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1138 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141 IWineD3DVolumeTextureImpl *object;
1144 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1145 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1147 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1150 ERR("Out of memory\n");
1151 *ppVolumeTexture = NULL;
1152 return WINED3DERR_OUTOFVIDEOMEMORY;
1155 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1158 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1159 HeapFree(GetProcessHeap(), 0, object);
1160 *ppVolumeTexture = NULL;
1164 TRACE("(%p) : Created volume texture %p.\n", This, object);
1165 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1170 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1171 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1172 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1175 IWineD3DVolumeImpl *object;
1178 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1179 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1181 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1184 ERR("Out of memory\n");
1186 return WINED3DERR_OUTOFVIDEOMEMORY;
1189 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1192 WARN("Failed to initialize volume, returning %#x.\n", hr);
1193 HeapFree(GetProcessHeap(), 0, object);
1197 TRACE("(%p) : Created volume %p.\n", This, object);
1198 *ppVolume = (IWineD3DVolume *)object;
1203 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1204 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1205 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1208 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1214 ERR("Out of memory\n");
1215 *ppCubeTexture = NULL;
1216 return WINED3DERR_OUTOFVIDEOMEMORY;
1219 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1222 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1223 HeapFree(GetProcessHeap(), 0, object);
1224 *ppCubeTexture = NULL;
1228 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1229 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1234 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1235 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1238 IWineD3DQueryImpl *object;
1241 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1243 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1246 ERR("Failed to allocate query memory.\n");
1247 return E_OUTOFMEMORY;
1250 hr = query_init(object, This, type);
1253 WARN("Failed to initialize query, hr %#x.\n", hr);
1254 HeapFree(GetProcessHeap(), 0, object);
1258 TRACE("Created query %p.\n", object);
1259 *query = (IWineD3DQuery *)object;
1264 /* Do not call while under the GL lock. */
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1266 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1267 void *parent, IWineD3DSwapChain **swapchain)
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 IWineD3DSwapChainImpl *object;
1273 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1274 iface, present_parameters, swapchain, parent, surface_type);
1276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1279 ERR("Failed to allocate swapchain memory.\n");
1280 return E_OUTOFMEMORY;
1283 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1286 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1287 HeapFree(GetProcessHeap(), 0, object);
1291 TRACE("Created swapchain %p.\n", object);
1292 *swapchain = (IWineD3DSwapChain *)object;
1297 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1298 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1300 TRACE("(%p)\n", This);
1302 return This->NumberOfSwapChains;
1305 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1307 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1309 if(iSwapChain < This->NumberOfSwapChains) {
1310 *pSwapChain = 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 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1521 ERR("Failed to allocate shader memory.\n");
1522 return E_OUTOFMEMORY;
1525 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1528 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1529 HeapFree(GetProcessHeap(), 0, object);
1533 TRACE("Created vertex shader %p.\n", object);
1534 *ppVertexShader = (IWineD3DVertexShader *)object;
1539 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1540 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1541 void *parent, const struct wined3d_parent_ops *parent_ops,
1542 IWineD3DGeometryShader **shader)
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 struct wined3d_geometryshader *object;
1548 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1551 ERR("Failed to allocate shader memory.\n");
1552 return E_OUTOFMEMORY;
1555 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1558 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1559 HeapFree(GetProcessHeap(), 0, object);
1563 TRACE("Created geometry shader %p.\n", object);
1564 *shader = (IWineD3DGeometryShader *)object;
1569 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1570 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1571 void *parent, const struct wined3d_parent_ops *parent_ops,
1572 IWineD3DPixelShader **ppPixelShader)
1574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1575 IWineD3DPixelShaderImpl *object;
1578 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1581 ERR("Failed to allocate shader memory.\n");
1582 return E_OUTOFMEMORY;
1585 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1588 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1589 HeapFree(GetProcessHeap(), 0, object);
1593 TRACE("Created pixel shader %p.\n", object);
1594 *ppPixelShader = (IWineD3DPixelShader *)object;
1599 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1600 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1603 IWineD3DPaletteImpl *object;
1606 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1607 iface, Flags, PalEnt, Palette, parent);
1609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1612 ERR("Failed to allocate palette memory.\n");
1613 return E_OUTOFMEMORY;
1616 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1619 WARN("Failed to initialize palette, hr %#x.\n", hr);
1620 HeapFree(GetProcessHeap(), 0, object);
1624 TRACE("Created palette %p.\n", object);
1625 *Palette = (IWineD3DPalette *)object;
1630 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1634 HDC dcb = NULL, dcs = NULL;
1635 WINEDDCOLORKEY colorkey;
1637 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1640 GetObjectA(hbm, sizeof(BITMAP), &bm);
1641 dcb = CreateCompatibleDC(NULL);
1643 SelectObject(dcb, hbm);
1647 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1648 * couldn't be loaded
1650 memset(&bm, 0, sizeof(bm));
1655 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1656 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1657 &wined3d_null_parent_ops, &This->logo_surface);
1660 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1665 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1666 if(FAILED(hr)) goto out;
1667 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1668 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1670 colorkey.dwColorSpaceLowValue = 0;
1671 colorkey.dwColorSpaceHighValue = 0;
1672 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1676 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1677 /* Fill the surface with a white color to show that wined3d is there */
1678 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1682 if (dcb) DeleteDC(dcb);
1683 if (hbm) DeleteObject(hbm);
1686 /* Context activation is done by the caller. */
1687 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1689 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1691 /* Under DirectX you can have texture stage operations even if no texture is
1692 bound, whereas opengl will only do texture operations when a valid texture is
1693 bound. We emulate this by creating dummy textures and binding them to each
1694 texture stage, but disable all stages by default. Hence if a stage is enabled
1695 then the default texture will kick in until replaced by a SetTexture call */
1698 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1700 /* The dummy texture does not have client storage backing */
1701 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1702 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1705 for (i = 0; i < gl_info->limits.textures; ++i)
1707 GLubyte white = 255;
1709 /* Make appropriate texture active */
1710 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1711 checkGLcall("glActiveTextureARB");
1713 /* Generate an opengl texture name */
1714 glGenTextures(1, &This->dummyTextureName[i]);
1715 checkGLcall("glGenTextures");
1716 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1718 /* Generate a dummy 2d texture (not using 1d because they cause many
1719 * DRI drivers fall back to sw) */
1720 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1721 checkGLcall("glBindTexture");
1723 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1724 checkGLcall("glTexImage2D");
1727 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1729 /* Reenable because if supported it is enabled by default */
1730 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1731 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1737 /* Context activation is done by the caller. */
1738 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1741 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1742 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1745 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1748 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1750 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1752 if (!wined3d_register_window(window, device))
1754 ERR("Failed to register window %p.\n", window);
1758 device->focus_window = window;
1759 SetForegroundWindow(window);
1764 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1766 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1768 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1769 device->focus_window = NULL;
1772 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1773 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1776 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1777 IWineD3DSwapChainImpl *swapchain = NULL;
1778 struct wined3d_context *context;
1783 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1785 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1786 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1788 TRACE("(%p) : Creating stateblock\n", This);
1789 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1792 WARN("Failed to create stateblock\n");
1795 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1796 This->updateStateBlock = This->stateBlock;
1797 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1799 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1800 sizeof(*This->render_targets) * gl_info->limits.buffers);
1802 This->NumberOfPalettes = 1;
1803 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1804 if (!This->palettes || !This->render_targets)
1806 ERR("Out of memory!\n");
1810 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1811 if(!This->palettes[0]) {
1812 ERR("Out of memory!\n");
1816 for (i = 0; i < 256; ++i) {
1817 This->palettes[0][i].peRed = 0xFF;
1818 This->palettes[0][i].peGreen = 0xFF;
1819 This->palettes[0][i].peBlue = 0xFF;
1820 This->palettes[0][i].peFlags = 0xFF;
1822 This->currentPalette = 0;
1824 /* Initialize the texture unit mapping to a 1:1 mapping */
1825 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1827 if (state < gl_info->limits.fragment_samplers)
1829 This->texUnitMap[state] = state;
1830 This->rev_tex_unit_map[state] = state;
1832 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1833 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1837 /* Setup the implicit swapchain. This also initializes a context. */
1838 TRACE("Creating implicit swapchain\n");
1839 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1840 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1843 WARN("Failed to create implicit swapchain\n");
1847 This->NumberOfSwapChains = 1;
1848 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1849 if(!This->swapchains) {
1850 ERR("Out of memory!\n");
1853 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1855 if (swapchain->back_buffers && swapchain->back_buffers[0])
1857 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1858 This->render_targets[0] = swapchain->back_buffers[0];
1862 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1863 This->render_targets[0] = swapchain->front_buffer;
1865 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1867 /* Depth Stencil support */
1868 This->depth_stencil = This->auto_depth_stencil;
1869 if (This->depth_stencil)
1870 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1872 hr = This->shader_backend->shader_alloc_private(iface);
1874 TRACE("Shader private data couldn't be allocated\n");
1877 hr = This->frag_pipe->alloc_private(iface);
1879 TRACE("Fragment pipeline private data couldn't be allocated\n");
1882 hr = This->blitter->alloc_private(iface);
1884 TRACE("Blitter private data couldn't be allocated\n");
1888 /* Set up some starting GL setup */
1890 /* Setup all the devices defaults */
1891 stateblock_init_default_state(This->stateBlock);
1893 context = context_acquire(This, swapchain->front_buffer);
1895 create_dummy_textures(This);
1899 /* Initialize the current view state */
1900 This->view_ident = 1;
1901 This->contexts[0]->last_was_rhw = 0;
1902 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1903 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1905 switch(wined3d_settings.offscreen_rendering_mode) {
1907 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1910 case ORM_BACKBUFFER:
1912 if (context_get_current()->aux_buffers > 0)
1914 TRACE("Using auxilliary buffer for offscreen rendering\n");
1915 This->offscreenBuffer = GL_AUX0;
1917 TRACE("Using back buffer for offscreen rendering\n");
1918 This->offscreenBuffer = GL_BACK;
1923 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1926 context_release(context);
1928 /* Clear the screen */
1929 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1930 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1933 This->d3d_initialized = TRUE;
1935 if(wined3d_settings.logo) {
1936 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1938 This->highest_dirty_ps_const = 0;
1939 This->highest_dirty_vs_const = 0;
1943 HeapFree(GetProcessHeap(), 0, This->render_targets);
1944 HeapFree(GetProcessHeap(), 0, This->swapchains);
1945 This->NumberOfSwapChains = 0;
1946 if(This->palettes) {
1947 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1948 HeapFree(GetProcessHeap(), 0, This->palettes);
1950 This->NumberOfPalettes = 0;
1952 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1954 if(This->stateBlock) {
1955 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1956 This->stateBlock = NULL;
1958 if (This->blit_priv) {
1959 This->blitter->free_private(iface);
1961 if (This->fragment_priv) {
1962 This->frag_pipe->free_private(iface);
1964 if (This->shader_priv) {
1965 This->shader_backend->shader_free_private(iface);
1970 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1971 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1974 IWineD3DSwapChainImpl *swapchain = NULL;
1977 /* Setup the implicit swapchain */
1978 TRACE("Creating implicit swapchain\n");
1979 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1980 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1983 WARN("Failed to create implicit swapchain\n");
1987 This->NumberOfSwapChains = 1;
1988 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1989 if(!This->swapchains) {
1990 ERR("Out of memory!\n");
1993 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1997 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2001 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2003 IWineD3DResource_UnLoad(resource);
2004 IWineD3DResource_Release(resource);
2008 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2009 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2012 const struct wined3d_gl_info *gl_info;
2013 struct wined3d_context *context;
2016 TRACE("(%p)\n", This);
2018 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2020 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2021 * it was created. Thus make sure a context is active for the glDelete* calls
2023 context = context_acquire(This, NULL);
2024 gl_info = context->gl_info;
2026 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2028 /* Unload resources */
2029 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2031 TRACE("Deleting high order patches\n");
2032 for(i = 0; i < PATCHMAP_SIZE; i++) {
2033 struct list *e1, *e2;
2034 struct WineD3DRectPatch *patch;
2035 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2036 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2037 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2041 /* Delete the mouse cursor texture */
2042 if(This->cursorTexture) {
2044 glDeleteTextures(1, &This->cursorTexture);
2046 This->cursorTexture = 0;
2049 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2050 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2052 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2053 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2056 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2057 * private data, it might contain opengl pointers
2059 if(This->depth_blt_texture) {
2061 glDeleteTextures(1, &This->depth_blt_texture);
2063 This->depth_blt_texture = 0;
2065 if (This->depth_blt_rb) {
2067 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2069 This->depth_blt_rb = 0;
2070 This->depth_blt_rb_w = 0;
2071 This->depth_blt_rb_h = 0;
2074 /* Release the update stateblock */
2075 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2076 if(This->updateStateBlock != This->stateBlock)
2077 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2079 This->updateStateBlock = NULL;
2081 { /* because were not doing proper internal refcounts releasing the primary state block
2082 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2083 to set this->stateBlock = NULL; first */
2084 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2085 This->stateBlock = NULL;
2087 /* Release the stateblock */
2088 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2089 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2093 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2094 This->blitter->free_private(iface);
2095 This->frag_pipe->free_private(iface);
2096 This->shader_backend->shader_free_private(iface);
2098 /* Release the buffers (with sanity checks)*/
2099 if (This->onscreen_depth_stencil)
2101 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2102 This->onscreen_depth_stencil = NULL;
2105 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2106 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2108 if (This->auto_depth_stencil != This->depth_stencil)
2109 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2111 This->depth_stencil = NULL;
2113 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2114 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2116 TRACE("Setting rendertarget to NULL\n");
2117 This->render_targets[0] = NULL;
2119 if (This->auto_depth_stencil)
2121 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2123 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2125 This->auto_depth_stencil = NULL;
2128 context_release(context);
2130 for(i=0; i < This->NumberOfSwapChains; i++) {
2131 TRACE("Releasing the implicit swapchain %d\n", i);
2132 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2133 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2137 HeapFree(GetProcessHeap(), 0, This->swapchains);
2138 This->swapchains = NULL;
2139 This->NumberOfSwapChains = 0;
2141 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2142 HeapFree(GetProcessHeap(), 0, This->palettes);
2143 This->palettes = NULL;
2144 This->NumberOfPalettes = 0;
2146 HeapFree(GetProcessHeap(), 0, This->render_targets);
2147 This->render_targets = NULL;
2149 This->d3d_initialized = FALSE;
2154 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2158 for(i=0; i < This->NumberOfSwapChains; i++) {
2159 TRACE("Releasing the implicit swapchain %d\n", i);
2160 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2161 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2165 HeapFree(GetProcessHeap(), 0, This->swapchains);
2166 This->swapchains = NULL;
2167 This->NumberOfSwapChains = 0;
2171 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2172 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2173 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2175 * There is no way to deactivate thread safety once it is enabled.
2177 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2180 /*For now just store the flag(needed in case of ddraw) */
2181 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2184 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2185 const WINED3DDISPLAYMODE* pMode) {
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2188 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2192 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2194 /* Resize the screen even without a window:
2195 * The app could have unset it with SetCooperativeLevel, but not called
2196 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2197 * but we don't have any hwnd
2200 memset(&devmode, 0, sizeof(devmode));
2201 devmode.dmSize = sizeof(devmode);
2202 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2203 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2204 devmode.dmPelsWidth = pMode->Width;
2205 devmode.dmPelsHeight = pMode->Height;
2207 devmode.dmDisplayFrequency = pMode->RefreshRate;
2208 if (pMode->RefreshRate)
2209 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2211 /* Only change the mode if necessary */
2212 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2213 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2216 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2217 if (ret != DISP_CHANGE_SUCCESSFUL)
2219 if (devmode.dmDisplayFrequency)
2221 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2222 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2223 devmode.dmDisplayFrequency = 0;
2224 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2226 if(ret != DISP_CHANGE_SUCCESSFUL) {
2227 return WINED3DERR_NOTAVAILABLE;
2231 /* Store the new values */
2232 This->ddraw_width = pMode->Width;
2233 This->ddraw_height = pMode->Height;
2234 This->ddraw_format = pMode->Format;
2236 /* And finally clip mouse to our screen */
2237 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2238 ClipCursor(&clip_rc);
2243 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 *ppD3D = This->wined3d;
2246 TRACE("Returning %p.\n", *ppD3D);
2247 IWineD3D_AddRef(*ppD3D);
2251 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2254 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2255 (This->adapter->TextureRam/(1024*1024)),
2256 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2257 /* return simulated texture memory left */
2258 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2262 * Get / Set Stream Source
2264 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2265 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 struct wined3d_stream_state *stream;
2269 IWineD3DBuffer *oldSrc;
2271 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2272 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2274 if (StreamNumber >= MAX_STREAMS) {
2275 WARN("Stream out of range %d\n", StreamNumber);
2276 return WINED3DERR_INVALIDCALL;
2277 } else if(OffsetInBytes & 0x3) {
2278 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2279 return WINED3DERR_INVALIDCALL;
2282 stream = &This->updateStateBlock->state.streams[StreamNumber];
2283 oldSrc = (IWineD3DBuffer *)stream->buffer;
2285 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2287 if (oldSrc == pStreamData
2288 && stream->stride == Stride
2289 && stream->offset == OffsetInBytes)
2291 TRACE("Application is setting the old values over, nothing to do\n");
2295 stream->buffer = (struct wined3d_buffer *)pStreamData;
2298 stream->stride = Stride;
2299 stream->offset = OffsetInBytes;
2302 /* Handle recording of state blocks */
2303 if (This->isRecordingState) {
2304 TRACE("Recording... not performing anything\n");
2305 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2306 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2312 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2313 IWineD3DBuffer_AddRef(pStreamData);
2317 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2318 IWineD3DBuffer_Release(oldSrc);
2321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2326 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2327 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 struct wined3d_stream_state *stream;
2332 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2333 iface, StreamNumber, pStream, pOffset, pStride);
2335 if (StreamNumber >= MAX_STREAMS)
2337 WARN("Stream out of range %d\n", StreamNumber);
2338 return WINED3DERR_INVALIDCALL;
2341 stream = &This->stateBlock->state.streams[StreamNumber];
2342 *pStream = (IWineD3DBuffer *)stream->buffer;
2343 *pStride = stream->stride;
2344 if (pOffset) *pOffset = stream->offset;
2346 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2351 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 struct wined3d_stream_state *stream;
2354 UINT oldFlags, oldFreq;
2356 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2358 /* Verify input at least in d3d9 this is invalid. */
2359 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2361 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2362 return WINED3DERR_INVALIDCALL;
2364 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2366 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2367 return WINED3DERR_INVALIDCALL;
2371 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2372 return WINED3DERR_INVALIDCALL;
2375 stream = &This->updateStateBlock->state.streams[StreamNumber];
2376 oldFlags = stream->flags;
2377 oldFreq = stream->frequency;
2379 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2380 stream->frequency = Divider & 0x7FFFFF;
2382 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2384 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 struct wined3d_stream_state *stream;
2394 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2396 stream = &This->updateStateBlock->state.streams[StreamNumber];
2397 *Divider = stream->flags | stream->frequency;
2399 TRACE("Returning %#x.\n", *Divider);
2405 * Get / Set & Multiply Transform
2407 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2410 /* Most of this routine, comments included copied from ddraw tree initially: */
2411 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2413 /* Handle recording of state blocks */
2414 if (This->isRecordingState) {
2415 TRACE("Recording... not performing anything\n");
2416 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2417 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2422 * If the new matrix is the same as the current one,
2423 * we cut off any further processing. this seems to be a reasonable
2424 * optimization because as was noticed, some apps (warcraft3 for example)
2425 * tend towards setting the same matrix repeatedly for some reason.
2427 * From here on we assume that the new matrix is different, wherever it matters.
2429 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2431 TRACE("The app is setting the same matrix over again\n");
2436 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2440 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2441 where ViewMat = Camera space, WorldMat = world space.
2443 In OpenGL, camera and world space is combined into GL_MODELVIEW
2444 matrix. The Projection matrix stay projection matrix.
2447 /* Capture the times we can just ignore the change for now */
2448 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2449 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2450 /* Handled by the state manager */
2453 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2461 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2463 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2465 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2467 *matrix = device->stateBlock->state.transforms[state];
2472 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2473 const WINED3DMATRIX *mat = NULL;
2476 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2477 * below means it will be recorded in a state block change, but it
2478 * works regardless where it is recorded.
2479 * If this is found to be wrong, change to StateBlock.
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2484 if (State <= HIGHEST_TRANSFORMSTATE)
2486 mat = &This->updateStateBlock->state.transforms[State];
2490 FIXME("Unhandled transform state!!\n");
2493 multiply_matrix(&temp, mat, pMatrix);
2495 /* Apply change via set transform - will reapply to eg. lights this way */
2496 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2502 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2503 you can reference any indexes you want as long as that number max are enabled at any
2504 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2505 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2506 but when recording, just build a chain pretty much of commands to be replayed. */
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2510 struct wined3d_light_info *object = NULL;
2511 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2515 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2517 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2521 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2522 return WINED3DERR_INVALIDCALL;
2525 switch(pLight->Type) {
2526 case WINED3DLIGHT_POINT:
2527 case WINED3DLIGHT_SPOT:
2528 case WINED3DLIGHT_PARALLELPOINT:
2529 case WINED3DLIGHT_GLSPOT:
2530 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2533 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2535 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2536 return WINED3DERR_INVALIDCALL;
2540 case WINED3DLIGHT_DIRECTIONAL:
2541 /* Ignores attenuation */
2545 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2546 return WINED3DERR_INVALIDCALL;
2549 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2551 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2552 if(object->OriginalIndex == Index) break;
2557 TRACE("Adding new light\n");
2558 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2560 ERR("Out of memory error when allocating a light\n");
2561 return E_OUTOFMEMORY;
2563 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2564 object->glIndex = -1;
2565 object->OriginalIndex = Index;
2568 /* Initialize the object */
2569 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,
2570 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2571 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2572 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2573 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2574 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2575 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2577 /* Save away the information */
2578 object->OriginalParms = *pLight;
2580 switch (pLight->Type) {
2581 case WINED3DLIGHT_POINT:
2583 object->lightPosn[0] = pLight->Position.x;
2584 object->lightPosn[1] = pLight->Position.y;
2585 object->lightPosn[2] = pLight->Position.z;
2586 object->lightPosn[3] = 1.0f;
2587 object->cutoff = 180.0f;
2591 case WINED3DLIGHT_DIRECTIONAL:
2593 object->lightPosn[0] = -pLight->Direction.x;
2594 object->lightPosn[1] = -pLight->Direction.y;
2595 object->lightPosn[2] = -pLight->Direction.z;
2596 object->lightPosn[3] = 0.0f;
2597 object->exponent = 0.0f;
2598 object->cutoff = 180.0f;
2601 case WINED3DLIGHT_SPOT:
2603 object->lightPosn[0] = pLight->Position.x;
2604 object->lightPosn[1] = pLight->Position.y;
2605 object->lightPosn[2] = pLight->Position.z;
2606 object->lightPosn[3] = 1.0f;
2609 object->lightDirn[0] = pLight->Direction.x;
2610 object->lightDirn[1] = pLight->Direction.y;
2611 object->lightDirn[2] = pLight->Direction.z;
2612 object->lightDirn[3] = 1.0f;
2615 * opengl-ish and d3d-ish spot lights use too different models for the
2616 * light "intensity" as a function of the angle towards the main light direction,
2617 * so we only can approximate very roughly.
2618 * however spot lights are rather rarely used in games (if ever used at all).
2619 * furthermore if still used, probably nobody pays attention to such details.
2621 if (!pLight->Falloff)
2623 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2624 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2625 * will always be 1.0 for both of them, and we don't have to care for the
2626 * rest of the rather complex calculation
2628 object->exponent = 0.0f;
2630 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2631 if (rho < 0.0001f) rho = 0.0001f;
2632 object->exponent = -0.3f/logf(cosf(rho/2));
2634 if (object->exponent > 128.0f)
2636 object->exponent = 128.0f;
2638 object->cutoff = (float) (pLight->Phi*90/M_PI);
2644 FIXME("Unrecognized light type %d\n", pLight->Type);
2647 /* Update the live definitions if the light is currently assigned a glIndex */
2648 if (object->glIndex != -1 && !This->isRecordingState) {
2649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2654 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2656 struct wined3d_light_info *lightInfo = NULL;
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2660 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2662 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2664 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2665 if(lightInfo->OriginalIndex == Index) break;
2671 TRACE("Light information requested but light not defined\n");
2672 return WINED3DERR_INVALIDCALL;
2675 *pLight = lightInfo->OriginalParms;
2680 * Get / Set Light Enable
2681 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2683 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2685 struct wined3d_light_info *lightInfo = NULL;
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2689 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2691 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2693 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2694 if(lightInfo->OriginalIndex == Index) break;
2697 TRACE("Found light: %p\n", lightInfo);
2699 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2702 TRACE("Light enabled requested but light not defined, so defining one!\n");
2703 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2705 /* Search for it again! Should be fairly quick as near head of list */
2706 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2708 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2709 if(lightInfo->OriginalIndex == Index) break;
2714 FIXME("Adding default lights has failed dismally\n");
2715 return WINED3DERR_INVALIDCALL;
2720 if(lightInfo->glIndex != -1) {
2721 if(!This->isRecordingState) {
2722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2725 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2726 lightInfo->glIndex = -1;
2728 TRACE("Light already disabled, nothing to do\n");
2730 lightInfo->enabled = FALSE;
2732 lightInfo->enabled = TRUE;
2733 if (lightInfo->glIndex != -1) {
2735 TRACE("Nothing to do as light was enabled\n");
2738 /* Find a free gl light */
2739 for (i = 0; i < This->maxConcurrentLights; ++i)
2741 if (!This->updateStateBlock->state.lights[i])
2743 This->updateStateBlock->state.lights[i] = lightInfo;
2744 lightInfo->glIndex = i;
2748 if(lightInfo->glIndex == -1) {
2749 /* Our tests show that Windows returns D3D_OK in this situation, even with
2750 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2751 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2752 * as well for those lights.
2754 * TODO: Test how this affects rendering
2756 WARN("Too many concurrently active lights\n");
2760 /* i == lightInfo->glIndex */
2761 if(!This->isRecordingState) {
2762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2770 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2772 struct wined3d_light_info *lightInfo = NULL;
2773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2776 TRACE("(%p) : for idx(%d)\n", This, Index);
2778 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2780 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2781 if(lightInfo->OriginalIndex == Index) break;
2787 TRACE("Light enabled state requested but light not defined\n");
2788 return WINED3DERR_INVALIDCALL;
2790 /* true is 128 according to SetLightEnable */
2791 *pEnable = lightInfo->enabled ? 128 : 0;
2796 * Get / Set Clip Planes
2798 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2802 /* Validate Index */
2803 if (Index >= This->adapter->gl_info.limits.clipplanes)
2805 TRACE("Application has requested clipplane this device doesn't support\n");
2806 return WINED3DERR_INVALIDCALL;
2809 This->updateStateBlock->changed.clipplane |= 1 << Index;
2811 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2812 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2813 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2814 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2816 TRACE("Application is setting old values over, nothing to do\n");
2820 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2821 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2822 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2823 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2825 /* Handle recording of state blocks */
2826 if (This->isRecordingState) {
2827 TRACE("Recording... not performing anything\n");
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 TRACE("(%p) : for idx %d\n", This, Index);
2840 /* Validate Index */
2841 if (Index >= This->adapter->gl_info.limits.clipplanes)
2843 TRACE("Application has requested clipplane this device doesn't support\n");
2844 return WINED3DERR_INVALIDCALL;
2847 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2848 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2849 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2850 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2855 * Get / Set Clip Plane Status
2856 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2858 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 FIXME("(%p) : stub\n", This);
2863 return WINED3DERR_INVALIDCALL;
2865 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2866 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 FIXME("(%p) : stub\n", This);
2875 return WINED3DERR_INVALIDCALL;
2877 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2878 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2883 * Get / Set Material
2885 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 This->updateStateBlock->changed.material = TRUE;
2889 This->updateStateBlock->state.material = *pMaterial;
2891 /* Handle recording of state blocks */
2892 if (This->isRecordingState) {
2893 TRACE("Recording... not performing anything\n");
2897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 *pMaterial = This->updateStateBlock->state.material;
2904 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2905 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2906 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2907 pMaterial->Ambient.b, pMaterial->Ambient.a);
2908 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2909 pMaterial->Specular.b, pMaterial->Specular.a);
2910 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2911 pMaterial->Emissive.b, pMaterial->Emissive.a);
2912 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2921 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 IWineD3DBuffer *oldIdxs;
2926 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2927 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2929 This->updateStateBlock->changed.indices = TRUE;
2930 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2931 This->updateStateBlock->state.index_format = fmt;
2933 /* Handle recording of state blocks */
2934 if (This->isRecordingState) {
2935 TRACE("Recording... not performing anything\n");
2936 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2937 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2941 if(oldIdxs != pIndexData) {
2942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2944 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2945 IWineD3DBuffer_AddRef(pIndexData);
2948 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2949 IWineD3DBuffer_Release(oldIdxs);
2956 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2962 /* up ref count on ppindexdata */
2964 IWineD3DBuffer_AddRef(*ppIndexData);
2965 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2967 TRACE("(%p) No index data set\n", This);
2969 TRACE("Returning %p\n", *ppIndexData);
2974 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2975 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 TRACE("(%p)->(%d)\n", This, BaseIndex);
2979 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2981 TRACE("Application is setting the old value over, nothing to do\n");
2985 This->updateStateBlock->state.base_vertex_index = BaseIndex;
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2991 /* The base vertex index affects the stream sources */
2992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 TRACE("(%p) : base_index %p\n", This, base_index);
3000 *base_index = This->stateBlock->state.base_vertex_index;
3002 TRACE("Returning %u\n", *base_index);
3008 * Get / Set Viewports
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p)\n", This);
3014 This->updateStateBlock->changed.viewport = TRUE;
3015 This->updateStateBlock->state.viewport = *pViewport;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3023 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3024 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3031 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p)\n", This);
3034 *pViewport = This->stateBlock->state.viewport;
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3039 WINED3DRENDERSTATETYPE State, DWORD Value)
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 DWORD oldValue = This->stateBlock->state.render_states[State];
3044 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3046 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3047 This->updateStateBlock->state.render_states[State] = Value;
3049 /* Handle recording of state blocks */
3050 if (This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3055 /* Compared here and not before the assignment to allow proper stateblock recording */
3056 if(Value == oldValue) {
3057 TRACE("Application is setting the old value over, nothing to do\n");
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3065 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3066 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3072 *pValue = This->stateBlock->state.render_states[State];
3077 * Get / Set Sampler States
3078 * TODO: Verify against dx9 definitions
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3086 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3088 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3089 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3092 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3094 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3095 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3098 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3099 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3100 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3102 /* Handle recording of state blocks */
3103 if (This->isRecordingState) {
3104 TRACE("Recording... not performing anything\n");
3108 if(oldValue == Value) {
3109 TRACE("Application is setting the old value over, nothing to do\n");
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3122 This, Sampler, debug_d3dsamplerstate(Type), Type);
3124 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3125 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3128 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3130 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3131 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3133 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3134 TRACE("(%p) : Returning %#x\n", This, *Value);
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 This->updateStateBlock->changed.scissorRect = TRUE;
3143 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3145 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3148 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3150 if(This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 *pRect = This->updateStateBlock->state.scissor_rect;
3164 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3170 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3172 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3174 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3175 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3177 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3178 This->updateStateBlock->changed.vertexDecl = TRUE;
3180 if (This->isRecordingState) {
3181 TRACE("Recording... not performing anything\n");
3183 } else if(pDecl == oldDecl) {
3184 /* Checked after the assignment to allow proper stateblock recording */
3185 TRACE("Application is setting the old declaration over, nothing to do\n");
3189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3193 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3196 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3198 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3199 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3203 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3208 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3209 This->updateStateBlock->changed.vertexShader = TRUE;
3211 if (This->isRecordingState) {
3212 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3213 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3214 TRACE("Recording... not performing anything\n");
3216 } else if(oldShader == pShader) {
3217 /* Checked here to allow proper stateblock recording */
3218 TRACE("App is setting the old shader over, nothing to do\n");
3222 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3223 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3224 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3231 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3233 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3234 IWineD3DVertexShader *shader;
3236 TRACE("iface %p.\n", iface);
3238 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3239 if (shader) IWineD3DVertexShader_AddRef(shader);
3241 TRACE("Returning %p.\n", shader);
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3246 IWineD3DDevice *iface,
3248 CONST BOOL *srcData,
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3254 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3255 iface, srcData, start, count);
3257 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3259 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3260 for (i = 0; i < cnt; i++)
3261 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3263 for (i = start; i < cnt + start; ++i) {
3264 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3267 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3273 IWineD3DDevice *iface,
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 int cnt = min(count, MAX_CONST_B - start);
3281 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3282 iface, dstData, start, count);
3284 if (!dstData || cnt < 0)
3285 return WINED3DERR_INVALIDCALL;
3287 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3292 IWineD3DDevice *iface,
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3300 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3301 iface, srcData, start, count);
3303 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3305 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3306 for (i = 0; i < cnt; i++)
3307 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3308 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3310 for (i = start; i < cnt + start; ++i) {
3311 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3314 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3320 IWineD3DDevice *iface,
3325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 int cnt = min(count, MAX_CONST_I - start);
3328 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3329 iface, dstData, start, count);
3331 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3332 return WINED3DERR_INVALIDCALL;
3334 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3338 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3339 IWineD3DDevice *iface,
3341 CONST float *srcData,
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3348 iface, srcData, start, count);
3350 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3351 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3352 return WINED3DERR_INVALIDCALL;
3354 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3356 for (i = 0; i < count; i++)
3357 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3358 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3361 if (!This->isRecordingState)
3363 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3367 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3368 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3373 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3374 IWineD3DDevice *iface,
3379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 int cnt = min(count, This->d3d_vshader_constantF - start);
3382 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3383 iface, dstData, start, count);
3385 if (!dstData || cnt < 0)
3386 return WINED3DERR_INVALIDCALL;
3388 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3392 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3394 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3400 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3402 DWORD i = This->rev_tex_unit_map[unit];
3403 DWORD j = This->texUnitMap[stage];
3405 This->texUnitMap[stage] = unit;
3406 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3408 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3411 This->rev_tex_unit_map[unit] = stage;
3412 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3414 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3418 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3421 This->fixed_function_usage_map = 0;
3422 for (i = 0; i < MAX_TEXTURES; ++i)
3424 const struct wined3d_state *state = &This->stateBlock->state;
3425 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3426 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3427 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3428 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3429 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3430 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3431 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3432 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3434 if (color_op == WINED3DTOP_DISABLE) {
3435 /* Not used, and disable higher stages */
3439 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3440 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3441 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3442 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3443 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3444 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3445 This->fixed_function_usage_map |= (1 << i);
3448 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3449 This->fixed_function_usage_map |= (1 << (i + 1));
3454 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3456 unsigned int i, tex;
3459 device_update_fixed_function_usage_map(This);
3460 ffu_map = This->fixed_function_usage_map;
3462 if (This->max_ffp_textures == gl_info->limits.texture_stages
3463 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3465 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3467 if (!(ffu_map & 1)) continue;
3469 if (This->texUnitMap[i] != i) {
3470 device_map_stage(This, i, i);
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3472 markTextureStagesDirty(This, i);
3478 /* Now work out the mapping */
3480 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3482 if (!(ffu_map & 1)) continue;
3484 if (This->texUnitMap[i] != tex) {
3485 device_map_stage(This, i, tex);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3487 markTextureStagesDirty(This, i);
3494 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3496 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3497 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3500 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3501 if (sampler_type[i] && This->texUnitMap[i] != i)
3503 device_map_stage(This, i, i);
3504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3505 if (i < gl_info->limits.texture_stages)
3507 markTextureStagesDirty(This, i);
3513 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3514 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3516 DWORD current_mapping = This->rev_tex_unit_map[unit];
3518 /* Not currently used */
3519 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3521 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3522 /* Used by a fragment sampler */
3524 if (!pshader_sampler_tokens) {
3525 /* No pixel shader, check fixed function */
3526 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3529 /* Pixel shader, check the shader's sampler map */
3530 return !pshader_sampler_tokens[current_mapping];
3533 /* Used by a vertex sampler */
3534 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3537 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3539 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3540 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3541 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3542 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3547 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3549 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3550 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3551 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3554 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3555 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3556 if (vshader_sampler_type[i])
3558 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3560 /* Already mapped somewhere */
3564 while (start >= 0) {
3565 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3567 device_map_stage(This, vsampler_idx, start);
3568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3580 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3582 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3583 BOOL vs = use_vs(This->stateBlock);
3584 BOOL ps = use_ps(This->stateBlock);
3587 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3588 * that would be really messy and require shader recompilation
3589 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3590 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3592 if (ps) device_map_psamplers(This, gl_info);
3593 else device_map_fixed_function_samplers(This, gl_info);
3595 if (vs) device_map_vsamplers(This, ps, gl_info);
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3601 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3602 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3603 This->updateStateBlock->changed.pixelShader = TRUE;
3605 /* Handle recording of state blocks */
3606 if (This->isRecordingState) {
3607 TRACE("Recording... not performing anything\n");
3610 if (This->isRecordingState) {
3611 TRACE("Recording... not performing anything\n");
3612 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3613 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3617 if(pShader == oldShader) {
3618 TRACE("App is setting the old pixel shader over, nothing to do\n");
3622 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3623 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3625 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3631 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3633 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3634 IWineD3DPixelShader *shader;
3636 TRACE("iface %p.\n", iface);
3638 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3639 if (shader) IWineD3DPixelShader_AddRef(shader);
3641 TRACE("Returning %p.\n", shader);
3645 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3646 IWineD3DDevice *iface,
3648 CONST BOOL *srcData,
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3652 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3654 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3655 iface, srcData, start, count);
3657 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3659 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3660 for (i = 0; i < cnt; i++)
3661 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3663 for (i = start; i < cnt + start; ++i) {
3664 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3667 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3672 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3673 IWineD3DDevice *iface,
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int cnt = min(count, MAX_CONST_B - start);
3681 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3682 iface, dstData, start, count);
3684 if (!dstData || cnt < 0)
3685 return WINED3DERR_INVALIDCALL;
3687 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3691 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3692 IWineD3DDevice *iface,
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3700 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3701 iface, srcData, start, count);
3703 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3705 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3706 for (i = 0; i < cnt; i++)
3707 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3708 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3710 for (i = start; i < cnt + start; ++i) {
3711 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3714 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3719 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3720 IWineD3DDevice *iface,
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3726 int cnt = min(count, MAX_CONST_I - start);
3728 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3729 iface, dstData, start, count);
3731 if (!dstData || cnt < 0)
3732 return WINED3DERR_INVALIDCALL;
3734 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3739 IWineD3DDevice *iface,
3741 CONST float *srcData,
3744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3747 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3748 iface, srcData, start, count);
3750 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3751 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3752 return WINED3DERR_INVALIDCALL;
3754 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3756 for (i = 0; i < count; i++)
3757 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3758 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3761 if (!This->isRecordingState)
3763 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3767 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3768 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3773 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3774 IWineD3DDevice *iface,
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 int cnt = min(count, This->d3d_pshader_constantF - start);
3782 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3783 iface, dstData, start, count);
3785 if (!dstData || cnt < 0)
3786 return WINED3DERR_INVALIDCALL;
3788 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3792 /* Context activation is done by the caller. */
3793 /* Do not call while under the GL lock. */
3794 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3795 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3796 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3799 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3800 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3803 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3807 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3809 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3812 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3814 ERR("Source has no position mask\n");
3815 return WINED3DERR_INVALIDCALL;
3818 if (!dest->resource.allocatedMemory)
3819 buffer_get_sysmem(dest, gl_info);
3821 /* Get a pointer into the destination vbo(create one if none exists) and
3822 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3824 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3826 dest->flags |= WINED3D_BUFFER_CREATEBO;
3827 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3830 if (dest->buffer_object)
3832 unsigned char extrabytes = 0;
3833 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3834 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3835 * this may write 4 extra bytes beyond the area that should be written
3837 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3838 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3839 if(!dest_conv_addr) {
3840 ERR("Out of memory\n");
3841 /* Continue without storing converted vertices */
3843 dest_conv = dest_conv_addr;
3846 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3848 static BOOL warned = FALSE;
3850 * The clipping code is not quite correct. Some things need
3851 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3852 * so disable clipping for now.
3853 * (The graphics in Half-Life are broken, and my processvertices
3854 * test crashes with IDirect3DDevice3)
3860 FIXME("Clipping is broken and disabled for now\n");
3862 } else doClip = FALSE;
3863 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3865 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3868 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3869 WINED3DTS_PROJECTION,
3871 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3872 WINED3DTS_WORLDMATRIX(0),
3875 TRACE("View mat:\n");
3876 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);
3877 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);
3878 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);
3879 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);
3881 TRACE("Proj mat:\n");
3882 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);
3883 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);
3884 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);
3885 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);
3887 TRACE("World mat:\n");
3888 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);
3889 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);
3890 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);
3891 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);
3893 /* Get the viewport */
3894 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3895 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3896 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3898 multiply_matrix(&mat,&view_mat,&world_mat);
3899 multiply_matrix(&mat,&proj_mat,&mat);
3901 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3903 for (i = 0; i < dwCount; i+= 1) {
3904 unsigned int tex_index;
3906 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3907 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3908 /* The position first */
3909 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3910 const float *p = (const float *)(element->data + i * element->stride);
3912 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3914 /* Multiplication with world, view and projection matrix */
3915 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);
3916 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);
3917 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);
3918 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);
3920 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3922 /* WARNING: The following things are taken from d3d7 and were not yet checked
3923 * against d3d8 or d3d9!
3926 /* Clipping conditions: From msdn
3928 * A vertex is clipped if it does not match the following requirements
3932 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3934 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3935 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3940 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3941 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3944 /* "Normal" viewport transformation (not clipped)
3945 * 1) The values are divided by rhw
3946 * 2) The y axis is negative, so multiply it with -1
3947 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3948 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3949 * 4) Multiply x with Width/2 and add Width/2
3950 * 5) The same for the height
3951 * 6) Add the viewpoint X and Y to the 2D coordinates and
3952 * The minimum Z value to z
3953 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3955 * Well, basically it's simply a linear transformation into viewport
3967 z *= vp.MaxZ - vp.MinZ;
3969 x += vp.Width / 2 + vp.X;
3970 y += vp.Height / 2 + vp.Y;
3975 /* That vertex got clipped
3976 * Contrary to OpenGL it is not dropped completely, it just
3977 * undergoes a different calculation.
3979 TRACE("Vertex got clipped\n");
3986 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3987 * outside of the main vertex buffer memory. That needs some more
3992 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3995 ( (float *) dest_ptr)[0] = x;
3996 ( (float *) dest_ptr)[1] = y;
3997 ( (float *) dest_ptr)[2] = z;
3998 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4000 dest_ptr += 3 * sizeof(float);
4002 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4003 dest_ptr += sizeof(float);
4008 ( (float *) dest_conv)[0] = x * w;
4009 ( (float *) dest_conv)[1] = y * w;
4010 ( (float *) dest_conv)[2] = z * w;
4011 ( (float *) dest_conv)[3] = w;
4013 dest_conv += 3 * sizeof(float);
4015 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4016 dest_conv += sizeof(float);
4020 if (DestFVF & WINED3DFVF_PSIZE) {
4021 dest_ptr += sizeof(DWORD);
4022 if(dest_conv) dest_conv += sizeof(DWORD);
4024 if (DestFVF & WINED3DFVF_NORMAL) {
4025 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4026 const float *normal = (const float *)(element->data + i * element->stride);
4027 /* AFAIK this should go into the lighting information */
4028 FIXME("Didn't expect the destination to have a normal\n");
4029 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4031 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4035 if (DestFVF & WINED3DFVF_DIFFUSE) {
4036 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4037 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4038 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4040 static BOOL warned = FALSE;
4043 ERR("No diffuse color in source, but destination has one\n");
4047 *( (DWORD *) dest_ptr) = 0xffffffff;
4048 dest_ptr += sizeof(DWORD);
4051 *( (DWORD *) dest_conv) = 0xffffffff;
4052 dest_conv += sizeof(DWORD);
4056 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4058 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4059 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4060 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4061 dest_conv += sizeof(DWORD);
4066 if (DestFVF & WINED3DFVF_SPECULAR)
4068 /* What's the color value in the feedback buffer? */
4069 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4070 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4071 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4073 static BOOL warned = FALSE;
4076 ERR("No specular color in source, but destination has one\n");
4080 *( (DWORD *) dest_ptr) = 0xFF000000;
4081 dest_ptr += sizeof(DWORD);
4084 *( (DWORD *) dest_conv) = 0xFF000000;
4085 dest_conv += sizeof(DWORD);
4089 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4091 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4092 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4093 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4094 dest_conv += sizeof(DWORD);
4099 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4100 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4101 const float *tex_coord = (const float *)(element->data + i * element->stride);
4102 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4104 ERR("No source texture, but destination requests one\n");
4105 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4106 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4109 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4111 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4121 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4122 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4123 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4124 dwCount * get_flexible_vertex_size(DestFVF),
4126 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4130 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4135 #undef copy_and_next
4137 /* Do not call while under the GL lock. */
4138 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4139 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4143 struct wined3d_stream_info stream_info;
4144 const struct wined3d_gl_info *gl_info;
4145 struct wined3d_context *context;
4146 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4149 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4152 ERR("Output vertex declaration not implemented yet\n");
4155 /* Need any context to write to the vbo. */
4156 context = context_acquire(This, NULL);
4157 gl_info = context->gl_info;
4159 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4160 * control the streamIsUP flag, thus restore it afterwards.
4162 This->stateBlock->state.user_stream = FALSE;
4163 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4164 This->stateBlock->state.user_stream = streamWasUP;
4166 if(vbo || SrcStartIndex) {
4168 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4169 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4171 * Also get the start index in, but only loop over all elements if there's something to add at all.
4173 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4175 struct wined3d_stream_info_element *e;
4177 if (!(stream_info.use_map & (1 << i))) continue;
4179 e = &stream_info.elements[i];
4180 if (e->buffer_object)
4182 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4183 e->buffer_object = 0;
4184 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4186 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4187 vb->buffer_object = 0;
4190 if (e->data) e->data += e->stride * SrcStartIndex;
4194 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4195 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4197 context_release(context);
4203 * Get / Set Texture Stage States
4204 * TODO: Verify against dx9 definitions
4206 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4209 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4212 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4214 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4216 WARN("Invalid Type %d passed.\n", Type);
4220 if (Stage >= gl_info->limits.texture_stages)
4222 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4223 Stage, gl_info->limits.texture_stages - 1);
4227 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4228 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4229 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4231 if (This->isRecordingState) {
4232 TRACE("Recording... not performing anything\n");
4236 /* Checked after the assignments to allow proper stateblock recording */
4237 if(oldValue == Value) {
4238 TRACE("App is setting the old value over, nothing to do\n");
4242 if (Stage > This->stateBlock->state.lowest_disabled_stage
4243 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4244 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4246 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4247 * Changes in other states are important on disabled stages too
4252 if(Type == WINED3DTSS_COLOROP) {
4255 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4256 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4257 * they have to be disabled
4259 * The current stage is dirtified below.
4261 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4263 TRACE("Additionally dirtifying stage %u\n", i);
4264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4266 This->stateBlock->state.lowest_disabled_stage = Stage;
4267 TRACE("New lowest disabled: %u\n", Stage);
4268 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4269 /* Previously disabled stage enabled. Stages above it may need enabling
4270 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4271 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4273 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4276 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4278 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4280 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4283 This->stateBlock->state.lowest_disabled_stage = i;
4284 TRACE("New lowest disabled: %u\n", i);
4288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4293 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4297 TRACE("iface %p, stage %u, state %s, value %p.\n",
4298 iface, Stage, debug_d3dtexturestate(Type), pValue);
4300 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4302 WARN("Invalid Type %d passed.\n", Type);
4306 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4307 TRACE("Returning %#x.\n", *pValue);
4315 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4316 DWORD stage, IWineD3DBaseTexture *texture)
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4320 IWineD3DBaseTexture *prev;
4322 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4324 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4325 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4327 /* Windows accepts overflowing this array... we do not. */
4328 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4330 WARN("Ignoring invalid stage %u.\n", stage);
4334 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4335 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4337 WARN("Rejecting attempt to set scratch texture.\n");
4338 return WINED3DERR_INVALIDCALL;
4341 This->updateStateBlock->changed.textures |= 1 << stage;
4343 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4344 TRACE("Previous texture %p.\n", prev);
4346 if (texture == prev)
4348 TRACE("App is setting the same texture again, nothing to do.\n");
4352 TRACE("Setting new texture to %p.\n", texture);
4353 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4355 if (This->isRecordingState)
4357 TRACE("Recording... not performing anything\n");
4359 if (texture) IWineD3DBaseTexture_AddRef(texture);
4360 if (prev) IWineD3DBaseTexture_Release(prev);
4367 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4368 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4369 GLenum dimensions = t->baseTexture.target;
4371 IWineD3DBaseTexture_AddRef(texture);
4373 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4376 if (!prev && stage < gl_info->limits.texture_stages)
4378 /* The source arguments for color and alpha ops have different
4379 * meanings when a NULL texture is bound, so the COLOROP and
4380 * ALPHAOP have to be dirtified. */
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4385 if (bind_count == 1) t->baseTexture.sampler = stage;
4390 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4391 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4393 IWineD3DBaseTexture_Release(prev);
4395 if (!texture && stage < gl_info->limits.texture_stages)
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4401 if (bind_count && t->baseTexture.sampler == stage)
4405 /* Search for other stages the texture is bound to. Shouldn't
4406 * happen if applications bind textures to a single stage only. */
4407 TRACE("Searching for other stages the texture is bound to.\n");
4408 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4410 if (This->updateStateBlock->state.textures[i] == t)
4412 TRACE("Texture is also bound to stage %u.\n", i);
4413 t->baseTexture.sampler = i;
4420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4425 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4428 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4430 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4431 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4434 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4436 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4437 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4440 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4442 IWineD3DBaseTexture_AddRef(*ppTexture);
4444 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4452 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4453 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4455 IWineD3DSwapChain *swapchain;
4458 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4459 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4461 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4464 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4468 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4469 IWineD3DSwapChain_Release(swapchain);
4472 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4479 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4481 WARN("(%p) : stub, calling idirect3d for now\n", This);
4482 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4485 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 IWineD3DSwapChain *swapChain;
4490 if(iSwapChain > 0) {
4491 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4492 if (hr == WINED3D_OK) {
4493 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4494 IWineD3DSwapChain_Release(swapChain);
4496 FIXME("(%p) Error getting display mode\n", This);
4499 /* Don't read the real display mode,
4500 but return the stored mode instead. X11 can't change the color
4501 depth, and some apps are pretty angry if they SetDisplayMode from
4502 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4504 Also don't relay to the swapchain because with ddraw it's possible
4505 that there isn't a swapchain at all */
4506 pMode->Width = This->ddraw_width;
4507 pMode->Height = This->ddraw_height;
4508 pMode->Format = This->ddraw_format;
4509 pMode->RefreshRate = 0;
4517 * Stateblock related functions
4520 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 IWineD3DStateBlock *stateblock;
4525 TRACE("(%p)\n", This);
4527 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4529 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4530 if (FAILED(hr)) return hr;
4532 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4533 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4534 This->isRecordingState = TRUE;
4536 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4541 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4545 if (!This->isRecordingState) {
4546 WARN("(%p) not recording! returning error\n", This);
4547 *ppStateBlock = NULL;
4548 return WINED3DERR_INVALIDCALL;
4551 stateblock_init_contained_states(object);
4553 *ppStateBlock = (IWineD3DStateBlock*) object;
4554 This->isRecordingState = FALSE;
4555 This->updateStateBlock = This->stateBlock;
4556 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4557 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4558 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4563 * Scene related functions
4565 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4566 /* At the moment we have no need for any functionality at the beginning
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 TRACE("(%p)\n", This);
4572 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4573 return WINED3DERR_INVALIDCALL;
4575 This->inScene = TRUE;
4579 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 struct wined3d_context *context;
4584 TRACE("(%p)\n", This);
4586 if(!This->inScene) {
4587 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4588 return WINED3DERR_INVALIDCALL;
4591 context = context_acquire(This, NULL);
4592 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4594 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4596 context_release(context);
4598 This->inScene = FALSE;
4602 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4603 const RECT *pSourceRect, const RECT *pDestRect,
4604 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4606 IWineD3DSwapChain *swapChain = NULL;
4608 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4610 TRACE("iface %p.\n", iface);
4612 for(i = 0 ; i < swapchains ; i ++) {
4614 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4615 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4616 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4617 IWineD3DSwapChain_Release(swapChain);
4623 /* Do not call while under the GL lock. */
4624 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4625 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4627 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4628 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4631 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4632 iface, rect_count, rects, flags, color, depth, stencil);
4634 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4636 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4637 /* TODO: What about depth stencil buffers without stencil bits? */
4638 return WINED3DERR_INVALIDCALL;
4641 device_get_draw_rect(device, &draw_rect);
4643 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4644 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4651 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4652 WINED3DPRIMITIVETYPE primitive_type)
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4658 This->updateStateBlock->changed.primitive_type = TRUE;
4659 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4662 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4663 WINED3DPRIMITIVETYPE *primitive_type)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4667 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4669 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4671 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4674 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4680 if (!This->stateBlock->state.vertex_declaration)
4682 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4683 return WINED3DERR_INVALIDCALL;
4686 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4687 if (This->stateBlock->state.user_stream)
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4690 This->stateBlock->state.user_stream = FALSE;
4693 if (This->stateBlock->state.load_base_vertex_index)
4695 This->stateBlock->state.load_base_vertex_index = 0;
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4698 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4699 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4703 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 struct wined3d_buffer *index_buffer;
4710 index_buffer = This->stateBlock->state.index_buffer;
4713 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4714 * without an index buffer set. (The first time at least...)
4715 * D3D8 simply dies, but I doubt it can do much harm to return
4716 * D3DERR_INVALIDCALL there as well. */
4717 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4718 return WINED3DERR_INVALIDCALL;
4721 if (!This->stateBlock->state.vertex_declaration)
4723 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4724 return WINED3DERR_INVALIDCALL;
4727 if (This->stateBlock->state.user_stream)
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4730 This->stateBlock->state.user_stream = FALSE;
4732 vbo = index_buffer->buffer_object;
4734 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4736 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4741 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4743 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4747 drawPrimitive(iface, index_count, startIndex, idxStride,
4748 vbo ? NULL : index_buffer->resource.allocatedMemory);
4753 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4754 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 struct wined3d_stream_state *stream;
4760 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4761 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4763 if (!This->stateBlock->state.vertex_declaration)
4765 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4766 return WINED3DERR_INVALIDCALL;
4769 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4770 stream = &This->stateBlock->state.streams[0];
4771 vb = (IWineD3DBuffer *)stream->buffer;
4772 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4773 if (vb) IWineD3DBuffer_Release(vb);
4775 stream->stride = VertexStreamZeroStride;
4776 This->stateBlock->state.user_stream = TRUE;
4777 This->stateBlock->state.load_base_vertex_index = 0;
4779 /* TODO: Only mark dirty if drawing from a different UP address */
4780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4782 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4784 /* MSDN specifies stream zero settings must be set to NULL */
4785 stream->buffer = NULL;
4788 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4789 * the new stream sources or use UP drawing again
4794 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4795 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4796 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 struct wined3d_stream_state *stream;
4804 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4805 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4807 if (!This->stateBlock->state.vertex_declaration)
4809 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4810 return WINED3DERR_INVALIDCALL;
4813 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4819 stream = &This->stateBlock->state.streams[0];
4820 vb = (IWineD3DBuffer *)stream->buffer;
4821 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4822 if (vb) IWineD3DBuffer_Release(vb);
4824 stream->stride = VertexStreamZeroStride;
4825 This->stateBlock->state.user_stream = TRUE;
4827 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4828 This->stateBlock->state.base_vertex_index = 0;
4829 This->stateBlock->state.load_base_vertex_index = 0;
4830 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4834 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4836 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4837 stream->buffer = NULL;
4839 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4842 IWineD3DBuffer_Release(ib);
4843 This->stateBlock->state.index_buffer = NULL;
4845 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4846 * SetStreamSource to specify a vertex buffer
4852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4853 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4857 /* Mark the state dirty until we have nicer tracking
4858 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4863 This->stateBlock->state.base_vertex_index = 0;
4864 This->up_strided = DrawPrimStrideData;
4865 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4866 This->up_strided = NULL;
4870 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4871 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4872 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4875 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4877 /* Mark the state dirty until we have nicer tracking
4878 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4883 This->stateBlock->state.user_stream = TRUE;
4884 This->stateBlock->state.base_vertex_index = 0;
4885 This->up_strided = DrawPrimStrideData;
4886 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4887 This->up_strided = NULL;
4891 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4892 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4893 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4895 WINED3DLOCKED_BOX src;
4896 WINED3DLOCKED_BOX dst;
4899 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4900 iface, pSourceVolume, pDestinationVolume);
4902 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4903 * dirtification to improve loading performance.
4905 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4906 if(FAILED(hr)) return hr;
4907 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4909 IWineD3DVolume_UnlockBox(pSourceVolume);
4913 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4915 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4917 IWineD3DVolume_UnlockBox(pSourceVolume);
4919 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4924 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4925 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4927 unsigned int level_count, i;
4928 WINED3DRESOURCETYPE type;
4931 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4933 /* Verify that the source and destination textures are non-NULL. */
4934 if (!src_texture || !dst_texture)
4936 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4937 return WINED3DERR_INVALIDCALL;
4940 if (src_texture == dst_texture)
4942 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4943 return WINED3DERR_INVALIDCALL;
4946 /* Verify that the source and destination textures are the same type. */
4947 type = IWineD3DBaseTexture_GetType(src_texture);
4948 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4950 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4951 return WINED3DERR_INVALIDCALL;
4954 /* Check that both textures have the identical numbers of levels. */
4955 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4956 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4958 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4959 return WINED3DERR_INVALIDCALL;
4962 /* Make sure that the destination texture is loaded. */
4963 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4965 /* Update every surface level of the texture. */
4968 case WINED3DRTYPE_TEXTURE:
4970 IWineD3DSurface *src_surface;
4971 IWineD3DSurface *dst_surface;
4973 for (i = 0; i < level_count; ++i)
4975 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4976 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4977 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4978 IWineD3DSurface_Release(dst_surface);
4979 IWineD3DSurface_Release(src_surface);
4982 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4989 case WINED3DRTYPE_CUBETEXTURE:
4991 IWineD3DSurface *src_surface;
4992 IWineD3DSurface *dst_surface;
4993 WINED3DCUBEMAP_FACES face;
4995 for (i = 0; i < level_count; ++i)
4997 /* Update each cube face. */
4998 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5000 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5001 face, i, &src_surface);
5002 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5003 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5004 face, i, &dst_surface);
5005 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5006 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5007 IWineD3DSurface_Release(dst_surface);
5008 IWineD3DSurface_Release(src_surface);
5011 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5019 case WINED3DRTYPE_VOLUMETEXTURE:
5021 IWineD3DVolume *src_volume;
5022 IWineD3DVolume *dst_volume;
5024 for (i = 0; i < level_count; ++i)
5026 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5027 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5028 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5029 IWineD3DVolume_Release(dst_volume);
5030 IWineD3DVolume_Release(src_volume);
5033 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5041 FIXME("Unsupported texture type %#x.\n", type);
5042 return WINED3DERR_INVALIDCALL;
5048 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5049 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5051 IWineD3DSwapChain *swapchain;
5054 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5056 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5057 if (FAILED(hr)) return hr;
5059 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5060 IWineD3DSwapChain_Release(swapchain);
5065 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 IWineD3DBaseTextureImpl *texture;
5070 TRACE("(%p) : %p\n", This, pNumPasses);
5072 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5074 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5076 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5077 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5079 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5081 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5082 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5085 texture = This->stateBlock->state.textures[i];
5086 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5088 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5090 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5093 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5095 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5098 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5099 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5101 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5106 /* return a sensible default */
5109 TRACE("returning D3D_OK\n");
5113 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5117 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5119 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5120 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5121 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5123 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5128 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5132 PALETTEENTRY **palettes;
5134 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5136 if (PaletteNumber >= MAX_PALETTES) {
5137 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5138 return WINED3DERR_INVALIDCALL;
5141 if (PaletteNumber >= This->NumberOfPalettes) {
5142 NewSize = This->NumberOfPalettes;
5145 } while(PaletteNumber >= NewSize);
5146 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5148 ERR("Out of memory!\n");
5149 return E_OUTOFMEMORY;
5151 This->palettes = palettes;
5152 This->NumberOfPalettes = NewSize;
5155 if (!This->palettes[PaletteNumber]) {
5156 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5157 if (!This->palettes[PaletteNumber]) {
5158 ERR("Out of memory!\n");
5159 return E_OUTOFMEMORY;
5163 for (j = 0; j < 256; ++j) {
5164 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5165 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5166 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5167 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5169 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5170 TRACE("(%p) : returning\n", This);
5174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5177 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5178 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5179 /* What happens in such situation isn't documented; Native seems to silently abort
5180 on such conditions. Return Invalid Call. */
5181 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5182 return WINED3DERR_INVALIDCALL;
5184 for (j = 0; j < 256; ++j) {
5185 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5186 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5187 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5188 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5190 TRACE("(%p) : returning\n", This);
5194 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5197 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5198 (tested with reference rasterizer). Return Invalid Call. */
5199 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5200 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5201 return WINED3DERR_INVALIDCALL;
5203 /*TODO: stateblocks */
5204 if (This->currentPalette != PaletteNumber) {
5205 This->currentPalette = PaletteNumber;
5206 dirtify_p8_texture_samplers(This);
5208 TRACE("(%p) : returning\n", This);
5212 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5217 WARN("(%p) : returning Invalid Call\n", This);
5218 return WINED3DERR_INVALIDCALL;
5220 /*TODO: stateblocks */
5221 *PaletteNumber = This->currentPalette;
5222 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5226 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5231 FIXME("(%p) : stub\n", This);
5235 This->softwareVertexProcessing = bSoftware;
5240 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 FIXME("(%p) : stub\n", This);
5248 return This->softwareVertexProcessing;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5252 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5254 IWineD3DSwapChain *swapchain;
5257 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5258 iface, swapchain_idx, raster_status);
5260 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5263 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5267 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5268 IWineD3DSwapChain_Release(swapchain);
5271 WARN("Failed to get raster status, hr %#x.\n", hr);
5278 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5281 if(nSegments != 0.0f) {
5284 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5291 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5296 FIXME("iface %p stub!\n", iface);
5302 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5303 IWineD3DSurface *src_surface, const RECT *src_rect,
5304 IWineD3DSurface *dst_surface, const POINT *dst_point)
5306 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5307 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 const struct wined3d_format *src_format;
5310 const struct wined3d_format *dst_format;
5311 const struct wined3d_gl_info *gl_info;
5312 struct wined3d_context *context;
5313 const unsigned char *data;
5314 UINT update_w, update_h;
5315 CONVERT_TYPES convert;
5319 struct wined3d_format format;
5321 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5322 iface, src_surface, wine_dbgstr_rect(src_rect),
5323 dst_surface, wine_dbgstr_point(dst_point));
5325 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5327 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5328 src_surface, dst_surface);
5329 return WINED3DERR_INVALIDCALL;
5332 src_format = src_impl->resource.format;
5333 dst_format = dst_impl->resource.format;
5335 if (src_format->id != dst_format->id)
5337 WARN("Source and destination surfaces should have the same format.\n");
5338 return WINED3DERR_INVALIDCALL;
5341 dst_x = dst_point ? dst_point->x : 0;
5342 dst_y = dst_point ? dst_point->y : 0;
5344 /* This call loads the OpenGL surface directly, instead of copying the
5345 * surface to the destination's sysmem copy. If surface conversion is
5346 * needed, use BltFast instead to copy in sysmem and use regular surface
5348 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5349 if (convert != NO_CONVERSION || format.convert)
5350 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5352 context = context_acquire(This, NULL);
5353 gl_info = context->gl_info;
5356 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5357 checkGLcall("glActiveTextureARB");
5360 /* Make sure the surface is loaded and up to date */
5361 surface_internal_preload(dst_impl, SRGB_RGB);
5362 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5364 src_w = src_impl->currentDesc.Width;
5365 src_h = src_impl->currentDesc.Height;
5366 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5367 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5369 data = IWineD3DSurface_GetData(src_surface);
5370 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5374 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5376 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5377 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5378 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5382 data += (src_rect->top / src_format->block_height) * src_pitch;
5383 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5386 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5387 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5388 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5390 if (row_length == src_pitch)
5392 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5393 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5399 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5400 * can't use the unpack row length like below. */
5401 for (row = 0, y = dst_y; row < row_count; ++row)
5403 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5404 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5405 y += src_format->block_height;
5409 checkGLcall("glCompressedTexSubImage2DARB");
5415 data += src_rect->top * src_w * src_format->byte_count;
5416 data += src_rect->left * src_format->byte_count;
5419 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5420 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5421 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5423 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5424 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5425 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5426 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5427 checkGLcall("glTexSubImage2D");
5431 context_release(context);
5433 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5434 sampler = This->rev_tex_unit_map[0];
5435 if (sampler != WINED3D_UNMAPPED_STAGE)
5437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5443 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5445 struct WineD3DRectPatch *patch;
5446 GLenum old_primitive_type;
5450 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5452 if(!(Handle || pRectPatchInfo)) {
5453 /* TODO: Write a test for the return value, thus the FIXME */
5454 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5455 return WINED3DERR_INVALIDCALL;
5459 i = PATCHMAP_HASHFUNC(Handle);
5461 LIST_FOR_EACH(e, &This->patches[i]) {
5462 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5463 if(patch->Handle == Handle) {
5470 TRACE("Patch does not exist. Creating a new one\n");
5471 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5472 patch->Handle = Handle;
5473 list_add_head(&This->patches[i], &patch->entry);
5475 TRACE("Found existing patch %p\n", patch);
5478 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5479 * attributes we have to tesselate, read back, and draw. This needs a patch
5480 * management structure instance. Create one.
5482 * A possible improvement is to check if a vertex shader is used, and if not directly
5485 FIXME("Drawing an uncached patch. This is slow\n");
5486 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5489 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5490 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5491 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5494 TRACE("Tesselation density or patch info changed, retesselating\n");
5496 if(pRectPatchInfo) {
5497 patch->RectPatchInfo = *pRectPatchInfo;
5499 patch->numSegs[0] = pNumSegs[0];
5500 patch->numSegs[1] = pNumSegs[1];
5501 patch->numSegs[2] = pNumSegs[2];
5502 patch->numSegs[3] = pNumSegs[3];
5504 hr = tesselate_rectpatch(This, patch);
5506 WARN("Patch tesselation failed\n");
5508 /* Do not release the handle to store the params of the patch */
5510 HeapFree(GetProcessHeap(), 0, patch);
5516 This->currentPatch = patch;
5517 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5518 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5519 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5520 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5521 This->currentPatch = NULL;
5523 /* Destroy uncached patches */
5525 HeapFree(GetProcessHeap(), 0, patch->mem);
5526 HeapFree(GetProcessHeap(), 0, patch);
5531 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5532 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5534 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5535 iface, handle, segment_count, patch_info);
5540 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5543 struct WineD3DRectPatch *patch;
5545 TRACE("(%p) Handle(%d)\n", This, Handle);
5547 i = PATCHMAP_HASHFUNC(Handle);
5548 LIST_FOR_EACH(e, &This->patches[i]) {
5549 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5550 if(patch->Handle == Handle) {
5551 TRACE("Deleting patch %p\n", patch);
5552 list_remove(&patch->entry);
5553 HeapFree(GetProcessHeap(), 0, patch->mem);
5554 HeapFree(GetProcessHeap(), 0, patch);
5559 /* TODO: Write a test for the return value */
5560 FIXME("Attempt to destroy nonexistent patch\n");
5561 return WINED3DERR_INVALIDCALL;
5564 /* Do not call while under the GL lock. */
5565 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5566 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5568 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5570 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5571 iface, surface, wine_dbgstr_rect(rect),
5572 color->r, color->g, color->b, color->a);
5574 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5576 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5577 return WINED3DERR_INVALIDCALL;
5580 return surface_color_fill(s, rect, color);
5583 /* Do not call while under the GL lock. */
5584 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5585 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5587 IWineD3DResource *resource;
5590 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5593 ERR("Failed to get resource, hr %#x\n", hr);
5597 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5599 FIXME("Only supported on surface resources\n");
5600 IWineD3DResource_Release(resource);
5604 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5605 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5607 IWineD3DResource_Release(resource);
5610 /* rendertarget and depth stencil functions */
5611 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5612 DWORD render_target_idx, IWineD3DSurface **render_target)
5614 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5616 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5617 iface, render_target_idx, render_target);
5619 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5621 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5622 return WINED3DERR_INVALIDCALL;
5625 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5626 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5628 TRACE("Returning render target %p.\n", *render_target);
5633 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5634 IWineD3DSurface *front, IWineD3DSurface *back)
5636 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5637 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5638 IWineD3DSwapChainImpl *swapchain;
5641 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5643 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5645 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5649 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5651 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5652 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5653 return WINED3DERR_INVALIDCALL;
5658 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5660 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5661 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5662 return WINED3DERR_INVALIDCALL;
5665 if (!swapchain->back_buffers)
5667 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5668 if (!swapchain->back_buffers)
5670 ERR("Failed to allocate back buffer array memory.\n");
5671 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5672 return E_OUTOFMEMORY;
5677 if (swapchain->front_buffer != front_impl)
5679 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5681 if (swapchain->front_buffer)
5682 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5683 swapchain->front_buffer = front_impl;
5686 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5689 if (swapchain->back_buffers[0] != back_impl)
5691 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5693 if (swapchain->back_buffers[0])
5694 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5695 swapchain->back_buffers[0] = back_impl;
5699 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5700 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5701 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5702 swapchain->presentParms.BackBufferCount = 1;
5704 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5708 swapchain->presentParms.BackBufferCount = 0;
5709 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5710 swapchain->back_buffers = NULL;
5714 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5718 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5720 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5722 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5724 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5725 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5726 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5727 IWineD3DSurface_AddRef(*depth_stencil);
5732 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5733 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5735 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5736 IWineD3DSurfaceImpl *prev;
5738 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5739 iface, render_target_idx, render_target, set_viewport);
5741 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5743 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5744 return WINED3DERR_INVALIDCALL;
5747 prev = device->render_targets[render_target_idx];
5748 if (render_target == (IWineD3DSurface *)prev)
5750 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5754 /* Render target 0 can't be set to NULL. */
5755 if (!render_target && !render_target_idx)
5757 WARN("Trying to set render target 0 to NULL.\n");
5758 return WINED3DERR_INVALIDCALL;
5761 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5763 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5764 return WINED3DERR_INVALIDCALL;
5767 if (render_target) IWineD3DSurface_AddRef(render_target);
5768 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5769 /* Release after the assignment, to prevent device_resource_released()
5770 * from seeing the surface as still in use. */
5771 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5773 /* Render target 0 is special. */
5774 if (!render_target_idx && set_viewport)
5776 /* Set the viewport and scissor rectangles, if requested. Tests show
5777 * that stateblock recording is ignored, the change goes directly
5778 * into the primary stateblock. */
5779 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5780 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5781 device->stateBlock->state.viewport.X = 0;
5782 device->stateBlock->state.viewport.Y = 0;
5783 device->stateBlock->state.viewport.MaxZ = 1.0f;
5784 device->stateBlock->state.viewport.MinZ = 0.0f;
5785 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5787 device->stateBlock->state.scissor_rect.top = 0;
5788 device->stateBlock->state.scissor_rect.left = 0;
5789 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5790 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5791 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5797 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 IWineD3DSurfaceImpl *tmp;
5802 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5804 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5806 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5810 if (This->depth_stencil)
5812 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5813 || This->depth_stencil->Flags & SFLAG_DISCARD)
5815 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5816 This->depth_stencil->currentDesc.Width,
5817 This->depth_stencil->currentDesc.Height);
5818 if (This->depth_stencil == This->onscreen_depth_stencil)
5820 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5821 This->onscreen_depth_stencil = NULL;
5826 tmp = This->depth_stencil;
5827 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5828 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5829 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5831 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5833 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5842 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5843 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5846 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5847 WINED3DLOCKED_RECT lockedRect;
5849 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5850 iface, XHotSpot, YHotSpot, cursor_image);
5852 /* some basic validation checks */
5853 if (This->cursorTexture)
5855 struct wined3d_context *context = context_acquire(This, NULL);
5857 glDeleteTextures(1, &This->cursorTexture);
5859 context_release(context);
5860 This->cursorTexture = 0;
5863 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5864 This->haveHardwareCursor = TRUE;
5866 This->haveHardwareCursor = FALSE;
5870 WINED3DLOCKED_RECT rect;
5872 /* MSDN: Cursor must be A8R8G8B8 */
5873 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5875 WARN("surface %p has an invalid format.\n", cursor_image);
5876 return WINED3DERR_INVALIDCALL;
5879 /* MSDN: Cursor must be smaller than the display mode */
5880 if (s->currentDesc.Width > This->ddraw_width
5881 || s->currentDesc.Height > This->ddraw_height)
5883 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5884 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5885 return WINED3DERR_INVALIDCALL;
5888 if (!This->haveHardwareCursor) {
5889 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5891 /* Do not store the surface's pointer because the application may
5892 * release it after setting the cursor image. Windows doesn't
5893 * addref the set surface, so we can't do this either without
5894 * creating circular refcount dependencies. Copy out the gl texture
5897 This->cursorWidth = s->currentDesc.Width;
5898 This->cursorHeight = s->currentDesc.Height;
5899 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5901 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5902 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5903 struct wined3d_context *context;
5904 char *mem, *bits = rect.pBits;
5905 GLint intfmt = format->glInternal;
5906 GLint gl_format = format->glFormat;
5907 GLint type = format->glType;
5908 INT height = This->cursorHeight;
5909 INT width = This->cursorWidth;
5910 INT bpp = format->byte_count;
5914 /* Reformat the texture memory (pitch and width can be
5916 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5917 for(i = 0; i < height; i++)
5918 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5919 IWineD3DSurface_UnlockRect(cursor_image);
5921 context = context_acquire(This, NULL);
5925 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5927 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5928 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5931 /* Make sure that a proper texture unit is selected */
5932 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5933 checkGLcall("glActiveTextureARB");
5934 sampler = This->rev_tex_unit_map[0];
5935 if (sampler != WINED3D_UNMAPPED_STAGE)
5937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5939 /* Create a new cursor texture */
5940 glGenTextures(1, &This->cursorTexture);
5941 checkGLcall("glGenTextures");
5942 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5943 checkGLcall("glBindTexture");
5944 /* Copy the bitmap memory into the cursor texture */
5945 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5946 HeapFree(GetProcessHeap(), 0, mem);
5947 checkGLcall("glTexImage2D");
5949 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5951 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5952 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5957 context_release(context);
5961 FIXME("A cursor texture was not returned.\n");
5962 This->cursorTexture = 0;
5967 /* Draw a hardware cursor */
5968 ICONINFO cursorInfo;
5970 /* Create and clear maskBits because it is not needed for
5971 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5973 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5974 (s->currentDesc.Width * s->currentDesc.Height / 8));
5975 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5976 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5977 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5979 cursorInfo.fIcon = FALSE;
5980 cursorInfo.xHotspot = XHotSpot;
5981 cursorInfo.yHotspot = YHotSpot;
5982 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5983 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5984 IWineD3DSurface_UnlockRect(cursor_image);
5985 /* Create our cursor and clean up. */
5986 cursor = CreateIconIndirect(&cursorInfo);
5988 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5989 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5990 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5991 This->hardwareCursor = cursor;
5992 HeapFree(GetProcessHeap(), 0, maskBits);
5996 This->xHotSpot = XHotSpot;
5997 This->yHotSpot = YHotSpot;
6001 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6003 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6005 This->xScreenSpace = XScreenSpace;
6006 This->yScreenSpace = YScreenSpace;
6012 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6014 BOOL oldVisible = This->bCursorVisible;
6017 TRACE("(%p) : visible(%d)\n", This, bShow);
6020 * When ShowCursor is first called it should make the cursor appear at the OS's last
6021 * known cursor position. Because of this, some applications just repetitively call
6022 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6025 This->xScreenSpace = pt.x;
6026 This->yScreenSpace = pt.y;
6028 if (This->haveHardwareCursor) {
6029 This->bCursorVisible = bShow;
6031 SetCursor(This->hardwareCursor);
6037 if (This->cursorTexture)
6038 This->bCursorVisible = bShow;
6044 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6045 TRACE("checking resource %p for eviction\n", resource);
6046 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6047 TRACE("Evicting %p\n", resource);
6048 IWineD3DResource_UnLoad(resource);
6050 IWineD3DResource_Release(resource);
6054 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6056 TRACE("iface %p.\n", iface);
6058 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6059 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6060 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6065 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6067 IWineD3DDeviceImpl *device = surface->resource.device;
6068 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6070 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6071 if(surface->Flags & SFLAG_DIBSECTION) {
6072 /* Release the DC */
6073 SelectObject(surface->hDC, surface->dib.holdbitmap);
6074 DeleteDC(surface->hDC);
6075 /* Release the DIB section */
6076 DeleteObject(surface->dib.DIBsection);
6077 surface->dib.bitmap_data = NULL;
6078 surface->resource.allocatedMemory = NULL;
6079 surface->Flags &= ~SFLAG_DIBSECTION;
6081 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6082 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6083 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6084 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6086 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6087 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6089 surface->pow2Width = surface->pow2Height = 1;
6090 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6091 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6094 if (surface->texture_name)
6096 struct wined3d_context *context = context_acquire(device, NULL);
6098 glDeleteTextures(1, &surface->texture_name);
6100 context_release(context);
6101 surface->texture_name = 0;
6102 surface->Flags &= ~SFLAG_CLIENT;
6104 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6105 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6106 surface->Flags |= SFLAG_NONPOW2;
6108 surface->Flags &= ~SFLAG_NONPOW2;
6110 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6111 surface->resource.allocatedMemory = NULL;
6112 surface->resource.heapMemory = NULL;
6113 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6115 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6117 if (!surface_init_sysmem(surface))
6119 return E_OUTOFMEMORY;
6124 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6125 TRACE("Unloading resource %p\n", resource);
6126 IWineD3DResource_UnLoad(resource);
6127 IWineD3DResource_Release(resource);
6131 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6134 WINED3DDISPLAYMODE m;
6137 /* All Windowed modes are supported, as is leaving the current mode */
6138 if(pp->Windowed) return TRUE;
6139 if(!pp->BackBufferWidth) return TRUE;
6140 if(!pp->BackBufferHeight) return TRUE;
6142 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6143 for(i = 0; i < count; i++) {
6144 memset(&m, 0, sizeof(m));
6145 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6147 ERR("EnumAdapterModes failed\n");
6149 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6150 /* Mode found, it is supported */
6154 /* Mode not found -> not supported */
6158 /* Do not call while under the GL lock. */
6159 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6162 const struct wined3d_gl_info *gl_info;
6163 struct wined3d_context *context;
6164 IWineD3DBaseShaderImpl *shader;
6166 context = context_acquire(This, NULL);
6167 gl_info = context->gl_info;
6169 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6170 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6171 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6175 if(This->depth_blt_texture) {
6176 glDeleteTextures(1, &This->depth_blt_texture);
6177 This->depth_blt_texture = 0;
6179 if (This->depth_blt_rb) {
6180 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6181 This->depth_blt_rb = 0;
6182 This->depth_blt_rb_w = 0;
6183 This->depth_blt_rb_h = 0;
6187 This->blitter->free_private(iface);
6188 This->frag_pipe->free_private(iface);
6189 This->shader_backend->shader_free_private(iface);
6190 destroy_dummy_textures(This, gl_info);
6192 context_release(context);
6194 while (This->numContexts)
6196 context_destroy(This, This->contexts[0]);
6198 HeapFree(GetProcessHeap(), 0, swapchain->context);
6199 swapchain->context = NULL;
6200 swapchain->num_contexts = 0;
6203 /* Do not call while under the GL lock. */
6204 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6207 struct wined3d_context *context;
6209 IWineD3DSurfaceImpl *target;
6211 /* Recreate the primary swapchain's context */
6212 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6213 if (!swapchain->context)
6215 ERR("Failed to allocate memory for swapchain context array.\n");
6216 return E_OUTOFMEMORY;
6219 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6220 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6222 WARN("Failed to create context.\n");
6223 HeapFree(GetProcessHeap(), 0, swapchain->context);
6227 swapchain->context[0] = context;
6228 swapchain->num_contexts = 1;
6229 create_dummy_textures(This);
6230 context_release(context);
6232 hr = This->shader_backend->shader_alloc_private(iface);
6235 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6239 hr = This->frag_pipe->alloc_private(iface);
6242 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6243 This->shader_backend->shader_free_private(iface);
6247 hr = This->blitter->alloc_private(iface);
6250 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6251 This->frag_pipe->free_private(iface);
6252 This->shader_backend->shader_free_private(iface);
6259 context_acquire(This, NULL);
6260 destroy_dummy_textures(This, context->gl_info);
6261 context_release(context);
6262 context_destroy(This, context);
6263 HeapFree(GetProcessHeap(), 0, swapchain->context);
6264 swapchain->num_contexts = 0;
6268 /* Do not call while under the GL lock. */
6269 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6270 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6273 IWineD3DSwapChainImpl *swapchain;
6275 BOOL DisplayModeChanged = FALSE;
6276 WINED3DDISPLAYMODE mode;
6277 TRACE("(%p)\n", This);
6279 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6281 ERR("Failed to get the first implicit swapchain\n");
6285 if(!is_display_mode_supported(This, pPresentationParameters)) {
6286 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6287 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6288 pPresentationParameters->BackBufferHeight);
6289 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6290 return WINED3DERR_INVALIDCALL;
6293 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6294 * on an existing gl context, so there's no real need for recreation.
6296 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6298 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6300 TRACE("New params:\n");
6301 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6302 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6303 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6304 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6305 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6306 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6307 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6308 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6309 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6310 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6311 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6312 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6313 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6315 /* No special treatment of these parameters. Just store them */
6316 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6317 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6318 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6319 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6321 /* What to do about these? */
6322 if (pPresentationParameters->BackBufferCount
6323 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6324 ERR("Cannot change the back buffer count yet\n");
6326 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6327 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6328 ERR("Cannot change the back buffer format yet\n");
6331 if (pPresentationParameters->hDeviceWindow
6332 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6333 ERR("Cannot change the device window yet\n");
6335 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6339 TRACE("Creating the depth stencil buffer\n");
6341 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6342 pPresentationParameters->BackBufferWidth,
6343 pPresentationParameters->BackBufferHeight,
6344 pPresentationParameters->AutoDepthStencilFormat,
6345 pPresentationParameters->MultiSampleType,
6346 pPresentationParameters->MultiSampleQuality,
6348 (IWineD3DSurface **)&This->auto_depth_stencil);
6351 ERR("Failed to create the depth stencil buffer\n");
6352 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6353 return WINED3DERR_INVALIDCALL;
6357 if (This->onscreen_depth_stencil)
6359 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6360 This->onscreen_depth_stencil = NULL;
6363 /* Reset the depth stencil */
6364 if (pPresentationParameters->EnableAutoDepthStencil)
6365 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6367 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6369 TRACE("Resetting stateblock\n");
6370 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6371 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6373 delete_opengl_contexts(iface, swapchain);
6375 if(pPresentationParameters->Windowed) {
6376 mode.Width = swapchain->orig_width;
6377 mode.Height = swapchain->orig_height;
6378 mode.RefreshRate = 0;
6379 mode.Format = swapchain->presentParms.BackBufferFormat;
6381 mode.Width = pPresentationParameters->BackBufferWidth;
6382 mode.Height = pPresentationParameters->BackBufferHeight;
6383 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6384 mode.Format = swapchain->presentParms.BackBufferFormat;
6387 /* Should Width == 800 && Height == 0 set 800x600? */
6388 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6389 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6390 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6394 if(!pPresentationParameters->Windowed) {
6395 DisplayModeChanged = TRUE;
6397 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6398 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6400 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6403 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6407 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6409 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6412 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6416 if (This->auto_depth_stencil)
6418 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6421 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6427 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6428 || DisplayModeChanged)
6430 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6432 if (!pPresentationParameters->Windowed)
6434 if(swapchain->presentParms.Windowed) {
6435 /* switch from windowed to fs */
6436 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6437 pPresentationParameters->BackBufferHeight);
6439 /* Fullscreen -> fullscreen mode change */
6440 MoveWindow(swapchain->device_window, 0, 0,
6441 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6445 else if (!swapchain->presentParms.Windowed)
6447 /* Fullscreen -> windowed switch */
6448 swapchain_restore_fullscreen_window(swapchain);
6450 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6451 } else if(!pPresentationParameters->Windowed) {
6452 DWORD style = This->style, exStyle = This->exStyle;
6453 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6454 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6455 * Reset to clear up their mess. Guild Wars also loses the device during that.
6459 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6460 pPresentationParameters->BackBufferHeight);
6461 This->style = style;
6462 This->exStyle = exStyle;
6465 /* Note: No parent needed for initial internal stateblock */
6466 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6467 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6468 else TRACE("Created stateblock %p\n", This->stateBlock);
6469 This->updateStateBlock = This->stateBlock;
6470 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6472 stateblock_init_default_state(This->stateBlock);
6474 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6477 GetClientRect(swapchain->win_handle, &client_rect);
6479 if(!swapchain->presentParms.BackBufferCount)
6481 TRACE("Single buffered rendering\n");
6482 swapchain->render_to_fbo = FALSE;
6484 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6485 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6487 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6488 swapchain->presentParms.BackBufferWidth,
6489 swapchain->presentParms.BackBufferHeight,
6490 client_rect.right, client_rect.bottom);
6491 swapchain->render_to_fbo = TRUE;
6495 TRACE("Rendering directly to GL_BACK\n");
6496 swapchain->render_to_fbo = FALSE;
6500 hr = create_primary_opengl_context(iface, swapchain);
6501 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6503 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6509 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6511 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6513 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6519 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6521 TRACE("(%p) : pParameters %p\n", This, pParameters);
6523 *pParameters = This->createParms;
6527 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6528 IWineD3DSwapChain *swapchain;
6530 TRACE("Relaying to swapchain\n");
6532 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6533 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6534 IWineD3DSwapChain_Release(swapchain);
6538 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6539 IWineD3DSwapChain *swapchain;
6541 TRACE("Relaying to swapchain\n");
6543 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6544 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6545 IWineD3DSwapChain_Release(swapchain);
6550 /** ********************************************************
6551 * Notification functions
6552 ** ********************************************************/
6553 /** This function must be called in the release of a resource when ref == 0,
6554 * the contents of resource must still be correct,
6555 * any handles to other resource held by the caller must be closed
6556 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6557 *****************************************************/
6558 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6560 TRACE("(%p) : Adding resource %p\n", This, resource);
6562 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6565 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6567 TRACE("(%p) : Removing resource %p\n", This, resource);
6569 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6572 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6574 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6577 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6579 context_resource_released(device, resource, type);
6583 case WINED3DRTYPE_SURFACE:
6584 if (!device->d3d_initialized) break;
6586 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6588 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6590 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6591 device->render_targets[i] = NULL;
6595 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6597 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6598 device->depth_stencil = NULL;
6602 case WINED3DRTYPE_TEXTURE:
6603 case WINED3DRTYPE_CUBETEXTURE:
6604 case WINED3DRTYPE_VOLUMETEXTURE:
6605 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6607 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6609 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6610 resource, device->stateBlock, i);
6611 device->stateBlock->state.textures[i] = NULL;
6614 if (device->updateStateBlock != device->stateBlock
6615 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6617 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6618 resource, device->updateStateBlock, i);
6619 device->updateStateBlock->state.textures[i] = NULL;
6624 case WINED3DRTYPE_BUFFER:
6625 for (i = 0; i < MAX_STREAMS; ++i)
6627 if (device->stateBlock
6628 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6630 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6631 resource, device->stateBlock, i);
6632 device->stateBlock->state.streams[i].buffer = NULL;
6635 if (device->updateStateBlock != device->stateBlock
6636 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6638 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6639 resource, device->updateStateBlock, i);
6640 device->updateStateBlock->state.streams[i].buffer = NULL;
6645 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6647 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6648 resource, device->stateBlock);
6649 device->stateBlock->state.index_buffer = NULL;
6652 if (device->updateStateBlock != device->stateBlock
6653 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6655 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6656 resource, device->updateStateBlock);
6657 device->updateStateBlock->state.index_buffer = NULL;
6665 /* Remove the resource from the resourceStore */
6666 device_resource_remove(device, resource);
6668 TRACE("Resource released.\n");
6671 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6673 IWineD3DResourceImpl *resource, *cursor;
6675 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6677 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6678 TRACE("enumerating resource %p\n", resource);
6679 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6680 ret = pCallback((IWineD3DResource *) resource, pData);
6681 if(ret == S_FALSE) {
6682 TRACE("Canceling enumeration\n");
6689 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6692 IWineD3DResourceImpl *resource;
6694 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6696 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6697 if (type == WINED3DRTYPE_SURFACE)
6699 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6701 TRACE("Found surface %p for dc %p.\n", resource, dc);
6702 *surface = (IWineD3DSurface *)resource;
6708 return WINED3DERR_INVALIDCALL;
6711 /**********************************************************
6712 * IWineD3DDevice VTbl follows
6713 **********************************************************/
6715 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6717 /*** IUnknown methods ***/
6718 IWineD3DDeviceImpl_QueryInterface,
6719 IWineD3DDeviceImpl_AddRef,
6720 IWineD3DDeviceImpl_Release,
6721 /*** IWineD3DDevice methods ***/
6722 /*** Creation methods**/
6723 IWineD3DDeviceImpl_CreateBuffer,
6724 IWineD3DDeviceImpl_CreateVertexBuffer,
6725 IWineD3DDeviceImpl_CreateIndexBuffer,
6726 IWineD3DDeviceImpl_CreateStateBlock,
6727 IWineD3DDeviceImpl_CreateSurface,
6728 IWineD3DDeviceImpl_CreateRendertargetView,
6729 IWineD3DDeviceImpl_CreateTexture,
6730 IWineD3DDeviceImpl_CreateVolumeTexture,
6731 IWineD3DDeviceImpl_CreateVolume,
6732 IWineD3DDeviceImpl_CreateCubeTexture,
6733 IWineD3DDeviceImpl_CreateQuery,
6734 IWineD3DDeviceImpl_CreateSwapChain,
6735 IWineD3DDeviceImpl_CreateVertexDeclaration,
6736 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6737 IWineD3DDeviceImpl_CreateVertexShader,
6738 IWineD3DDeviceImpl_CreateGeometryShader,
6739 IWineD3DDeviceImpl_CreatePixelShader,
6740 IWineD3DDeviceImpl_CreatePalette,
6741 /*** Odd functions **/
6742 IWineD3DDeviceImpl_Init3D,
6743 IWineD3DDeviceImpl_InitGDI,
6744 IWineD3DDeviceImpl_Uninit3D,
6745 IWineD3DDeviceImpl_UninitGDI,
6746 IWineD3DDeviceImpl_SetMultithreaded,
6747 IWineD3DDeviceImpl_EvictManagedResources,
6748 IWineD3DDeviceImpl_GetAvailableTextureMem,
6749 IWineD3DDeviceImpl_GetBackBuffer,
6750 IWineD3DDeviceImpl_GetCreationParameters,
6751 IWineD3DDeviceImpl_GetDeviceCaps,
6752 IWineD3DDeviceImpl_GetDirect3D,
6753 IWineD3DDeviceImpl_GetDisplayMode,
6754 IWineD3DDeviceImpl_SetDisplayMode,
6755 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6756 IWineD3DDeviceImpl_GetRasterStatus,
6757 IWineD3DDeviceImpl_GetSwapChain,
6758 IWineD3DDeviceImpl_Reset,
6759 IWineD3DDeviceImpl_SetDialogBoxMode,
6760 IWineD3DDeviceImpl_SetCursorProperties,
6761 IWineD3DDeviceImpl_SetCursorPosition,
6762 IWineD3DDeviceImpl_ShowCursor,
6763 /*** Getters and setters **/
6764 IWineD3DDeviceImpl_SetClipPlane,
6765 IWineD3DDeviceImpl_GetClipPlane,
6766 IWineD3DDeviceImpl_SetClipStatus,
6767 IWineD3DDeviceImpl_GetClipStatus,
6768 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6769 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6770 IWineD3DDeviceImpl_SetDepthStencilSurface,
6771 IWineD3DDeviceImpl_GetDepthStencilSurface,
6772 IWineD3DDeviceImpl_SetGammaRamp,
6773 IWineD3DDeviceImpl_GetGammaRamp,
6774 IWineD3DDeviceImpl_SetIndexBuffer,
6775 IWineD3DDeviceImpl_GetIndexBuffer,
6776 IWineD3DDeviceImpl_SetBaseVertexIndex,
6777 IWineD3DDeviceImpl_GetBaseVertexIndex,
6778 IWineD3DDeviceImpl_SetLight,
6779 IWineD3DDeviceImpl_GetLight,
6780 IWineD3DDeviceImpl_SetLightEnable,
6781 IWineD3DDeviceImpl_GetLightEnable,
6782 IWineD3DDeviceImpl_SetMaterial,
6783 IWineD3DDeviceImpl_GetMaterial,
6784 IWineD3DDeviceImpl_SetNPatchMode,
6785 IWineD3DDeviceImpl_GetNPatchMode,
6786 IWineD3DDeviceImpl_SetPaletteEntries,
6787 IWineD3DDeviceImpl_GetPaletteEntries,
6788 IWineD3DDeviceImpl_SetPixelShader,
6789 IWineD3DDeviceImpl_GetPixelShader,
6790 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6791 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6792 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6793 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6794 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6795 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6796 IWineD3DDeviceImpl_SetRenderState,
6797 IWineD3DDeviceImpl_GetRenderState,
6798 IWineD3DDeviceImpl_SetRenderTarget,
6799 IWineD3DDeviceImpl_GetRenderTarget,
6800 IWineD3DDeviceImpl_SetFrontBackBuffers,
6801 IWineD3DDeviceImpl_SetSamplerState,
6802 IWineD3DDeviceImpl_GetSamplerState,
6803 IWineD3DDeviceImpl_SetScissorRect,
6804 IWineD3DDeviceImpl_GetScissorRect,
6805 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6806 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6807 IWineD3DDeviceImpl_SetStreamSource,
6808 IWineD3DDeviceImpl_GetStreamSource,
6809 IWineD3DDeviceImpl_SetStreamSourceFreq,
6810 IWineD3DDeviceImpl_GetStreamSourceFreq,
6811 IWineD3DDeviceImpl_SetTexture,
6812 IWineD3DDeviceImpl_GetTexture,
6813 IWineD3DDeviceImpl_SetTextureStageState,
6814 IWineD3DDeviceImpl_GetTextureStageState,
6815 IWineD3DDeviceImpl_SetTransform,
6816 IWineD3DDeviceImpl_GetTransform,
6817 IWineD3DDeviceImpl_SetVertexDeclaration,
6818 IWineD3DDeviceImpl_GetVertexDeclaration,
6819 IWineD3DDeviceImpl_SetVertexShader,
6820 IWineD3DDeviceImpl_GetVertexShader,
6821 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6822 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6823 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6824 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6825 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6826 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6827 IWineD3DDeviceImpl_SetViewport,
6828 IWineD3DDeviceImpl_GetViewport,
6829 IWineD3DDeviceImpl_MultiplyTransform,
6830 IWineD3DDeviceImpl_ValidateDevice,
6831 IWineD3DDeviceImpl_ProcessVertices,
6832 /*** State block ***/
6833 IWineD3DDeviceImpl_BeginStateBlock,
6834 IWineD3DDeviceImpl_EndStateBlock,
6835 /*** Scene management ***/
6836 IWineD3DDeviceImpl_BeginScene,
6837 IWineD3DDeviceImpl_EndScene,
6838 IWineD3DDeviceImpl_Present,
6839 IWineD3DDeviceImpl_Clear,
6840 IWineD3DDeviceImpl_ClearRendertargetView,
6842 IWineD3DDeviceImpl_SetPrimitiveType,
6843 IWineD3DDeviceImpl_GetPrimitiveType,
6844 IWineD3DDeviceImpl_DrawPrimitive,
6845 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6846 IWineD3DDeviceImpl_DrawPrimitiveUP,
6847 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6848 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6849 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6850 IWineD3DDeviceImpl_DrawRectPatch,
6851 IWineD3DDeviceImpl_DrawTriPatch,
6852 IWineD3DDeviceImpl_DeletePatch,
6853 IWineD3DDeviceImpl_ColorFill,
6854 IWineD3DDeviceImpl_UpdateTexture,
6855 IWineD3DDeviceImpl_UpdateSurface,
6856 IWineD3DDeviceImpl_GetFrontBufferData,
6857 /*** object tracking ***/
6858 IWineD3DDeviceImpl_EnumResources,
6859 IWineD3DDeviceImpl_GetSurfaceFromDC,
6860 IWineD3DDeviceImpl_AcquireFocusWindow,
6861 IWineD3DDeviceImpl_ReleaseFocusWindow,
6864 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6865 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6866 IWineD3DDeviceParent *device_parent)
6868 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6869 const struct fragment_pipeline *fragment_pipeline;
6870 struct shader_caps shader_caps;
6871 struct fragment_caps ffp_caps;
6872 WINED3DDISPLAYMODE mode;
6876 device->lpVtbl = &IWineD3DDevice_Vtbl;
6878 device->wined3d = (IWineD3D *)wined3d;
6879 IWineD3D_AddRef(device->wined3d);
6880 device->adapter = wined3d->adapter_count ? adapter : NULL;
6881 device->device_parent = device_parent;
6882 list_init(&device->resources);
6883 list_init(&device->shaders);
6885 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6886 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6888 /* Get the initial screen setup for ddraw. */
6889 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6892 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6893 IWineD3D_Release(device->wined3d);
6896 device->ddraw_width = mode.Width;
6897 device->ddraw_height = mode.Height;
6898 device->ddraw_format = mode.Format;
6900 /* Save the creation parameters. */
6901 device->createParms.AdapterOrdinal = adapter_idx;
6902 device->createParms.DeviceType = device_type;
6903 device->createParms.hFocusWindow = focus_window;
6904 device->createParms.BehaviorFlags = flags;
6906 device->devType = device_type;
6907 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6909 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6910 device->shader_backend = adapter->shader_backend;
6912 if (device->shader_backend)
6914 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6915 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6916 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6917 device->vs_clipping = shader_caps.VSClipping;
6919 fragment_pipeline = adapter->fragment_pipe;
6920 device->frag_pipe = fragment_pipeline;
6921 if (fragment_pipeline)
6923 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6924 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6926 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6927 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6930 ERR("Failed to compile state table, hr %#x.\n", hr);
6931 IWineD3D_Release(device->wined3d);
6935 device->blitter = adapter->blitter;
6941 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6942 DWORD rep = This->StateTable[state].representative;
6943 struct wined3d_context *context;
6948 for(i = 0; i < This->numContexts; i++) {
6949 context = This->contexts[i];
6950 if(isStateDirty(context, rep)) continue;
6952 context->dirtyArray[context->numDirtyEntries++] = rep;
6953 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6954 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6955 context->isStateDirty[idx] |= (1 << shift);
6959 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6961 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6962 *width = context->current_rt->pow2Width;
6963 *height = context->current_rt->pow2Height;
6966 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6968 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6969 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6970 * current context's drawable, which is the size of the back buffer of the swapchain
6971 * the active context belongs to. */
6972 *width = swapchain->presentParms.BackBufferWidth;
6973 *height = swapchain->presentParms.BackBufferHeight;
6976 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6977 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6979 if (device->filter_messages)
6981 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6982 window, message, wparam, lparam);
6983 return DefWindowProcW(window, message, wparam, lparam);
6986 if (message == WM_DESTROY)
6988 TRACE("unregister window %p.\n", window);
6989 wined3d_unregister_window(window);
6991 if (device->focus_window == window) device->focus_window = NULL;
6992 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6995 return CallWindowProcW(proc, window, message, wparam, lparam);