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 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)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->lightMap[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->lightMap[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->lightMap[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->lightMap[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->lightMap[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->activeLights[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->activeLights[i])
2743 This->updateStateBlock->activeLights[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->lightMap[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->clipplane[Index][0] == pPlane[0] &&
2812 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2813 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2814 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2815 TRACE("Application is setting old values over, nothing to do\n");
2819 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2820 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2821 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2822 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2824 /* Handle recording of state blocks */
2825 if (This->isRecordingState) {
2826 TRACE("Recording... not performing anything\n");
2830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2835 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 TRACE("(%p) : for idx %d\n", This, Index);
2839 /* Validate Index */
2840 if (Index >= This->adapter->gl_info.limits.clipplanes)
2842 TRACE("Application has requested clipplane this device doesn't support\n");
2843 return WINED3DERR_INVALIDCALL;
2846 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2847 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2848 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2849 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2854 * Get / Set Clip Plane Status
2855 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2857 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 FIXME("(%p) : stub\n", This);
2862 return WINED3DERR_INVALIDCALL;
2864 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2865 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2869 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 FIXME("(%p) : stub\n", This);
2874 return WINED3DERR_INVALIDCALL;
2876 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2877 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2882 * Get / Set Material
2884 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 This->updateStateBlock->changed.material = TRUE;
2888 This->updateStateBlock->state.material = *pMaterial;
2890 /* Handle recording of state blocks */
2891 if (This->isRecordingState) {
2892 TRACE("Recording... not performing anything\n");
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2900 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 *pMaterial = This->updateStateBlock->state.material;
2903 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2904 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2905 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2906 pMaterial->Ambient.b, pMaterial->Ambient.a);
2907 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2908 pMaterial->Specular.b, pMaterial->Specular.a);
2909 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2910 pMaterial->Emissive.b, pMaterial->Emissive.a);
2911 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2919 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2920 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 IWineD3DBuffer *oldIdxs;
2925 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2926 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2928 This->updateStateBlock->changed.indices = TRUE;
2929 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2930 This->updateStateBlock->state.index_format = fmt;
2932 /* Handle recording of state blocks */
2933 if (This->isRecordingState) {
2934 TRACE("Recording... not performing anything\n");
2935 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2936 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2940 if(oldIdxs != pIndexData) {
2941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2943 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2944 IWineD3DBuffer_AddRef(pIndexData);
2947 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2948 IWineD3DBuffer_Release(oldIdxs);
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2959 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2961 /* up ref count on ppindexdata */
2963 IWineD3DBuffer_AddRef(*ppIndexData);
2964 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2966 TRACE("(%p) No index data set\n", This);
2968 TRACE("Returning %p\n", *ppIndexData);
2973 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2974 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2976 TRACE("(%p)->(%d)\n", This, BaseIndex);
2978 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2980 TRACE("Application is setting the old value over, nothing to do\n");
2984 This->updateStateBlock->state.base_vertex_index = BaseIndex;
2986 if (This->isRecordingState) {
2987 TRACE("Recording... not performing anything\n");
2990 /* The base vertex index affects the stream sources */
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2995 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 TRACE("(%p) : base_index %p\n", This, base_index);
2999 *base_index = This->stateBlock->state.base_vertex_index;
3001 TRACE("Returning %u\n", *base_index);
3007 * Get / Set Viewports
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 TRACE("(%p)\n", This);
3013 This->updateStateBlock->changed.viewport = TRUE;
3014 This->updateStateBlock->state.viewport = *pViewport;
3016 /* Handle recording of state blocks */
3017 if (This->isRecordingState) {
3018 TRACE("Recording... not performing anything\n");
3022 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3023 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3030 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 TRACE("(%p)\n", This);
3033 *pViewport = This->stateBlock->state.viewport;
3037 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3038 WINED3DRENDERSTATETYPE State, DWORD Value)
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 DWORD oldValue = This->stateBlock->state.render_states[State];
3043 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3045 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3046 This->updateStateBlock->state.render_states[State] = Value;
3048 /* Handle recording of state blocks */
3049 if (This->isRecordingState) {
3050 TRACE("Recording... not performing anything\n");
3054 /* Compared here and not before the assignment to allow proper stateblock recording */
3055 if(Value == oldValue) {
3056 TRACE("Application is setting the old value over, nothing to do\n");
3058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3065 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3071 *pValue = This->stateBlock->state.render_states[State];
3076 * Get / Set Sampler States
3077 * TODO: Verify against dx9 definitions
3080 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3085 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3087 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3088 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3091 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3093 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3094 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3097 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3098 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3099 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3101 /* Handle recording of state blocks */
3102 if (This->isRecordingState) {
3103 TRACE("Recording... not performing anything\n");
3107 if(oldValue == Value) {
3108 TRACE("Application is setting the old value over, nothing to do\n");
3112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3117 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3121 This, Sampler, debug_d3dsamplerstate(Type), Type);
3123 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3124 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3127 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3129 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3130 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3132 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3133 TRACE("(%p) : Returning %#x\n", This, *Value);
3138 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 This->updateStateBlock->changed.scissorRect = TRUE;
3142 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3144 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3147 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3149 if(This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 *pRect = This->updateStateBlock->state.scissor_rect;
3163 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3167 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3169 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3171 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3173 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3174 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3176 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3177 This->updateStateBlock->changed.vertexDecl = TRUE;
3179 if (This->isRecordingState) {
3180 TRACE("Recording... not performing anything\n");
3182 } else if(pDecl == oldDecl) {
3183 /* Checked after the assignment to allow proper stateblock recording */
3184 TRACE("Application is setting the old declaration over, nothing to do\n");
3188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3192 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3197 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3198 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3202 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3207 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3208 This->updateStateBlock->changed.vertexShader = TRUE;
3210 if (This->isRecordingState) {
3211 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3212 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3213 TRACE("Recording... not performing anything\n");
3215 } else if(oldShader == pShader) {
3216 /* Checked here to allow proper stateblock recording */
3217 TRACE("App is setting the old shader over, nothing to do\n");
3221 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3222 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3223 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3230 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3232 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3233 IWineD3DVertexShader *shader;
3235 TRACE("iface %p.\n", iface);
3237 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3238 if (shader) IWineD3DVertexShader_AddRef(shader);
3240 TRACE("Returning %p.\n", shader);
3244 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3245 IWineD3DDevice *iface,
3247 CONST BOOL *srcData,
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3253 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3254 iface, srcData, start, count);
3256 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3258 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3259 for (i = 0; i < cnt; i++)
3260 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3262 for (i = start; i < cnt + start; ++i) {
3263 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3266 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3271 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3272 IWineD3DDevice *iface,
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3278 int cnt = min(count, MAX_CONST_B - start);
3280 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3281 iface, dstData, start, count);
3283 if (!dstData || cnt < 0)
3284 return WINED3DERR_INVALIDCALL;
3286 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3291 IWineD3DDevice *iface,
3296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3299 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3300 iface, srcData, start, count);
3302 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3304 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3305 for (i = 0; i < cnt; i++)
3306 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3307 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3309 for (i = start; i < cnt + start; ++i) {
3310 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3313 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3318 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3319 IWineD3DDevice *iface,
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3325 int cnt = min(count, MAX_CONST_I - start);
3327 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3328 iface, dstData, start, count);
3330 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3331 return WINED3DERR_INVALIDCALL;
3333 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3337 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3338 IWineD3DDevice *iface,
3340 CONST float *srcData,
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3347 iface, srcData, start, count);
3349 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3350 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3351 return WINED3DERR_INVALIDCALL;
3353 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3355 for (i = 0; i < count; i++)
3356 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3357 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3360 if (!This->isRecordingState)
3362 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3366 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3367 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3373 IWineD3DDevice *iface,
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 int cnt = min(count, This->d3d_vshader_constantF - start);
3381 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3382 iface, dstData, start, count);
3384 if (!dstData || cnt < 0)
3385 return WINED3DERR_INVALIDCALL;
3387 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3391 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3393 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3399 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3401 DWORD i = This->rev_tex_unit_map[unit];
3402 DWORD j = This->texUnitMap[stage];
3404 This->texUnitMap[stage] = unit;
3405 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3407 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3410 This->rev_tex_unit_map[unit] = stage;
3411 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3413 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3417 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3420 This->fixed_function_usage_map = 0;
3421 for (i = 0; i < MAX_TEXTURES; ++i)
3423 const struct wined3d_state *state = &This->stateBlock->state;
3424 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3425 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3426 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3427 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3428 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3429 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3430 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3431 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3433 if (color_op == WINED3DTOP_DISABLE) {
3434 /* Not used, and disable higher stages */
3438 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3439 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3440 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3441 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3442 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3443 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3444 This->fixed_function_usage_map |= (1 << i);
3447 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3448 This->fixed_function_usage_map |= (1 << (i + 1));
3453 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3455 unsigned int i, tex;
3458 device_update_fixed_function_usage_map(This);
3459 ffu_map = This->fixed_function_usage_map;
3461 if (This->max_ffp_textures == gl_info->limits.texture_stages
3462 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3464 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3466 if (!(ffu_map & 1)) continue;
3468 if (This->texUnitMap[i] != i) {
3469 device_map_stage(This, i, i);
3470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3471 markTextureStagesDirty(This, i);
3477 /* Now work out the mapping */
3479 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3481 if (!(ffu_map & 1)) continue;
3483 if (This->texUnitMap[i] != tex) {
3484 device_map_stage(This, i, tex);
3485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3486 markTextureStagesDirty(This, i);
3493 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3495 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3496 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3499 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3500 if (sampler_type[i] && This->texUnitMap[i] != i)
3502 device_map_stage(This, i, i);
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3504 if (i < gl_info->limits.texture_stages)
3506 markTextureStagesDirty(This, i);
3512 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3513 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3515 DWORD current_mapping = This->rev_tex_unit_map[unit];
3517 /* Not currently used */
3518 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3520 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3521 /* Used by a fragment sampler */
3523 if (!pshader_sampler_tokens) {
3524 /* No pixel shader, check fixed function */
3525 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3528 /* Pixel shader, check the shader's sampler map */
3529 return !pshader_sampler_tokens[current_mapping];
3532 /* Used by a vertex sampler */
3533 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3536 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3538 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3539 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3540 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3541 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3546 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3548 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3549 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3550 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3553 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3554 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3555 if (vshader_sampler_type[i])
3557 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3559 /* Already mapped somewhere */
3563 while (start >= 0) {
3564 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3566 device_map_stage(This, vsampler_idx, start);
3567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3579 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3581 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3582 BOOL vs = use_vs(This->stateBlock);
3583 BOOL ps = use_ps(This->stateBlock);
3586 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3587 * that would be really messy and require shader recompilation
3588 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3589 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3591 if (ps) device_map_psamplers(This, gl_info);
3592 else device_map_fixed_function_samplers(This, gl_info);
3594 if (vs) device_map_vsamplers(This, ps, gl_info);
3597 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3600 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3601 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3602 This->updateStateBlock->changed.pixelShader = TRUE;
3604 /* Handle recording of state blocks */
3605 if (This->isRecordingState) {
3606 TRACE("Recording... not performing anything\n");
3609 if (This->isRecordingState) {
3610 TRACE("Recording... not performing anything\n");
3611 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3612 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3616 if(pShader == oldShader) {
3617 TRACE("App is setting the old pixel shader over, nothing to do\n");
3621 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3622 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3624 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3630 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3632 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3633 IWineD3DPixelShader *shader;
3635 TRACE("iface %p.\n", iface);
3637 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3638 if (shader) IWineD3DPixelShader_AddRef(shader);
3640 TRACE("Returning %p.\n", shader);
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3645 IWineD3DDevice *iface,
3647 CONST BOOL *srcData,
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3653 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3654 iface, srcData, start, count);
3656 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3658 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3659 for (i = 0; i < cnt; i++)
3660 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3662 for (i = start; i < cnt + start; ++i) {
3663 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3666 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3671 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3672 IWineD3DDevice *iface,
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 int cnt = min(count, MAX_CONST_B - start);
3680 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3681 iface, dstData, start, count);
3683 if (!dstData || cnt < 0)
3684 return WINED3DERR_INVALIDCALL;
3686 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3690 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3691 IWineD3DDevice *iface,
3696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3697 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3699 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3700 iface, srcData, start, count);
3702 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3704 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3705 for (i = 0; i < cnt; i++)
3706 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3707 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3709 for (i = start; i < cnt + start; ++i) {
3710 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3713 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3718 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3719 IWineD3DDevice *iface,
3724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3725 int cnt = min(count, MAX_CONST_I - start);
3727 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3728 iface, dstData, start, count);
3730 if (!dstData || cnt < 0)
3731 return WINED3DERR_INVALIDCALL;
3733 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3737 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3738 IWineD3DDevice *iface,
3740 CONST float *srcData,
3743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3746 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3747 iface, srcData, start, count);
3749 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3750 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3751 return WINED3DERR_INVALIDCALL;
3753 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3755 for (i = 0; i < count; i++)
3756 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3757 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3760 if (!This->isRecordingState)
3762 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3766 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3767 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3772 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3773 IWineD3DDevice *iface,
3778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3779 int cnt = min(count, This->d3d_pshader_constantF - start);
3781 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3782 iface, dstData, start, count);
3784 if (!dstData || cnt < 0)
3785 return WINED3DERR_INVALIDCALL;
3787 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3791 /* Context activation is done by the caller. */
3792 /* Do not call while under the GL lock. */
3793 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3794 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3795 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3798 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3799 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3802 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3806 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3808 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3811 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3813 ERR("Source has no position mask\n");
3814 return WINED3DERR_INVALIDCALL;
3817 if (!dest->resource.allocatedMemory)
3818 buffer_get_sysmem(dest, gl_info);
3820 /* Get a pointer into the destination vbo(create one if none exists) and
3821 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3823 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3825 dest->flags |= WINED3D_BUFFER_CREATEBO;
3826 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3829 if (dest->buffer_object)
3831 unsigned char extrabytes = 0;
3832 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3833 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3834 * this may write 4 extra bytes beyond the area that should be written
3836 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3837 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3838 if(!dest_conv_addr) {
3839 ERR("Out of memory\n");
3840 /* Continue without storing converted vertices */
3842 dest_conv = dest_conv_addr;
3845 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3847 static BOOL warned = FALSE;
3849 * The clipping code is not quite correct. Some things need
3850 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3851 * so disable clipping for now.
3852 * (The graphics in Half-Life are broken, and my processvertices
3853 * test crashes with IDirect3DDevice3)
3859 FIXME("Clipping is broken and disabled for now\n");
3861 } else doClip = FALSE;
3862 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3864 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3867 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3868 WINED3DTS_PROJECTION,
3870 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3871 WINED3DTS_WORLDMATRIX(0),
3874 TRACE("View mat:\n");
3875 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);
3876 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);
3877 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);
3878 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);
3880 TRACE("Proj mat:\n");
3881 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);
3882 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);
3883 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);
3884 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);
3886 TRACE("World mat:\n");
3887 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);
3888 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);
3889 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);
3890 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);
3892 /* Get the viewport */
3893 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3894 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3895 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3897 multiply_matrix(&mat,&view_mat,&world_mat);
3898 multiply_matrix(&mat,&proj_mat,&mat);
3900 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3902 for (i = 0; i < dwCount; i+= 1) {
3903 unsigned int tex_index;
3905 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3906 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3907 /* The position first */
3908 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3909 const float *p = (const float *)(element->data + i * element->stride);
3911 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3913 /* Multiplication with world, view and projection matrix */
3914 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);
3915 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);
3916 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);
3917 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);
3919 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3921 /* WARNING: The following things are taken from d3d7 and were not yet checked
3922 * against d3d8 or d3d9!
3925 /* Clipping conditions: From msdn
3927 * A vertex is clipped if it does not match the following requirements
3931 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3933 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3934 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3939 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3940 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3943 /* "Normal" viewport transformation (not clipped)
3944 * 1) The values are divided by rhw
3945 * 2) The y axis is negative, so multiply it with -1
3946 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3947 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3948 * 4) Multiply x with Width/2 and add Width/2
3949 * 5) The same for the height
3950 * 6) Add the viewpoint X and Y to the 2D coordinates and
3951 * The minimum Z value to z
3952 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3954 * Well, basically it's simply a linear transformation into viewport
3966 z *= vp.MaxZ - vp.MinZ;
3968 x += vp.Width / 2 + vp.X;
3969 y += vp.Height / 2 + vp.Y;
3974 /* That vertex got clipped
3975 * Contrary to OpenGL it is not dropped completely, it just
3976 * undergoes a different calculation.
3978 TRACE("Vertex got clipped\n");
3985 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3986 * outside of the main vertex buffer memory. That needs some more
3991 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3994 ( (float *) dest_ptr)[0] = x;
3995 ( (float *) dest_ptr)[1] = y;
3996 ( (float *) dest_ptr)[2] = z;
3997 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3999 dest_ptr += 3 * sizeof(float);
4001 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4002 dest_ptr += sizeof(float);
4007 ( (float *) dest_conv)[0] = x * w;
4008 ( (float *) dest_conv)[1] = y * w;
4009 ( (float *) dest_conv)[2] = z * w;
4010 ( (float *) dest_conv)[3] = w;
4012 dest_conv += 3 * sizeof(float);
4014 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4015 dest_conv += sizeof(float);
4019 if (DestFVF & WINED3DFVF_PSIZE) {
4020 dest_ptr += sizeof(DWORD);
4021 if(dest_conv) dest_conv += sizeof(DWORD);
4023 if (DestFVF & WINED3DFVF_NORMAL) {
4024 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4025 const float *normal = (const float *)(element->data + i * element->stride);
4026 /* AFAIK this should go into the lighting information */
4027 FIXME("Didn't expect the destination to have a normal\n");
4028 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4030 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4034 if (DestFVF & WINED3DFVF_DIFFUSE) {
4035 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4036 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4037 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4039 static BOOL warned = FALSE;
4042 ERR("No diffuse color in source, but destination has one\n");
4046 *( (DWORD *) dest_ptr) = 0xffffffff;
4047 dest_ptr += sizeof(DWORD);
4050 *( (DWORD *) dest_conv) = 0xffffffff;
4051 dest_conv += sizeof(DWORD);
4055 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4057 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4058 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4059 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4060 dest_conv += sizeof(DWORD);
4065 if (DestFVF & WINED3DFVF_SPECULAR)
4067 /* What's the color value in the feedback buffer? */
4068 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4069 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4070 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4072 static BOOL warned = FALSE;
4075 ERR("No specular color in source, but destination has one\n");
4079 *( (DWORD *) dest_ptr) = 0xFF000000;
4080 dest_ptr += sizeof(DWORD);
4083 *( (DWORD *) dest_conv) = 0xFF000000;
4084 dest_conv += sizeof(DWORD);
4088 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4090 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4091 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4092 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4093 dest_conv += sizeof(DWORD);
4098 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4099 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4100 const float *tex_coord = (const float *)(element->data + i * element->stride);
4101 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4103 ERR("No source texture, but destination requests one\n");
4104 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4105 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4108 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4110 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4120 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4121 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4122 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4123 dwCount * get_flexible_vertex_size(DestFVF),
4125 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4129 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4134 #undef copy_and_next
4136 /* Do not call while under the GL lock. */
4137 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4138 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 struct wined3d_stream_info stream_info;
4143 const struct wined3d_gl_info *gl_info;
4144 struct wined3d_context *context;
4145 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4148 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4151 ERR("Output vertex declaration not implemented yet\n");
4154 /* Need any context to write to the vbo. */
4155 context = context_acquire(This, NULL);
4156 gl_info = context->gl_info;
4158 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4159 * control the streamIsUP flag, thus restore it afterwards.
4161 This->stateBlock->state.user_stream = FALSE;
4162 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4163 This->stateBlock->state.user_stream = streamWasUP;
4165 if(vbo || SrcStartIndex) {
4167 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4168 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4170 * Also get the start index in, but only loop over all elements if there's something to add at all.
4172 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4174 struct wined3d_stream_info_element *e;
4176 if (!(stream_info.use_map & (1 << i))) continue;
4178 e = &stream_info.elements[i];
4179 if (e->buffer_object)
4181 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4182 e->buffer_object = 0;
4183 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4185 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4186 vb->buffer_object = 0;
4189 if (e->data) e->data += e->stride * SrcStartIndex;
4193 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4194 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4196 context_release(context);
4202 * Get / Set Texture Stage States
4203 * TODO: Verify against dx9 definitions
4205 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4208 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4211 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4213 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4215 WARN("Invalid Type %d passed.\n", Type);
4219 if (Stage >= gl_info->limits.texture_stages)
4221 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4222 Stage, gl_info->limits.texture_stages - 1);
4226 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4227 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4228 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4230 if (This->isRecordingState) {
4231 TRACE("Recording... not performing anything\n");
4235 /* Checked after the assignments to allow proper stateblock recording */
4236 if(oldValue == Value) {
4237 TRACE("App is setting the old value over, nothing to do\n");
4241 if (Stage > This->stateBlock->state.lowest_disabled_stage
4242 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4243 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4245 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4246 * Changes in other states are important on disabled stages too
4251 if(Type == WINED3DTSS_COLOROP) {
4254 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4255 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4256 * they have to be disabled
4258 * The current stage is dirtified below.
4260 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4262 TRACE("Additionally dirtifying stage %u\n", i);
4263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4265 This->stateBlock->state.lowest_disabled_stage = Stage;
4266 TRACE("New lowest disabled: %u\n", Stage);
4267 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4268 /* Previously disabled stage enabled. Stages above it may need enabling
4269 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4270 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4272 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4275 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4277 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4279 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4282 This->stateBlock->state.lowest_disabled_stage = i;
4283 TRACE("New lowest disabled: %u\n", i);
4287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4292 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4296 TRACE("iface %p, stage %u, state %s, value %p.\n",
4297 iface, Stage, debug_d3dtexturestate(Type), pValue);
4299 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4301 WARN("Invalid Type %d passed.\n", Type);
4305 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4306 TRACE("Returning %#x.\n", *pValue);
4314 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4315 DWORD stage, IWineD3DBaseTexture *texture)
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4319 IWineD3DBaseTexture *prev;
4321 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4323 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4324 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4326 /* Windows accepts overflowing this array... we do not. */
4327 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4329 WARN("Ignoring invalid stage %u.\n", stage);
4333 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4334 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4336 WARN("Rejecting attempt to set scratch texture.\n");
4337 return WINED3DERR_INVALIDCALL;
4340 This->updateStateBlock->changed.textures |= 1 << stage;
4342 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4343 TRACE("Previous texture %p.\n", prev);
4345 if (texture == prev)
4347 TRACE("App is setting the same texture again, nothing to do.\n");
4351 TRACE("Setting new texture to %p.\n", texture);
4352 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4354 if (This->isRecordingState)
4356 TRACE("Recording... not performing anything\n");
4358 if (texture) IWineD3DBaseTexture_AddRef(texture);
4359 if (prev) IWineD3DBaseTexture_Release(prev);
4366 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4367 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4368 GLenum dimensions = t->baseTexture.target;
4370 IWineD3DBaseTexture_AddRef(texture);
4372 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4375 if (!prev && stage < gl_info->limits.texture_stages)
4377 /* The source arguments for color and alpha ops have different
4378 * meanings when a NULL texture is bound, so the COLOROP and
4379 * ALPHAOP have to be dirtified. */
4380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4384 if (bind_count == 1) t->baseTexture.sampler = stage;
4389 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4390 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4392 IWineD3DBaseTexture_Release(prev);
4394 if (!texture && stage < gl_info->limits.texture_stages)
4396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4400 if (bind_count && t->baseTexture.sampler == stage)
4404 /* Search for other stages the texture is bound to. Shouldn't
4405 * happen if applications bind textures to a single stage only. */
4406 TRACE("Searching for other stages the texture is bound to.\n");
4407 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4409 if (This->updateStateBlock->state.textures[i] == t)
4411 TRACE("Texture is also bound to stage %u.\n", i);
4412 t->baseTexture.sampler = i;
4419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4424 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4427 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4429 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4430 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4433 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4435 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4436 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4439 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4441 IWineD3DBaseTexture_AddRef(*ppTexture);
4443 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4451 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4452 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4454 IWineD3DSwapChain *swapchain;
4457 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4458 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4460 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4463 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4467 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4468 IWineD3DSwapChain_Release(swapchain);
4471 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4478 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 WARN("(%p) : stub, calling idirect3d for now\n", This);
4481 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4484 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 IWineD3DSwapChain *swapChain;
4489 if(iSwapChain > 0) {
4490 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4491 if (hr == WINED3D_OK) {
4492 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4493 IWineD3DSwapChain_Release(swapChain);
4495 FIXME("(%p) Error getting display mode\n", This);
4498 /* Don't read the real display mode,
4499 but return the stored mode instead. X11 can't change the color
4500 depth, and some apps are pretty angry if they SetDisplayMode from
4501 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4503 Also don't relay to the swapchain because with ddraw it's possible
4504 that there isn't a swapchain at all */
4505 pMode->Width = This->ddraw_width;
4506 pMode->Height = This->ddraw_height;
4507 pMode->Format = This->ddraw_format;
4508 pMode->RefreshRate = 0;
4516 * Stateblock related functions
4519 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 IWineD3DStateBlock *stateblock;
4524 TRACE("(%p)\n", This);
4526 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4528 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4529 if (FAILED(hr)) return hr;
4531 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4532 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4533 This->isRecordingState = TRUE;
4535 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4540 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4544 if (!This->isRecordingState) {
4545 WARN("(%p) not recording! returning error\n", This);
4546 *ppStateBlock = NULL;
4547 return WINED3DERR_INVALIDCALL;
4550 stateblock_init_contained_states(object);
4552 *ppStateBlock = (IWineD3DStateBlock*) object;
4553 This->isRecordingState = FALSE;
4554 This->updateStateBlock = This->stateBlock;
4555 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4556 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4557 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4562 * Scene related functions
4564 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4565 /* At the moment we have no need for any functionality at the beginning
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 TRACE("(%p)\n", This);
4571 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4572 return WINED3DERR_INVALIDCALL;
4574 This->inScene = TRUE;
4578 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 struct wined3d_context *context;
4583 TRACE("(%p)\n", This);
4585 if(!This->inScene) {
4586 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4587 return WINED3DERR_INVALIDCALL;
4590 context = context_acquire(This, NULL);
4591 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4593 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4595 context_release(context);
4597 This->inScene = FALSE;
4601 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4602 const RECT *pSourceRect, const RECT *pDestRect,
4603 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4605 IWineD3DSwapChain *swapChain = NULL;
4607 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4609 TRACE("iface %p.\n", iface);
4611 for(i = 0 ; i < swapchains ; i ++) {
4613 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4614 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4615 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4616 IWineD3DSwapChain_Release(swapChain);
4622 /* Do not call while under the GL lock. */
4623 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4624 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4626 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4627 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4630 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4631 iface, rect_count, rects, flags, color, depth, stencil);
4633 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4635 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4636 /* TODO: What about depth stencil buffers without stencil bits? */
4637 return WINED3DERR_INVALIDCALL;
4640 device_get_draw_rect(device, &draw_rect);
4642 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4643 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4650 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4651 WINED3DPRIMITIVETYPE primitive_type)
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4657 This->updateStateBlock->changed.primitive_type = TRUE;
4658 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4661 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4662 WINED3DPRIMITIVETYPE *primitive_type)
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4668 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4670 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4673 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4677 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4679 if (!This->stateBlock->state.vertex_declaration)
4681 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4682 return WINED3DERR_INVALIDCALL;
4685 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4686 if (This->stateBlock->state.user_stream)
4688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4689 This->stateBlock->state.user_stream = FALSE;
4692 if (This->stateBlock->state.load_base_vertex_index)
4694 This->stateBlock->state.load_base_vertex_index = 0;
4695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4697 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4698 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4705 struct wined3d_buffer *index_buffer;
4709 index_buffer = This->stateBlock->state.index_buffer;
4712 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4713 * without an index buffer set. (The first time at least...)
4714 * D3D8 simply dies, but I doubt it can do much harm to return
4715 * D3DERR_INVALIDCALL there as well. */
4716 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4717 return WINED3DERR_INVALIDCALL;
4720 if (!This->stateBlock->state.vertex_declaration)
4722 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4723 return WINED3DERR_INVALIDCALL;
4726 if (This->stateBlock->state.user_stream)
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4729 This->stateBlock->state.user_stream = FALSE;
4731 vbo = index_buffer->buffer_object;
4733 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4735 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4740 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4742 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4746 drawPrimitive(iface, index_count, startIndex, idxStride,
4747 vbo ? NULL : index_buffer->resource.allocatedMemory);
4752 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4753 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 struct wined3d_stream_state *stream;
4759 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4760 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4762 if (!This->stateBlock->state.vertex_declaration)
4764 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4765 return WINED3DERR_INVALIDCALL;
4768 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4769 stream = &This->stateBlock->state.streams[0];
4770 vb = (IWineD3DBuffer *)stream->buffer;
4771 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4772 if (vb) IWineD3DBuffer_Release(vb);
4774 stream->stride = VertexStreamZeroStride;
4775 This->stateBlock->state.user_stream = TRUE;
4776 This->stateBlock->state.load_base_vertex_index = 0;
4778 /* TODO: Only mark dirty if drawing from a different UP address */
4779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4781 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4783 /* MSDN specifies stream zero settings must be set to NULL */
4784 stream->buffer = NULL;
4787 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4788 * the new stream sources or use UP drawing again
4793 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4794 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4795 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4799 struct wined3d_stream_state *stream;
4803 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4804 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4806 if (!This->stateBlock->state.vertex_declaration)
4808 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4809 return WINED3DERR_INVALIDCALL;
4812 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4818 stream = &This->stateBlock->state.streams[0];
4819 vb = (IWineD3DBuffer *)stream->buffer;
4820 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4821 if (vb) IWineD3DBuffer_Release(vb);
4823 stream->stride = VertexStreamZeroStride;
4824 This->stateBlock->state.user_stream = TRUE;
4826 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4827 This->stateBlock->state.base_vertex_index = 0;
4828 This->stateBlock->state.load_base_vertex_index = 0;
4829 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4833 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4835 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4836 stream->buffer = NULL;
4838 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4841 IWineD3DBuffer_Release(ib);
4842 This->stateBlock->state.index_buffer = NULL;
4844 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4845 * SetStreamSource to specify a vertex buffer
4851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4852 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4856 /* Mark the state dirty until we have nicer tracking
4857 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4862 This->stateBlock->state.base_vertex_index = 0;
4863 This->up_strided = DrawPrimStrideData;
4864 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4865 This->up_strided = NULL;
4869 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4870 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4871 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4874 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4876 /* Mark the state dirty until we have nicer tracking
4877 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4882 This->stateBlock->state.user_stream = TRUE;
4883 This->stateBlock->state.base_vertex_index = 0;
4884 This->up_strided = DrawPrimStrideData;
4885 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4886 This->up_strided = NULL;
4890 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4891 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4892 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4894 WINED3DLOCKED_BOX src;
4895 WINED3DLOCKED_BOX dst;
4898 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4899 iface, pSourceVolume, pDestinationVolume);
4901 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4902 * dirtification to improve loading performance.
4904 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4905 if(FAILED(hr)) return hr;
4906 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4908 IWineD3DVolume_UnlockBox(pSourceVolume);
4912 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4914 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4916 IWineD3DVolume_UnlockBox(pSourceVolume);
4918 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4923 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4924 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4926 unsigned int level_count, i;
4927 WINED3DRESOURCETYPE type;
4930 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4932 /* Verify that the source and destination textures are non-NULL. */
4933 if (!src_texture || !dst_texture)
4935 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4936 return WINED3DERR_INVALIDCALL;
4939 if (src_texture == dst_texture)
4941 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4942 return WINED3DERR_INVALIDCALL;
4945 /* Verify that the source and destination textures are the same type. */
4946 type = IWineD3DBaseTexture_GetType(src_texture);
4947 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4949 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4950 return WINED3DERR_INVALIDCALL;
4953 /* Check that both textures have the identical numbers of levels. */
4954 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4955 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4957 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4958 return WINED3DERR_INVALIDCALL;
4961 /* Make sure that the destination texture is loaded. */
4962 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4964 /* Update every surface level of the texture. */
4967 case WINED3DRTYPE_TEXTURE:
4969 IWineD3DSurface *src_surface;
4970 IWineD3DSurface *dst_surface;
4972 for (i = 0; i < level_count; ++i)
4974 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4975 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4976 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4977 IWineD3DSurface_Release(dst_surface);
4978 IWineD3DSurface_Release(src_surface);
4981 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4988 case WINED3DRTYPE_CUBETEXTURE:
4990 IWineD3DSurface *src_surface;
4991 IWineD3DSurface *dst_surface;
4992 WINED3DCUBEMAP_FACES face;
4994 for (i = 0; i < level_count; ++i)
4996 /* Update each cube face. */
4997 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4999 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5000 face, i, &src_surface);
5001 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5002 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5003 face, i, &dst_surface);
5004 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5005 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5006 IWineD3DSurface_Release(dst_surface);
5007 IWineD3DSurface_Release(src_surface);
5010 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5018 case WINED3DRTYPE_VOLUMETEXTURE:
5020 IWineD3DVolume *src_volume;
5021 IWineD3DVolume *dst_volume;
5023 for (i = 0; i < level_count; ++i)
5025 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5026 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5027 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5028 IWineD3DVolume_Release(dst_volume);
5029 IWineD3DVolume_Release(src_volume);
5032 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5040 FIXME("Unsupported texture type %#x.\n", type);
5041 return WINED3DERR_INVALIDCALL;
5047 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5048 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5050 IWineD3DSwapChain *swapchain;
5053 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5055 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5056 if (FAILED(hr)) return hr;
5058 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5059 IWineD3DSwapChain_Release(swapchain);
5064 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5066 IWineD3DBaseTextureImpl *texture;
5069 TRACE("(%p) : %p\n", This, pNumPasses);
5071 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5073 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5075 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5076 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5078 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5080 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5081 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5084 texture = This->stateBlock->state.textures[i];
5085 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5087 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5089 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5092 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5094 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5097 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5098 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5100 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5105 /* return a sensible default */
5108 TRACE("returning D3D_OK\n");
5112 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5116 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5118 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5119 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5120 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5122 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5127 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 PALETTEENTRY **palettes;
5133 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5135 if (PaletteNumber >= MAX_PALETTES) {
5136 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5137 return WINED3DERR_INVALIDCALL;
5140 if (PaletteNumber >= This->NumberOfPalettes) {
5141 NewSize = This->NumberOfPalettes;
5144 } while(PaletteNumber >= NewSize);
5145 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5147 ERR("Out of memory!\n");
5148 return E_OUTOFMEMORY;
5150 This->palettes = palettes;
5151 This->NumberOfPalettes = NewSize;
5154 if (!This->palettes[PaletteNumber]) {
5155 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5156 if (!This->palettes[PaletteNumber]) {
5157 ERR("Out of memory!\n");
5158 return E_OUTOFMEMORY;
5162 for (j = 0; j < 256; ++j) {
5163 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5164 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5165 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5166 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5168 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5169 TRACE("(%p) : returning\n", This);
5173 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5176 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5177 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5178 /* What happens in such situation isn't documented; Native seems to silently abort
5179 on such conditions. Return Invalid Call. */
5180 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5181 return WINED3DERR_INVALIDCALL;
5183 for (j = 0; j < 256; ++j) {
5184 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5185 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5186 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5187 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5189 TRACE("(%p) : returning\n", This);
5193 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5195 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5196 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5197 (tested with reference rasterizer). Return Invalid Call. */
5198 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5199 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5200 return WINED3DERR_INVALIDCALL;
5202 /*TODO: stateblocks */
5203 if (This->currentPalette != PaletteNumber) {
5204 This->currentPalette = PaletteNumber;
5205 dirtify_p8_texture_samplers(This);
5207 TRACE("(%p) : returning\n", This);
5211 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5216 WARN("(%p) : returning Invalid Call\n", This);
5217 return WINED3DERR_INVALIDCALL;
5219 /*TODO: stateblocks */
5220 *PaletteNumber = This->currentPalette;
5221 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5225 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5230 FIXME("(%p) : stub\n", This);
5234 This->softwareVertexProcessing = bSoftware;
5239 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5244 FIXME("(%p) : stub\n", This);
5247 return This->softwareVertexProcessing;
5250 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5251 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5253 IWineD3DSwapChain *swapchain;
5256 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5257 iface, swapchain_idx, raster_status);
5259 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5262 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5266 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5267 IWineD3DSwapChain_Release(swapchain);
5270 WARN("Failed to get raster status, hr %#x.\n", hr);
5277 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5280 if(nSegments != 0.0f) {
5283 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5290 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5295 FIXME("iface %p stub!\n", iface);
5301 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5302 IWineD3DSurface *src_surface, const RECT *src_rect,
5303 IWineD3DSurface *dst_surface, const POINT *dst_point)
5305 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5306 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5308 const struct wined3d_format *src_format;
5309 const struct wined3d_format *dst_format;
5310 const struct wined3d_gl_info *gl_info;
5311 struct wined3d_context *context;
5312 const unsigned char *data;
5313 UINT update_w, update_h;
5314 CONVERT_TYPES convert;
5318 struct wined3d_format format;
5320 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5321 iface, src_surface, wine_dbgstr_rect(src_rect),
5322 dst_surface, wine_dbgstr_point(dst_point));
5324 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5326 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5327 src_surface, dst_surface);
5328 return WINED3DERR_INVALIDCALL;
5331 src_format = src_impl->resource.format;
5332 dst_format = dst_impl->resource.format;
5334 if (src_format->id != dst_format->id)
5336 WARN("Source and destination surfaces should have the same format.\n");
5337 return WINED3DERR_INVALIDCALL;
5340 dst_x = dst_point ? dst_point->x : 0;
5341 dst_y = dst_point ? dst_point->y : 0;
5343 /* This call loads the OpenGL surface directly, instead of copying the
5344 * surface to the destination's sysmem copy. If surface conversion is
5345 * needed, use BltFast instead to copy in sysmem and use regular surface
5347 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5348 if (convert != NO_CONVERSION || format.convert)
5349 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5351 context = context_acquire(This, NULL);
5352 gl_info = context->gl_info;
5355 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5356 checkGLcall("glActiveTextureARB");
5359 /* Make sure the surface is loaded and up to date */
5360 surface_internal_preload(dst_impl, SRGB_RGB);
5361 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5363 src_w = src_impl->currentDesc.Width;
5364 src_h = src_impl->currentDesc.Height;
5365 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5366 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5368 data = IWineD3DSurface_GetData(src_surface);
5369 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5373 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5375 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5376 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5377 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5381 data += (src_rect->top / src_format->block_height) * src_pitch;
5382 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5385 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5386 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5387 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5389 if (row_length == src_pitch)
5391 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5392 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5398 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5399 * can't use the unpack row length like below. */
5400 for (row = 0, y = dst_y; row < row_count; ++row)
5402 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5403 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5404 y += src_format->block_height;
5408 checkGLcall("glCompressedTexSubImage2DARB");
5414 data += src_rect->top * src_w * src_format->byte_count;
5415 data += src_rect->left * src_format->byte_count;
5418 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5419 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5420 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5422 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5423 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5424 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5425 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5426 checkGLcall("glTexSubImage2D");
5430 context_release(context);
5432 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5433 sampler = This->rev_tex_unit_map[0];
5434 if (sampler != WINED3D_UNMAPPED_STAGE)
5436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5442 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5444 struct WineD3DRectPatch *patch;
5445 GLenum old_primitive_type;
5449 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5451 if(!(Handle || pRectPatchInfo)) {
5452 /* TODO: Write a test for the return value, thus the FIXME */
5453 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5454 return WINED3DERR_INVALIDCALL;
5458 i = PATCHMAP_HASHFUNC(Handle);
5460 LIST_FOR_EACH(e, &This->patches[i]) {
5461 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5462 if(patch->Handle == Handle) {
5469 TRACE("Patch does not exist. Creating a new one\n");
5470 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5471 patch->Handle = Handle;
5472 list_add_head(&This->patches[i], &patch->entry);
5474 TRACE("Found existing patch %p\n", patch);
5477 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5478 * attributes we have to tesselate, read back, and draw. This needs a patch
5479 * management structure instance. Create one.
5481 * A possible improvement is to check if a vertex shader is used, and if not directly
5484 FIXME("Drawing an uncached patch. This is slow\n");
5485 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5488 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5489 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5490 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5493 TRACE("Tesselation density or patch info changed, retesselating\n");
5495 if(pRectPatchInfo) {
5496 patch->RectPatchInfo = *pRectPatchInfo;
5498 patch->numSegs[0] = pNumSegs[0];
5499 patch->numSegs[1] = pNumSegs[1];
5500 patch->numSegs[2] = pNumSegs[2];
5501 patch->numSegs[3] = pNumSegs[3];
5503 hr = tesselate_rectpatch(This, patch);
5505 WARN("Patch tesselation failed\n");
5507 /* Do not release the handle to store the params of the patch */
5509 HeapFree(GetProcessHeap(), 0, patch);
5515 This->currentPatch = patch;
5516 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5517 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5518 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5519 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5520 This->currentPatch = NULL;
5522 /* Destroy uncached patches */
5524 HeapFree(GetProcessHeap(), 0, patch->mem);
5525 HeapFree(GetProcessHeap(), 0, patch);
5530 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5531 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5533 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5534 iface, handle, segment_count, patch_info);
5539 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 struct WineD3DRectPatch *patch;
5544 TRACE("(%p) Handle(%d)\n", This, Handle);
5546 i = PATCHMAP_HASHFUNC(Handle);
5547 LIST_FOR_EACH(e, &This->patches[i]) {
5548 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5549 if(patch->Handle == Handle) {
5550 TRACE("Deleting patch %p\n", patch);
5551 list_remove(&patch->entry);
5552 HeapFree(GetProcessHeap(), 0, patch->mem);
5553 HeapFree(GetProcessHeap(), 0, patch);
5558 /* TODO: Write a test for the return value */
5559 FIXME("Attempt to destroy nonexistent patch\n");
5560 return WINED3DERR_INVALIDCALL;
5563 /* Do not call while under the GL lock. */
5564 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5565 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5567 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5569 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5570 iface, surface, wine_dbgstr_rect(rect),
5571 color->r, color->g, color->b, color->a);
5573 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5575 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5576 return WINED3DERR_INVALIDCALL;
5579 return surface_color_fill(s, rect, color);
5582 /* Do not call while under the GL lock. */
5583 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5584 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5586 IWineD3DResource *resource;
5589 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5592 ERR("Failed to get resource, hr %#x\n", hr);
5596 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5598 FIXME("Only supported on surface resources\n");
5599 IWineD3DResource_Release(resource);
5603 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5604 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5606 IWineD3DResource_Release(resource);
5609 /* rendertarget and depth stencil functions */
5610 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5611 DWORD render_target_idx, IWineD3DSurface **render_target)
5613 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5615 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5616 iface, render_target_idx, render_target);
5618 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5620 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5621 return WINED3DERR_INVALIDCALL;
5624 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5625 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5627 TRACE("Returning render target %p.\n", *render_target);
5632 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5633 IWineD3DSurface *front, IWineD3DSurface *back)
5635 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5636 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5637 IWineD3DSwapChainImpl *swapchain;
5640 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5642 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5644 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5648 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5650 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5651 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5652 return WINED3DERR_INVALIDCALL;
5657 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5659 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5660 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5661 return WINED3DERR_INVALIDCALL;
5664 if (!swapchain->back_buffers)
5666 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5667 if (!swapchain->back_buffers)
5669 ERR("Failed to allocate back buffer array memory.\n");
5670 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5671 return E_OUTOFMEMORY;
5676 if (swapchain->front_buffer != front_impl)
5678 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5680 if (swapchain->front_buffer)
5681 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5682 swapchain->front_buffer = front_impl;
5685 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5688 if (swapchain->back_buffers[0] != back_impl)
5690 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5692 if (swapchain->back_buffers[0])
5693 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5694 swapchain->back_buffers[0] = back_impl;
5698 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5699 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5700 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5701 swapchain->presentParms.BackBufferCount = 1;
5703 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5707 swapchain->presentParms.BackBufferCount = 0;
5708 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5709 swapchain->back_buffers = NULL;
5713 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5717 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5719 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5721 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5723 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5724 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5725 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5726 IWineD3DSurface_AddRef(*depth_stencil);
5731 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5732 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5734 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5735 IWineD3DSurfaceImpl *prev;
5737 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5738 iface, render_target_idx, render_target, set_viewport);
5740 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5742 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5743 return WINED3DERR_INVALIDCALL;
5746 prev = device->render_targets[render_target_idx];
5747 if (render_target == (IWineD3DSurface *)prev)
5749 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5753 /* Render target 0 can't be set to NULL. */
5754 if (!render_target && !render_target_idx)
5756 WARN("Trying to set render target 0 to NULL.\n");
5757 return WINED3DERR_INVALIDCALL;
5760 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5762 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5763 return WINED3DERR_INVALIDCALL;
5766 if (render_target) IWineD3DSurface_AddRef(render_target);
5767 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5768 /* Release after the assignment, to prevent device_resource_released()
5769 * from seeing the surface as still in use. */
5770 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5772 /* Render target 0 is special. */
5773 if (!render_target_idx && set_viewport)
5775 /* Set the viewport and scissor rectangles, if requested. Tests show
5776 * that stateblock recording is ignored, the change goes directly
5777 * into the primary stateblock. */
5778 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5779 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5780 device->stateBlock->state.viewport.X = 0;
5781 device->stateBlock->state.viewport.Y = 0;
5782 device->stateBlock->state.viewport.MaxZ = 1.0f;
5783 device->stateBlock->state.viewport.MinZ = 0.0f;
5784 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5786 device->stateBlock->state.scissor_rect.top = 0;
5787 device->stateBlock->state.scissor_rect.left = 0;
5788 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5789 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5790 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5796 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5799 IWineD3DSurfaceImpl *tmp;
5801 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5803 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5805 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5809 if (This->depth_stencil)
5811 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5812 || This->depth_stencil->Flags & SFLAG_DISCARD)
5814 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5815 This->depth_stencil->currentDesc.Width,
5816 This->depth_stencil->currentDesc.Height);
5817 if (This->depth_stencil == This->onscreen_depth_stencil)
5819 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5820 This->onscreen_depth_stencil = NULL;
5825 tmp = This->depth_stencil;
5826 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5827 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5828 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5830 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5832 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5841 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5842 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5845 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5846 WINED3DLOCKED_RECT lockedRect;
5848 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5849 iface, XHotSpot, YHotSpot, cursor_image);
5851 /* some basic validation checks */
5852 if (This->cursorTexture)
5854 struct wined3d_context *context = context_acquire(This, NULL);
5856 glDeleteTextures(1, &This->cursorTexture);
5858 context_release(context);
5859 This->cursorTexture = 0;
5862 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5863 This->haveHardwareCursor = TRUE;
5865 This->haveHardwareCursor = FALSE;
5869 WINED3DLOCKED_RECT rect;
5871 /* MSDN: Cursor must be A8R8G8B8 */
5872 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5874 WARN("surface %p has an invalid format.\n", cursor_image);
5875 return WINED3DERR_INVALIDCALL;
5878 /* MSDN: Cursor must be smaller than the display mode */
5879 if (s->currentDesc.Width > This->ddraw_width
5880 || s->currentDesc.Height > This->ddraw_height)
5882 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5883 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5884 return WINED3DERR_INVALIDCALL;
5887 if (!This->haveHardwareCursor) {
5888 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5890 /* Do not store the surface's pointer because the application may
5891 * release it after setting the cursor image. Windows doesn't
5892 * addref the set surface, so we can't do this either without
5893 * creating circular refcount dependencies. Copy out the gl texture
5896 This->cursorWidth = s->currentDesc.Width;
5897 This->cursorHeight = s->currentDesc.Height;
5898 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5900 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5901 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5902 struct wined3d_context *context;
5903 char *mem, *bits = rect.pBits;
5904 GLint intfmt = format->glInternal;
5905 GLint gl_format = format->glFormat;
5906 GLint type = format->glType;
5907 INT height = This->cursorHeight;
5908 INT width = This->cursorWidth;
5909 INT bpp = format->byte_count;
5913 /* Reformat the texture memory (pitch and width can be
5915 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5916 for(i = 0; i < height; i++)
5917 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5918 IWineD3DSurface_UnlockRect(cursor_image);
5920 context = context_acquire(This, NULL);
5924 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5926 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5927 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5930 /* Make sure that a proper texture unit is selected */
5931 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5932 checkGLcall("glActiveTextureARB");
5933 sampler = This->rev_tex_unit_map[0];
5934 if (sampler != WINED3D_UNMAPPED_STAGE)
5936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5938 /* Create a new cursor texture */
5939 glGenTextures(1, &This->cursorTexture);
5940 checkGLcall("glGenTextures");
5941 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5942 checkGLcall("glBindTexture");
5943 /* Copy the bitmap memory into the cursor texture */
5944 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5945 HeapFree(GetProcessHeap(), 0, mem);
5946 checkGLcall("glTexImage2D");
5948 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5950 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5951 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5956 context_release(context);
5960 FIXME("A cursor texture was not returned.\n");
5961 This->cursorTexture = 0;
5966 /* Draw a hardware cursor */
5967 ICONINFO cursorInfo;
5969 /* Create and clear maskBits because it is not needed for
5970 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5972 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5973 (s->currentDesc.Width * s->currentDesc.Height / 8));
5974 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5975 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5976 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5978 cursorInfo.fIcon = FALSE;
5979 cursorInfo.xHotspot = XHotSpot;
5980 cursorInfo.yHotspot = YHotSpot;
5981 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5982 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5983 IWineD3DSurface_UnlockRect(cursor_image);
5984 /* Create our cursor and clean up. */
5985 cursor = CreateIconIndirect(&cursorInfo);
5987 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5988 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5989 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5990 This->hardwareCursor = cursor;
5991 HeapFree(GetProcessHeap(), 0, maskBits);
5995 This->xHotSpot = XHotSpot;
5996 This->yHotSpot = YHotSpot;
6000 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6002 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6004 This->xScreenSpace = XScreenSpace;
6005 This->yScreenSpace = YScreenSpace;
6011 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6013 BOOL oldVisible = This->bCursorVisible;
6016 TRACE("(%p) : visible(%d)\n", This, bShow);
6019 * When ShowCursor is first called it should make the cursor appear at the OS's last
6020 * known cursor position. Because of this, some applications just repetitively call
6021 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6024 This->xScreenSpace = pt.x;
6025 This->yScreenSpace = pt.y;
6027 if (This->haveHardwareCursor) {
6028 This->bCursorVisible = bShow;
6030 SetCursor(This->hardwareCursor);
6036 if (This->cursorTexture)
6037 This->bCursorVisible = bShow;
6043 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6044 TRACE("checking resource %p for eviction\n", resource);
6045 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6046 TRACE("Evicting %p\n", resource);
6047 IWineD3DResource_UnLoad(resource);
6049 IWineD3DResource_Release(resource);
6053 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6055 TRACE("iface %p.\n", iface);
6057 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6058 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6059 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6064 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6066 IWineD3DDeviceImpl *device = surface->resource.device;
6067 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6069 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6070 if(surface->Flags & SFLAG_DIBSECTION) {
6071 /* Release the DC */
6072 SelectObject(surface->hDC, surface->dib.holdbitmap);
6073 DeleteDC(surface->hDC);
6074 /* Release the DIB section */
6075 DeleteObject(surface->dib.DIBsection);
6076 surface->dib.bitmap_data = NULL;
6077 surface->resource.allocatedMemory = NULL;
6078 surface->Flags &= ~SFLAG_DIBSECTION;
6080 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6081 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6082 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6083 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6085 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6086 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6088 surface->pow2Width = surface->pow2Height = 1;
6089 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6090 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6093 if (surface->texture_name)
6095 struct wined3d_context *context = context_acquire(device, NULL);
6097 glDeleteTextures(1, &surface->texture_name);
6099 context_release(context);
6100 surface->texture_name = 0;
6101 surface->Flags &= ~SFLAG_CLIENT;
6103 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6104 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6105 surface->Flags |= SFLAG_NONPOW2;
6107 surface->Flags &= ~SFLAG_NONPOW2;
6109 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6110 surface->resource.allocatedMemory = NULL;
6111 surface->resource.heapMemory = NULL;
6112 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6114 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6116 if (!surface_init_sysmem(surface))
6118 return E_OUTOFMEMORY;
6123 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6124 TRACE("Unloading resource %p\n", resource);
6125 IWineD3DResource_UnLoad(resource);
6126 IWineD3DResource_Release(resource);
6130 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6133 WINED3DDISPLAYMODE m;
6136 /* All Windowed modes are supported, as is leaving the current mode */
6137 if(pp->Windowed) return TRUE;
6138 if(!pp->BackBufferWidth) return TRUE;
6139 if(!pp->BackBufferHeight) return TRUE;
6141 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6142 for(i = 0; i < count; i++) {
6143 memset(&m, 0, sizeof(m));
6144 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6146 ERR("EnumAdapterModes failed\n");
6148 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6149 /* Mode found, it is supported */
6153 /* Mode not found -> not supported */
6157 /* Do not call while under the GL lock. */
6158 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6161 const struct wined3d_gl_info *gl_info;
6162 struct wined3d_context *context;
6163 IWineD3DBaseShaderImpl *shader;
6165 context = context_acquire(This, NULL);
6166 gl_info = context->gl_info;
6168 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6169 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6170 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6174 if(This->depth_blt_texture) {
6175 glDeleteTextures(1, &This->depth_blt_texture);
6176 This->depth_blt_texture = 0;
6178 if (This->depth_blt_rb) {
6179 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6180 This->depth_blt_rb = 0;
6181 This->depth_blt_rb_w = 0;
6182 This->depth_blt_rb_h = 0;
6186 This->blitter->free_private(iface);
6187 This->frag_pipe->free_private(iface);
6188 This->shader_backend->shader_free_private(iface);
6189 destroy_dummy_textures(This, gl_info);
6191 context_release(context);
6193 while (This->numContexts)
6195 context_destroy(This, This->contexts[0]);
6197 HeapFree(GetProcessHeap(), 0, swapchain->context);
6198 swapchain->context = NULL;
6199 swapchain->num_contexts = 0;
6202 /* Do not call while under the GL lock. */
6203 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6206 struct wined3d_context *context;
6208 IWineD3DSurfaceImpl *target;
6210 /* Recreate the primary swapchain's context */
6211 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6212 if (!swapchain->context)
6214 ERR("Failed to allocate memory for swapchain context array.\n");
6215 return E_OUTOFMEMORY;
6218 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6219 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6221 WARN("Failed to create context.\n");
6222 HeapFree(GetProcessHeap(), 0, swapchain->context);
6226 swapchain->context[0] = context;
6227 swapchain->num_contexts = 1;
6228 create_dummy_textures(This);
6229 context_release(context);
6231 hr = This->shader_backend->shader_alloc_private(iface);
6234 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6238 hr = This->frag_pipe->alloc_private(iface);
6241 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6242 This->shader_backend->shader_free_private(iface);
6246 hr = This->blitter->alloc_private(iface);
6249 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6250 This->frag_pipe->free_private(iface);
6251 This->shader_backend->shader_free_private(iface);
6258 context_acquire(This, NULL);
6259 destroy_dummy_textures(This, context->gl_info);
6260 context_release(context);
6261 context_destroy(This, context);
6262 HeapFree(GetProcessHeap(), 0, swapchain->context);
6263 swapchain->num_contexts = 0;
6267 /* Do not call while under the GL lock. */
6268 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6269 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6272 IWineD3DSwapChainImpl *swapchain;
6274 BOOL DisplayModeChanged = FALSE;
6275 WINED3DDISPLAYMODE mode;
6276 TRACE("(%p)\n", This);
6278 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6280 ERR("Failed to get the first implicit swapchain\n");
6284 if(!is_display_mode_supported(This, pPresentationParameters)) {
6285 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6286 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6287 pPresentationParameters->BackBufferHeight);
6288 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6289 return WINED3DERR_INVALIDCALL;
6292 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6293 * on an existing gl context, so there's no real need for recreation.
6295 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6297 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6299 TRACE("New params:\n");
6300 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6301 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6302 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6303 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6304 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6305 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6306 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6307 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6308 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6309 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6310 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6311 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6312 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6314 /* No special treatment of these parameters. Just store them */
6315 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6316 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6317 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6318 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6320 /* What to do about these? */
6321 if (pPresentationParameters->BackBufferCount
6322 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6323 ERR("Cannot change the back buffer count yet\n");
6325 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6326 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6327 ERR("Cannot change the back buffer format yet\n");
6330 if (pPresentationParameters->hDeviceWindow
6331 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6332 ERR("Cannot change the device window yet\n");
6334 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6338 TRACE("Creating the depth stencil buffer\n");
6340 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6341 pPresentationParameters->BackBufferWidth,
6342 pPresentationParameters->BackBufferHeight,
6343 pPresentationParameters->AutoDepthStencilFormat,
6344 pPresentationParameters->MultiSampleType,
6345 pPresentationParameters->MultiSampleQuality,
6347 (IWineD3DSurface **)&This->auto_depth_stencil);
6350 ERR("Failed to create the depth stencil buffer\n");
6351 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6352 return WINED3DERR_INVALIDCALL;
6356 if (This->onscreen_depth_stencil)
6358 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6359 This->onscreen_depth_stencil = NULL;
6362 /* Reset the depth stencil */
6363 if (pPresentationParameters->EnableAutoDepthStencil)
6364 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6366 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6368 TRACE("Resetting stateblock\n");
6369 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6370 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6372 delete_opengl_contexts(iface, swapchain);
6374 if(pPresentationParameters->Windowed) {
6375 mode.Width = swapchain->orig_width;
6376 mode.Height = swapchain->orig_height;
6377 mode.RefreshRate = 0;
6378 mode.Format = swapchain->presentParms.BackBufferFormat;
6380 mode.Width = pPresentationParameters->BackBufferWidth;
6381 mode.Height = pPresentationParameters->BackBufferHeight;
6382 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6383 mode.Format = swapchain->presentParms.BackBufferFormat;
6386 /* Should Width == 800 && Height == 0 set 800x600? */
6387 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6388 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6389 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6393 if(!pPresentationParameters->Windowed) {
6394 DisplayModeChanged = TRUE;
6396 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6397 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6399 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6402 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6406 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6408 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6411 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6415 if (This->auto_depth_stencil)
6417 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6420 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6426 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6427 || DisplayModeChanged)
6429 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6431 if (!pPresentationParameters->Windowed)
6433 if(swapchain->presentParms.Windowed) {
6434 /* switch from windowed to fs */
6435 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6436 pPresentationParameters->BackBufferHeight);
6438 /* Fullscreen -> fullscreen mode change */
6439 MoveWindow(swapchain->device_window, 0, 0,
6440 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6444 else if (!swapchain->presentParms.Windowed)
6446 /* Fullscreen -> windowed switch */
6447 swapchain_restore_fullscreen_window(swapchain);
6449 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6450 } else if(!pPresentationParameters->Windowed) {
6451 DWORD style = This->style, exStyle = This->exStyle;
6452 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6453 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6454 * Reset to clear up their mess. Guild Wars also loses the device during that.
6458 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6459 pPresentationParameters->BackBufferHeight);
6460 This->style = style;
6461 This->exStyle = exStyle;
6464 /* Note: No parent needed for initial internal stateblock */
6465 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6466 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6467 else TRACE("Created stateblock %p\n", This->stateBlock);
6468 This->updateStateBlock = This->stateBlock;
6469 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6471 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6473 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6476 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6479 GetClientRect(swapchain->win_handle, &client_rect);
6481 if(!swapchain->presentParms.BackBufferCount)
6483 TRACE("Single buffered rendering\n");
6484 swapchain->render_to_fbo = FALSE;
6486 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6487 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6489 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6490 swapchain->presentParms.BackBufferWidth,
6491 swapchain->presentParms.BackBufferHeight,
6492 client_rect.right, client_rect.bottom);
6493 swapchain->render_to_fbo = TRUE;
6497 TRACE("Rendering directly to GL_BACK\n");
6498 swapchain->render_to_fbo = FALSE;
6502 hr = create_primary_opengl_context(iface, swapchain);
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6505 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6511 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6513 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6515 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6521 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6523 TRACE("(%p) : pParameters %p\n", This, pParameters);
6525 *pParameters = This->createParms;
6529 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6530 IWineD3DSwapChain *swapchain;
6532 TRACE("Relaying to swapchain\n");
6534 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6535 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6536 IWineD3DSwapChain_Release(swapchain);
6540 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6541 IWineD3DSwapChain *swapchain;
6543 TRACE("Relaying to swapchain\n");
6545 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6546 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6547 IWineD3DSwapChain_Release(swapchain);
6552 /** ********************************************************
6553 * Notification functions
6554 ** ********************************************************/
6555 /** This function must be called in the release of a resource when ref == 0,
6556 * the contents of resource must still be correct,
6557 * any handles to other resource held by the caller must be closed
6558 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6559 *****************************************************/
6560 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6562 TRACE("(%p) : Adding resource %p\n", This, resource);
6564 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6567 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6569 TRACE("(%p) : Removing resource %p\n", This, resource);
6571 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6574 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6576 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6579 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6581 context_resource_released(device, resource, type);
6585 case WINED3DRTYPE_SURFACE:
6586 if (!device->d3d_initialized) break;
6588 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6590 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6592 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6593 device->render_targets[i] = NULL;
6597 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6599 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6600 device->depth_stencil = NULL;
6604 case WINED3DRTYPE_TEXTURE:
6605 case WINED3DRTYPE_CUBETEXTURE:
6606 case WINED3DRTYPE_VOLUMETEXTURE:
6607 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6609 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6611 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6612 resource, device->stateBlock, i);
6613 device->stateBlock->state.textures[i] = NULL;
6616 if (device->updateStateBlock != device->stateBlock
6617 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6619 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6620 resource, device->updateStateBlock, i);
6621 device->updateStateBlock->state.textures[i] = NULL;
6626 case WINED3DRTYPE_BUFFER:
6627 for (i = 0; i < MAX_STREAMS; ++i)
6629 if (device->stateBlock
6630 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6632 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6633 resource, device->stateBlock, i);
6634 device->stateBlock->state.streams[i].buffer = NULL;
6637 if (device->updateStateBlock != device->stateBlock
6638 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6640 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6641 resource, device->updateStateBlock, i);
6642 device->updateStateBlock->state.streams[i].buffer = NULL;
6647 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6649 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6650 resource, device->stateBlock);
6651 device->stateBlock->state.index_buffer = NULL;
6654 if (device->updateStateBlock != device->stateBlock
6655 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6657 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6658 resource, device->updateStateBlock);
6659 device->updateStateBlock->state.index_buffer = NULL;
6667 /* Remove the resource from the resourceStore */
6668 device_resource_remove(device, resource);
6670 TRACE("Resource released.\n");
6673 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6675 IWineD3DResourceImpl *resource, *cursor;
6677 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6679 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6680 TRACE("enumerating resource %p\n", resource);
6681 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6682 ret = pCallback((IWineD3DResource *) resource, pData);
6683 if(ret == S_FALSE) {
6684 TRACE("Canceling enumeration\n");
6691 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6694 IWineD3DResourceImpl *resource;
6696 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6698 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6699 if (type == WINED3DRTYPE_SURFACE)
6701 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6703 TRACE("Found surface %p for dc %p.\n", resource, dc);
6704 *surface = (IWineD3DSurface *)resource;
6710 return WINED3DERR_INVALIDCALL;
6713 /**********************************************************
6714 * IWineD3DDevice VTbl follows
6715 **********************************************************/
6717 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6719 /*** IUnknown methods ***/
6720 IWineD3DDeviceImpl_QueryInterface,
6721 IWineD3DDeviceImpl_AddRef,
6722 IWineD3DDeviceImpl_Release,
6723 /*** IWineD3DDevice methods ***/
6724 /*** Creation methods**/
6725 IWineD3DDeviceImpl_CreateBuffer,
6726 IWineD3DDeviceImpl_CreateVertexBuffer,
6727 IWineD3DDeviceImpl_CreateIndexBuffer,
6728 IWineD3DDeviceImpl_CreateStateBlock,
6729 IWineD3DDeviceImpl_CreateSurface,
6730 IWineD3DDeviceImpl_CreateRendertargetView,
6731 IWineD3DDeviceImpl_CreateTexture,
6732 IWineD3DDeviceImpl_CreateVolumeTexture,
6733 IWineD3DDeviceImpl_CreateVolume,
6734 IWineD3DDeviceImpl_CreateCubeTexture,
6735 IWineD3DDeviceImpl_CreateQuery,
6736 IWineD3DDeviceImpl_CreateSwapChain,
6737 IWineD3DDeviceImpl_CreateVertexDeclaration,
6738 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6739 IWineD3DDeviceImpl_CreateVertexShader,
6740 IWineD3DDeviceImpl_CreateGeometryShader,
6741 IWineD3DDeviceImpl_CreatePixelShader,
6742 IWineD3DDeviceImpl_CreatePalette,
6743 /*** Odd functions **/
6744 IWineD3DDeviceImpl_Init3D,
6745 IWineD3DDeviceImpl_InitGDI,
6746 IWineD3DDeviceImpl_Uninit3D,
6747 IWineD3DDeviceImpl_UninitGDI,
6748 IWineD3DDeviceImpl_SetMultithreaded,
6749 IWineD3DDeviceImpl_EvictManagedResources,
6750 IWineD3DDeviceImpl_GetAvailableTextureMem,
6751 IWineD3DDeviceImpl_GetBackBuffer,
6752 IWineD3DDeviceImpl_GetCreationParameters,
6753 IWineD3DDeviceImpl_GetDeviceCaps,
6754 IWineD3DDeviceImpl_GetDirect3D,
6755 IWineD3DDeviceImpl_GetDisplayMode,
6756 IWineD3DDeviceImpl_SetDisplayMode,
6757 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6758 IWineD3DDeviceImpl_GetRasterStatus,
6759 IWineD3DDeviceImpl_GetSwapChain,
6760 IWineD3DDeviceImpl_Reset,
6761 IWineD3DDeviceImpl_SetDialogBoxMode,
6762 IWineD3DDeviceImpl_SetCursorProperties,
6763 IWineD3DDeviceImpl_SetCursorPosition,
6764 IWineD3DDeviceImpl_ShowCursor,
6765 /*** Getters and setters **/
6766 IWineD3DDeviceImpl_SetClipPlane,
6767 IWineD3DDeviceImpl_GetClipPlane,
6768 IWineD3DDeviceImpl_SetClipStatus,
6769 IWineD3DDeviceImpl_GetClipStatus,
6770 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6771 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6772 IWineD3DDeviceImpl_SetDepthStencilSurface,
6773 IWineD3DDeviceImpl_GetDepthStencilSurface,
6774 IWineD3DDeviceImpl_SetGammaRamp,
6775 IWineD3DDeviceImpl_GetGammaRamp,
6776 IWineD3DDeviceImpl_SetIndexBuffer,
6777 IWineD3DDeviceImpl_GetIndexBuffer,
6778 IWineD3DDeviceImpl_SetBaseVertexIndex,
6779 IWineD3DDeviceImpl_GetBaseVertexIndex,
6780 IWineD3DDeviceImpl_SetLight,
6781 IWineD3DDeviceImpl_GetLight,
6782 IWineD3DDeviceImpl_SetLightEnable,
6783 IWineD3DDeviceImpl_GetLightEnable,
6784 IWineD3DDeviceImpl_SetMaterial,
6785 IWineD3DDeviceImpl_GetMaterial,
6786 IWineD3DDeviceImpl_SetNPatchMode,
6787 IWineD3DDeviceImpl_GetNPatchMode,
6788 IWineD3DDeviceImpl_SetPaletteEntries,
6789 IWineD3DDeviceImpl_GetPaletteEntries,
6790 IWineD3DDeviceImpl_SetPixelShader,
6791 IWineD3DDeviceImpl_GetPixelShader,
6792 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6793 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6794 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6795 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6796 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6797 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6798 IWineD3DDeviceImpl_SetRenderState,
6799 IWineD3DDeviceImpl_GetRenderState,
6800 IWineD3DDeviceImpl_SetRenderTarget,
6801 IWineD3DDeviceImpl_GetRenderTarget,
6802 IWineD3DDeviceImpl_SetFrontBackBuffers,
6803 IWineD3DDeviceImpl_SetSamplerState,
6804 IWineD3DDeviceImpl_GetSamplerState,
6805 IWineD3DDeviceImpl_SetScissorRect,
6806 IWineD3DDeviceImpl_GetScissorRect,
6807 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6808 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6809 IWineD3DDeviceImpl_SetStreamSource,
6810 IWineD3DDeviceImpl_GetStreamSource,
6811 IWineD3DDeviceImpl_SetStreamSourceFreq,
6812 IWineD3DDeviceImpl_GetStreamSourceFreq,
6813 IWineD3DDeviceImpl_SetTexture,
6814 IWineD3DDeviceImpl_GetTexture,
6815 IWineD3DDeviceImpl_SetTextureStageState,
6816 IWineD3DDeviceImpl_GetTextureStageState,
6817 IWineD3DDeviceImpl_SetTransform,
6818 IWineD3DDeviceImpl_GetTransform,
6819 IWineD3DDeviceImpl_SetVertexDeclaration,
6820 IWineD3DDeviceImpl_GetVertexDeclaration,
6821 IWineD3DDeviceImpl_SetVertexShader,
6822 IWineD3DDeviceImpl_GetVertexShader,
6823 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6824 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6825 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6826 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6827 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6828 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6829 IWineD3DDeviceImpl_SetViewport,
6830 IWineD3DDeviceImpl_GetViewport,
6831 IWineD3DDeviceImpl_MultiplyTransform,
6832 IWineD3DDeviceImpl_ValidateDevice,
6833 IWineD3DDeviceImpl_ProcessVertices,
6834 /*** State block ***/
6835 IWineD3DDeviceImpl_BeginStateBlock,
6836 IWineD3DDeviceImpl_EndStateBlock,
6837 /*** Scene management ***/
6838 IWineD3DDeviceImpl_BeginScene,
6839 IWineD3DDeviceImpl_EndScene,
6840 IWineD3DDeviceImpl_Present,
6841 IWineD3DDeviceImpl_Clear,
6842 IWineD3DDeviceImpl_ClearRendertargetView,
6844 IWineD3DDeviceImpl_SetPrimitiveType,
6845 IWineD3DDeviceImpl_GetPrimitiveType,
6846 IWineD3DDeviceImpl_DrawPrimitive,
6847 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6848 IWineD3DDeviceImpl_DrawPrimitiveUP,
6849 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6850 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6851 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6852 IWineD3DDeviceImpl_DrawRectPatch,
6853 IWineD3DDeviceImpl_DrawTriPatch,
6854 IWineD3DDeviceImpl_DeletePatch,
6855 IWineD3DDeviceImpl_ColorFill,
6856 IWineD3DDeviceImpl_UpdateTexture,
6857 IWineD3DDeviceImpl_UpdateSurface,
6858 IWineD3DDeviceImpl_GetFrontBufferData,
6859 /*** object tracking ***/
6860 IWineD3DDeviceImpl_EnumResources,
6861 IWineD3DDeviceImpl_GetSurfaceFromDC,
6862 IWineD3DDeviceImpl_AcquireFocusWindow,
6863 IWineD3DDeviceImpl_ReleaseFocusWindow,
6866 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6867 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6868 IWineD3DDeviceParent *device_parent)
6870 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6871 const struct fragment_pipeline *fragment_pipeline;
6872 struct shader_caps shader_caps;
6873 struct fragment_caps ffp_caps;
6874 WINED3DDISPLAYMODE mode;
6878 device->lpVtbl = &IWineD3DDevice_Vtbl;
6880 device->wined3d = (IWineD3D *)wined3d;
6881 IWineD3D_AddRef(device->wined3d);
6882 device->adapter = wined3d->adapter_count ? adapter : NULL;
6883 device->device_parent = device_parent;
6884 list_init(&device->resources);
6885 list_init(&device->shaders);
6887 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6888 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6890 /* Get the initial screen setup for ddraw. */
6891 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6894 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6895 IWineD3D_Release(device->wined3d);
6898 device->ddraw_width = mode.Width;
6899 device->ddraw_height = mode.Height;
6900 device->ddraw_format = mode.Format;
6902 /* Save the creation parameters. */
6903 device->createParms.AdapterOrdinal = adapter_idx;
6904 device->createParms.DeviceType = device_type;
6905 device->createParms.hFocusWindow = focus_window;
6906 device->createParms.BehaviorFlags = flags;
6908 device->devType = device_type;
6909 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6911 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6912 device->shader_backend = adapter->shader_backend;
6914 if (device->shader_backend)
6916 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6917 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6918 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6919 device->vs_clipping = shader_caps.VSClipping;
6921 fragment_pipeline = adapter->fragment_pipe;
6922 device->frag_pipe = fragment_pipeline;
6923 if (fragment_pipeline)
6925 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6926 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6928 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6929 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6932 ERR("Failed to compile state table, hr %#x.\n", hr);
6933 IWineD3D_Release(device->wined3d);
6937 device->blitter = adapter->blitter;
6943 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6944 DWORD rep = This->StateTable[state].representative;
6945 struct wined3d_context *context;
6950 for(i = 0; i < This->numContexts; i++) {
6951 context = This->contexts[i];
6952 if(isStateDirty(context, rep)) continue;
6954 context->dirtyArray[context->numDirtyEntries++] = rep;
6955 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6956 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6957 context->isStateDirty[idx] |= (1 << shift);
6961 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6963 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6964 *width = context->current_rt->pow2Width;
6965 *height = context->current_rt->pow2Height;
6968 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6970 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6971 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6972 * current context's drawable, which is the size of the back buffer of the swapchain
6973 * the active context belongs to. */
6974 *width = swapchain->presentParms.BackBufferWidth;
6975 *height = swapchain->presentParms.BackBufferHeight;
6978 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6979 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6981 if (device->filter_messages)
6983 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6984 window, message, wparam, lparam);
6985 return DefWindowProcW(window, message, wparam, lparam);
6988 if (message == WM_DESTROY)
6990 TRACE("unregister window %p.\n", window);
6991 wined3d_unregister_window(window);
6993 if (device->focus_window == window) device->focus_window = NULL;
6994 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6997 return CallWindowProcW(proc, window, message, wparam, lparam);