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 const struct wined3d_state *state = &device->stateBlock->state;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
436 device->useDrawStridedSlow = FALSE;
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1114 ERR("Out of memory\n");
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1183 ERR("Out of memory\n");
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1314 TRACE("Swapchain out of range\n");
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 *ppVertexElements = state.elements;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1517 if (This->vs_selected_mode == SHADER_NONE)
1518 return WINED3DERR_INVALIDCALL;
1520 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1523 ERR("Failed to allocate shader memory.\n");
1524 return E_OUTOFMEMORY;
1527 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1530 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1531 HeapFree(GetProcessHeap(), 0, object);
1535 TRACE("Created vertex shader %p.\n", object);
1536 *ppVertexShader = (IWineD3DVertexShader *)object;
1541 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1542 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1543 void *parent, const struct wined3d_parent_ops *parent_ops,
1544 IWineD3DGeometryShader **shader)
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 struct wined3d_geometryshader *object;
1550 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1553 ERR("Failed to allocate shader memory.\n");
1554 return E_OUTOFMEMORY;
1557 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1560 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1561 HeapFree(GetProcessHeap(), 0, object);
1565 TRACE("Created geometry shader %p.\n", object);
1566 *shader = (IWineD3DGeometryShader *)object;
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1572 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1573 void *parent, const struct wined3d_parent_ops *parent_ops,
1574 IWineD3DPixelShader **ppPixelShader)
1576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1577 IWineD3DPixelShaderImpl *object;
1580 if (This->ps_selected_mode == SHADER_NONE)
1581 return WINED3DERR_INVALIDCALL;
1583 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1586 ERR("Failed to allocate shader memory.\n");
1587 return E_OUTOFMEMORY;
1590 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1593 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1594 HeapFree(GetProcessHeap(), 0, object);
1598 TRACE("Created pixel shader %p.\n", object);
1599 *ppPixelShader = (IWineD3DPixelShader *)object;
1604 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1605 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1608 IWineD3DPaletteImpl *object;
1611 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1612 iface, Flags, PalEnt, Palette, parent);
1614 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1617 ERR("Failed to allocate palette memory.\n");
1618 return E_OUTOFMEMORY;
1621 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1624 WARN("Failed to initialize palette, hr %#x.\n", hr);
1625 HeapFree(GetProcessHeap(), 0, object);
1629 TRACE("Created palette %p.\n", object);
1630 *Palette = (IWineD3DPalette *)object;
1635 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1639 HDC dcb = NULL, dcs = NULL;
1640 WINEDDCOLORKEY colorkey;
1642 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1645 GetObjectA(hbm, sizeof(BITMAP), &bm);
1646 dcb = CreateCompatibleDC(NULL);
1648 SelectObject(dcb, hbm);
1652 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1653 * couldn't be loaded
1655 memset(&bm, 0, sizeof(bm));
1660 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1661 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1662 &wined3d_null_parent_ops, &This->logo_surface);
1665 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1681 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1755 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1757 TRACE("iface %p, window %p.\n", iface, window);
1759 if (!wined3d_register_window(window, device))
1761 ERR("Failed to register window %p.\n", window);
1765 device->focus_window = window;
1766 SetForegroundWindow(window);
1771 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1775 TRACE("iface %p.\n", iface);
1777 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1778 device->focus_window = NULL;
1781 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1782 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1785 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1786 IWineD3DSwapChainImpl *swapchain = NULL;
1787 struct wined3d_context *context;
1792 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1794 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1795 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1797 TRACE("(%p) : Creating stateblock\n", This);
1798 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1801 WARN("Failed to create stateblock\n");
1804 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1805 This->updateStateBlock = This->stateBlock;
1806 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1808 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1809 sizeof(*This->render_targets) * gl_info->limits.buffers);
1811 This->NumberOfPalettes = 1;
1812 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1813 if (!This->palettes || !This->render_targets)
1815 ERR("Out of memory!\n");
1819 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1820 if(!This->palettes[0]) {
1821 ERR("Out of memory!\n");
1825 for (i = 0; i < 256; ++i) {
1826 This->palettes[0][i].peRed = 0xFF;
1827 This->palettes[0][i].peGreen = 0xFF;
1828 This->palettes[0][i].peBlue = 0xFF;
1829 This->palettes[0][i].peFlags = 0xFF;
1831 This->currentPalette = 0;
1833 /* Initialize the texture unit mapping to a 1:1 mapping */
1834 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1836 if (state < gl_info->limits.fragment_samplers)
1838 This->texUnitMap[state] = state;
1839 This->rev_tex_unit_map[state] = state;
1841 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1842 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1846 /* Setup the implicit swapchain. This also initializes a context. */
1847 TRACE("Creating implicit swapchain\n");
1848 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1849 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1852 WARN("Failed to create implicit swapchain\n");
1856 This->NumberOfSwapChains = 1;
1857 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1858 if(!This->swapchains) {
1859 ERR("Out of memory!\n");
1862 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1864 if (swapchain->back_buffers && swapchain->back_buffers[0])
1866 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1867 This->render_targets[0] = swapchain->back_buffers[0];
1871 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1872 This->render_targets[0] = swapchain->front_buffer;
1874 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1876 /* Depth Stencil support */
1877 This->depth_stencil = This->auto_depth_stencil;
1878 if (This->depth_stencil)
1879 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1881 hr = This->shader_backend->shader_alloc_private(iface);
1883 TRACE("Shader private data couldn't be allocated\n");
1886 hr = This->frag_pipe->alloc_private(iface);
1888 TRACE("Fragment pipeline private data couldn't be allocated\n");
1891 hr = This->blitter->alloc_private(iface);
1893 TRACE("Blitter private data couldn't be allocated\n");
1897 /* Set up some starting GL setup */
1899 /* Setup all the devices defaults */
1900 stateblock_init_default_state(This->stateBlock);
1902 context = context_acquire(This, swapchain->front_buffer);
1904 create_dummy_textures(This);
1908 /* Initialize the current view state */
1909 This->view_ident = 1;
1910 This->contexts[0]->last_was_rhw = 0;
1911 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1912 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1914 switch(wined3d_settings.offscreen_rendering_mode) {
1916 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1919 case ORM_BACKBUFFER:
1921 if (context_get_current()->aux_buffers > 0)
1923 TRACE("Using auxilliary buffer for offscreen rendering\n");
1924 This->offscreenBuffer = GL_AUX0;
1926 TRACE("Using back buffer for offscreen rendering\n");
1927 This->offscreenBuffer = GL_BACK;
1932 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1935 context_release(context);
1937 /* Clear the screen */
1938 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1939 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1942 This->d3d_initialized = TRUE;
1944 if(wined3d_settings.logo) {
1945 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1947 This->highest_dirty_ps_const = 0;
1948 This->highest_dirty_vs_const = 0;
1952 HeapFree(GetProcessHeap(), 0, This->render_targets);
1953 HeapFree(GetProcessHeap(), 0, This->swapchains);
1954 This->NumberOfSwapChains = 0;
1955 if(This->palettes) {
1956 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1957 HeapFree(GetProcessHeap(), 0, This->palettes);
1959 This->NumberOfPalettes = 0;
1961 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1963 if(This->stateBlock) {
1964 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1965 This->stateBlock = NULL;
1967 if (This->blit_priv) {
1968 This->blitter->free_private(iface);
1970 if (This->fragment_priv) {
1971 This->frag_pipe->free_private(iface);
1973 if (This->shader_priv) {
1974 This->shader_backend->shader_free_private(iface);
1979 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1980 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1983 IWineD3DSwapChainImpl *swapchain = NULL;
1986 /* Setup the implicit swapchain */
1987 TRACE("Creating implicit swapchain\n");
1988 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1989 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1992 WARN("Failed to create implicit swapchain\n");
1996 This->NumberOfSwapChains = 1;
1997 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1998 if(!This->swapchains) {
1999 ERR("Out of memory!\n");
2002 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2006 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2010 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2012 IWineD3DResource_UnLoad(resource);
2013 IWineD3DResource_Release(resource);
2017 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2018 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2021 const struct wined3d_gl_info *gl_info;
2022 struct wined3d_context *context;
2025 TRACE("(%p)\n", This);
2027 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2029 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2030 * it was created. Thus make sure a context is active for the glDelete* calls
2032 context = context_acquire(This, NULL);
2033 gl_info = context->gl_info;
2035 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2037 /* Unload resources */
2038 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2040 TRACE("Deleting high order patches\n");
2041 for(i = 0; i < PATCHMAP_SIZE; i++) {
2042 struct list *e1, *e2;
2043 struct WineD3DRectPatch *patch;
2044 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2045 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2046 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2050 /* Delete the mouse cursor texture */
2051 if(This->cursorTexture) {
2053 glDeleteTextures(1, &This->cursorTexture);
2055 This->cursorTexture = 0;
2058 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2059 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2061 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2062 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2065 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2066 * private data, it might contain opengl pointers
2068 if(This->depth_blt_texture) {
2070 glDeleteTextures(1, &This->depth_blt_texture);
2072 This->depth_blt_texture = 0;
2074 if (This->depth_blt_rb) {
2076 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2078 This->depth_blt_rb = 0;
2079 This->depth_blt_rb_w = 0;
2080 This->depth_blt_rb_h = 0;
2083 /* Release the update stateblock */
2084 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2085 if(This->updateStateBlock != This->stateBlock)
2086 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2088 This->updateStateBlock = NULL;
2090 { /* because were not doing proper internal refcounts releasing the primary state block
2091 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2092 to set this->stateBlock = NULL; first */
2093 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2094 This->stateBlock = NULL;
2096 /* Release the stateblock */
2097 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2098 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2102 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2103 This->blitter->free_private(iface);
2104 This->frag_pipe->free_private(iface);
2105 This->shader_backend->shader_free_private(iface);
2107 /* Release the buffers (with sanity checks)*/
2108 if (This->onscreen_depth_stencil)
2110 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2111 This->onscreen_depth_stencil = NULL;
2114 if (This->depth_stencil)
2116 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2118 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2120 This->depth_stencil = NULL;
2121 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2122 && ds != This->auto_depth_stencil)
2124 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2128 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2129 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2131 TRACE("Setting rendertarget to NULL\n");
2132 This->render_targets[0] = NULL;
2134 if (This->auto_depth_stencil)
2136 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2138 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2140 This->auto_depth_stencil = NULL;
2143 context_release(context);
2145 for(i=0; i < This->NumberOfSwapChains; i++) {
2146 TRACE("Releasing the implicit swapchain %d\n", i);
2147 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2148 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2152 HeapFree(GetProcessHeap(), 0, This->swapchains);
2153 This->swapchains = NULL;
2154 This->NumberOfSwapChains = 0;
2156 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2157 HeapFree(GetProcessHeap(), 0, This->palettes);
2158 This->palettes = NULL;
2159 This->NumberOfPalettes = 0;
2161 HeapFree(GetProcessHeap(), 0, This->render_targets);
2162 This->render_targets = NULL;
2164 This->d3d_initialized = FALSE;
2169 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2173 for(i=0; i < This->NumberOfSwapChains; i++) {
2174 TRACE("Releasing the implicit swapchain %d\n", i);
2175 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2176 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2180 HeapFree(GetProcessHeap(), 0, This->swapchains);
2181 This->swapchains = NULL;
2182 This->NumberOfSwapChains = 0;
2186 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2187 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2188 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2190 * There is no way to deactivate thread safety once it is enabled.
2192 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2195 /*For now just store the flag(needed in case of ddraw) */
2196 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2199 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2200 const WINED3DDISPLAYMODE* pMode) {
2202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2203 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2207 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2209 /* Resize the screen even without a window:
2210 * The app could have unset it with SetCooperativeLevel, but not called
2211 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2212 * but we don't have any hwnd
2215 memset(&devmode, 0, sizeof(devmode));
2216 devmode.dmSize = sizeof(devmode);
2217 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2218 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2219 devmode.dmPelsWidth = pMode->Width;
2220 devmode.dmPelsHeight = pMode->Height;
2222 devmode.dmDisplayFrequency = pMode->RefreshRate;
2223 if (pMode->RefreshRate)
2224 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2226 /* Only change the mode if necessary */
2227 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2228 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2232 if (ret != DISP_CHANGE_SUCCESSFUL)
2234 if (devmode.dmDisplayFrequency)
2236 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2237 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2238 devmode.dmDisplayFrequency = 0;
2239 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2241 if(ret != DISP_CHANGE_SUCCESSFUL) {
2242 return WINED3DERR_NOTAVAILABLE;
2246 /* Store the new values */
2247 This->ddraw_width = pMode->Width;
2248 This->ddraw_height = pMode->Height;
2249 This->ddraw_format = pMode->Format;
2251 /* And finally clip mouse to our screen */
2252 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2253 ClipCursor(&clip_rc);
2258 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 *ppD3D = This->wined3d;
2261 TRACE("Returning %p.\n", *ppD3D);
2262 IWineD3D_AddRef(*ppD3D);
2266 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2269 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2270 (This->adapter->TextureRam/(1024*1024)),
2271 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2272 /* return simulated texture memory left */
2273 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2277 * Get / Set Stream Source
2279 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2280 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 struct wined3d_stream_state *stream;
2284 IWineD3DBuffer *oldSrc;
2286 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2287 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2289 if (StreamNumber >= MAX_STREAMS) {
2290 WARN("Stream out of range %d\n", StreamNumber);
2291 return WINED3DERR_INVALIDCALL;
2292 } else if(OffsetInBytes & 0x3) {
2293 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2294 return WINED3DERR_INVALIDCALL;
2297 stream = &This->updateStateBlock->state.streams[StreamNumber];
2298 oldSrc = (IWineD3DBuffer *)stream->buffer;
2300 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2302 if (oldSrc == pStreamData
2303 && stream->stride == Stride
2304 && stream->offset == OffsetInBytes)
2306 TRACE("Application is setting the old values over, nothing to do\n");
2310 stream->buffer = (struct wined3d_buffer *)pStreamData;
2313 stream->stride = Stride;
2314 stream->offset = OffsetInBytes;
2317 /* Handle recording of state blocks */
2318 if (This->isRecordingState) {
2319 TRACE("Recording... not performing anything\n");
2320 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2321 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2327 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2328 IWineD3DBuffer_AddRef(pStreamData);
2332 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2333 IWineD3DBuffer_Release(oldSrc);
2336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2341 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2342 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 struct wined3d_stream_state *stream;
2347 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2348 iface, StreamNumber, pStream, pOffset, pStride);
2350 if (StreamNumber >= MAX_STREAMS)
2352 WARN("Stream out of range %d\n", StreamNumber);
2353 return WINED3DERR_INVALIDCALL;
2356 stream = &This->stateBlock->state.streams[StreamNumber];
2357 *pStream = (IWineD3DBuffer *)stream->buffer;
2358 *pStride = stream->stride;
2359 if (pOffset) *pOffset = stream->offset;
2361 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2366 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 struct wined3d_stream_state *stream;
2369 UINT oldFlags, oldFreq;
2371 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2373 /* Verify input at least in d3d9 this is invalid. */
2374 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2376 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2377 return WINED3DERR_INVALIDCALL;
2379 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2381 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2382 return WINED3DERR_INVALIDCALL;
2386 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2387 return WINED3DERR_INVALIDCALL;
2390 stream = &This->updateStateBlock->state.streams[StreamNumber];
2391 oldFlags = stream->flags;
2392 oldFreq = stream->frequency;
2394 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2395 stream->frequency = Divider & 0x7FFFFF;
2397 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2399 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2405 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2407 struct wined3d_stream_state *stream;
2409 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2411 stream = &This->updateStateBlock->state.streams[StreamNumber];
2412 *Divider = stream->flags | stream->frequency;
2414 TRACE("Returning %#x.\n", *Divider);
2420 * Get / Set & Multiply Transform
2422 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 /* Most of this routine, comments included copied from ddraw tree initially: */
2426 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2428 /* Handle recording of state blocks */
2429 if (This->isRecordingState) {
2430 TRACE("Recording... not performing anything\n");
2431 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2432 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2437 * If the new matrix is the same as the current one,
2438 * we cut off any further processing. this seems to be a reasonable
2439 * optimization because as was noticed, some apps (warcraft3 for example)
2440 * tend towards setting the same matrix repeatedly for some reason.
2442 * From here on we assume that the new matrix is different, wherever it matters.
2444 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2446 TRACE("The app is setting the same matrix over again\n");
2451 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2455 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2456 where ViewMat = Camera space, WorldMat = world space.
2458 In OpenGL, camera and world space is combined into GL_MODELVIEW
2459 matrix. The Projection matrix stay projection matrix.
2462 /* Capture the times we can just ignore the change for now */
2463 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2464 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2465 /* Handled by the state manager */
2468 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2475 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2476 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2478 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2480 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2482 *matrix = device->stateBlock->state.transforms[state];
2487 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2488 const WINED3DMATRIX *mat = NULL;
2491 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2492 * below means it will be recorded in a state block change, but it
2493 * works regardless where it is recorded.
2494 * If this is found to be wrong, change to StateBlock.
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2499 if (State <= HIGHEST_TRANSFORMSTATE)
2501 mat = &This->updateStateBlock->state.transforms[State];
2505 FIXME("Unhandled transform state!!\n");
2508 multiply_matrix(&temp, mat, pMatrix);
2510 /* Apply change via set transform - will reapply to eg. lights this way */
2511 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2517 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2518 you can reference any indexes you want as long as that number max are enabled at any
2519 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2520 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2521 but when recording, just build a chain pretty much of commands to be replayed. */
2523 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2525 struct wined3d_light_info *object = NULL;
2526 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2532 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2536 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2537 return WINED3DERR_INVALIDCALL;
2540 switch(pLight->Type) {
2541 case WINED3DLIGHT_POINT:
2542 case WINED3DLIGHT_SPOT:
2543 case WINED3DLIGHT_PARALLELPOINT:
2544 case WINED3DLIGHT_GLSPOT:
2545 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2548 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2550 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2551 return WINED3DERR_INVALIDCALL;
2555 case WINED3DLIGHT_DIRECTIONAL:
2556 /* Ignores attenuation */
2560 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2561 return WINED3DERR_INVALIDCALL;
2564 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2566 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2567 if(object->OriginalIndex == Index) break;
2572 TRACE("Adding new light\n");
2573 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2575 ERR("Out of memory error when allocating a light\n");
2576 return E_OUTOFMEMORY;
2578 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2579 object->glIndex = -1;
2580 object->OriginalIndex = Index;
2583 /* Initialize the object */
2584 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,
2585 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2586 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2587 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2588 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2589 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2590 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2592 /* Save away the information */
2593 object->OriginalParms = *pLight;
2595 switch (pLight->Type) {
2596 case WINED3DLIGHT_POINT:
2598 object->lightPosn[0] = pLight->Position.x;
2599 object->lightPosn[1] = pLight->Position.y;
2600 object->lightPosn[2] = pLight->Position.z;
2601 object->lightPosn[3] = 1.0f;
2602 object->cutoff = 180.0f;
2606 case WINED3DLIGHT_DIRECTIONAL:
2608 object->lightPosn[0] = -pLight->Direction.x;
2609 object->lightPosn[1] = -pLight->Direction.y;
2610 object->lightPosn[2] = -pLight->Direction.z;
2611 object->lightPosn[3] = 0.0f;
2612 object->exponent = 0.0f;
2613 object->cutoff = 180.0f;
2616 case WINED3DLIGHT_SPOT:
2618 object->lightPosn[0] = pLight->Position.x;
2619 object->lightPosn[1] = pLight->Position.y;
2620 object->lightPosn[2] = pLight->Position.z;
2621 object->lightPosn[3] = 1.0f;
2624 object->lightDirn[0] = pLight->Direction.x;
2625 object->lightDirn[1] = pLight->Direction.y;
2626 object->lightDirn[2] = pLight->Direction.z;
2627 object->lightDirn[3] = 1.0f;
2630 * opengl-ish and d3d-ish spot lights use too different models for the
2631 * light "intensity" as a function of the angle towards the main light direction,
2632 * so we only can approximate very roughly.
2633 * however spot lights are rather rarely used in games (if ever used at all).
2634 * furthermore if still used, probably nobody pays attention to such details.
2636 if (!pLight->Falloff)
2638 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2639 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2640 * will always be 1.0 for both of them, and we don't have to care for the
2641 * rest of the rather complex calculation
2643 object->exponent = 0.0f;
2645 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2646 if (rho < 0.0001f) rho = 0.0001f;
2647 object->exponent = -0.3f/logf(cosf(rho/2));
2649 if (object->exponent > 128.0f)
2651 object->exponent = 128.0f;
2653 object->cutoff = (float) (pLight->Phi*90/M_PI);
2659 FIXME("Unrecognized light type %d\n", pLight->Type);
2662 /* Update the live definitions if the light is currently assigned a glIndex */
2663 if (object->glIndex != -1 && !This->isRecordingState) {
2664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2669 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2671 struct wined3d_light_info *lightInfo = NULL;
2672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2675 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2677 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2679 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2680 if(lightInfo->OriginalIndex == Index) break;
2686 TRACE("Light information requested but light not defined\n");
2687 return WINED3DERR_INVALIDCALL;
2690 *pLight = lightInfo->OriginalParms;
2695 * Get / Set Light Enable
2696 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2698 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2700 struct wined3d_light_info *lightInfo = NULL;
2701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2702 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2704 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2706 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2708 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2709 if(lightInfo->OriginalIndex == Index) break;
2712 TRACE("Found light: %p\n", lightInfo);
2714 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2717 TRACE("Light enabled requested but light not defined, so defining one!\n");
2718 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2720 /* Search for it again! Should be fairly quick as near head of list */
2721 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2723 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2724 if(lightInfo->OriginalIndex == Index) break;
2729 FIXME("Adding default lights has failed dismally\n");
2730 return WINED3DERR_INVALIDCALL;
2735 if(lightInfo->glIndex != -1) {
2736 if(!This->isRecordingState) {
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2740 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2741 lightInfo->glIndex = -1;
2743 TRACE("Light already disabled, nothing to do\n");
2745 lightInfo->enabled = FALSE;
2747 lightInfo->enabled = TRUE;
2748 if (lightInfo->glIndex != -1) {
2750 TRACE("Nothing to do as light was enabled\n");
2753 /* Find a free gl light */
2754 for (i = 0; i < This->maxConcurrentLights; ++i)
2756 if (!This->updateStateBlock->state.lights[i])
2758 This->updateStateBlock->state.lights[i] = lightInfo;
2759 lightInfo->glIndex = i;
2763 if(lightInfo->glIndex == -1) {
2764 /* Our tests show that Windows returns D3D_OK in this situation, even with
2765 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2766 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2767 * as well for those lights.
2769 * TODO: Test how this affects rendering
2771 WARN("Too many concurrently active lights\n");
2775 /* i == lightInfo->glIndex */
2776 if(!This->isRecordingState) {
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2785 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2787 struct wined3d_light_info *lightInfo = NULL;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2790 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2791 TRACE("(%p) : for idx(%d)\n", This, Index);
2793 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2795 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2796 if(lightInfo->OriginalIndex == Index) break;
2802 TRACE("Light enabled state requested but light not defined\n");
2803 return WINED3DERR_INVALIDCALL;
2805 /* true is 128 according to SetLightEnable */
2806 *pEnable = lightInfo->enabled ? 128 : 0;
2811 * Get / Set Clip Planes
2813 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2815 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2817 /* Validate Index */
2818 if (Index >= This->adapter->gl_info.limits.clipplanes)
2820 TRACE("Application has requested clipplane this device doesn't support\n");
2821 return WINED3DERR_INVALIDCALL;
2824 This->updateStateBlock->changed.clipplane |= 1 << Index;
2826 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2827 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2828 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2829 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2831 TRACE("Application is setting old values over, nothing to do\n");
2835 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2836 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2837 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2838 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2840 /* Handle recording of state blocks */
2841 if (This->isRecordingState) {
2842 TRACE("Recording... not performing anything\n");
2846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 TRACE("(%p) : for idx %d\n", This, Index);
2855 /* Validate Index */
2856 if (Index >= This->adapter->gl_info.limits.clipplanes)
2858 TRACE("Application has requested clipplane this device doesn't support\n");
2859 return WINED3DERR_INVALIDCALL;
2862 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2863 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2864 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2865 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2870 * Get / Set Clip Plane Status
2871 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2873 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 FIXME("(%p) : stub\n", This);
2878 return WINED3DERR_INVALIDCALL;
2880 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2881 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 FIXME("(%p) : stub\n", This);
2890 return WINED3DERR_INVALIDCALL;
2892 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2893 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2898 * Get / Set Material
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 This->updateStateBlock->changed.material = TRUE;
2904 This->updateStateBlock->state.material = *pMaterial;
2906 /* Handle recording of state blocks */
2907 if (This->isRecordingState) {
2908 TRACE("Recording... not performing anything\n");
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2916 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 *pMaterial = This->updateStateBlock->state.material;
2919 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2920 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2921 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2922 pMaterial->Ambient.b, pMaterial->Ambient.a);
2923 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2924 pMaterial->Specular.b, pMaterial->Specular.a);
2925 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2926 pMaterial->Emissive.b, pMaterial->Emissive.a);
2927 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2935 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2936 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 IWineD3DBuffer *oldIdxs;
2941 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2942 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2944 This->updateStateBlock->changed.indices = TRUE;
2945 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2946 This->updateStateBlock->state.index_format = fmt;
2948 /* Handle recording of state blocks */
2949 if (This->isRecordingState) {
2950 TRACE("Recording... not performing anything\n");
2951 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2952 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2956 if(oldIdxs != pIndexData) {
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2959 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2960 IWineD3DBuffer_AddRef(pIndexData);
2963 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2964 IWineD3DBuffer_Release(oldIdxs);
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2977 /* up ref count on ppindexdata */
2979 IWineD3DBuffer_AddRef(*ppIndexData);
2980 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2982 TRACE("(%p) No index data set\n", This);
2984 TRACE("Returning %p\n", *ppIndexData);
2989 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 TRACE("(%p)->(%d)\n", This, BaseIndex);
2994 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2996 TRACE("Application is setting the old value over, nothing to do\n");
3000 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3002 if (This->isRecordingState) {
3003 TRACE("Recording... not performing anything\n");
3006 /* The base vertex index affects the stream sources */
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p) : base_index %p\n", This, base_index);
3015 *base_index = This->stateBlock->state.base_vertex_index;
3017 TRACE("Returning %u\n", *base_index);
3023 * Get / Set Viewports
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 TRACE("(%p)\n", This);
3029 This->updateStateBlock->changed.viewport = TRUE;
3030 This->updateStateBlock->state.viewport = *pViewport;
3032 /* Handle recording of state blocks */
3033 if (This->isRecordingState) {
3034 TRACE("Recording... not performing anything\n");
3038 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3039 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3048 TRACE("(%p)\n", This);
3049 *pViewport = This->stateBlock->state.viewport;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3054 WINED3DRENDERSTATETYPE State, DWORD Value)
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 DWORD oldValue = This->stateBlock->state.render_states[State];
3059 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3061 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3062 This->updateStateBlock->state.render_states[State] = Value;
3064 /* Handle recording of state blocks */
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3070 /* Compared here and not before the assignment to allow proper stateblock recording */
3071 if(Value == oldValue) {
3072 TRACE("Application is setting the old value over, nothing to do\n");
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3081 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3087 *pValue = This->stateBlock->state.render_states[State];
3092 * Get / Set Sampler States
3093 * TODO: Verify against dx9 definitions
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3101 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3103 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3104 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3107 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3109 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3110 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3113 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3114 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3115 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3117 /* Handle recording of state blocks */
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3123 if(oldValue == Value) {
3124 TRACE("Application is setting the old value over, nothing to do\n");
3128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3137 This, Sampler, debug_d3dsamplerstate(Type), Type);
3139 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3140 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3143 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3145 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3146 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3148 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3149 TRACE("(%p) : Returning %#x\n", This, *Value);
3154 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 This->updateStateBlock->changed.scissorRect = TRUE;
3158 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3160 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3163 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3165 if(This->isRecordingState) {
3166 TRACE("Recording... not performing anything\n");
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 *pRect = This->updateStateBlock->state.scissor_rect;
3179 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3185 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3187 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3189 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3190 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3192 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3193 This->updateStateBlock->changed.vertexDecl = TRUE;
3195 if (This->isRecordingState) {
3196 TRACE("Recording... not performing anything\n");
3198 } else if(pDecl == oldDecl) {
3199 /* Checked after the assignment to allow proper stateblock recording */
3200 TRACE("Application is setting the old declaration over, nothing to do\n");
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3213 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3214 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3218 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3223 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3224 This->updateStateBlock->changed.vertexShader = TRUE;
3226 if (This->isRecordingState) {
3227 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3228 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3229 TRACE("Recording... not performing anything\n");
3231 } else if(oldShader == pShader) {
3232 /* Checked here to allow proper stateblock recording */
3233 TRACE("App is setting the old shader over, nothing to do\n");
3237 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3238 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3239 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3246 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3248 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3249 IWineD3DVertexShader *shader;
3251 TRACE("iface %p.\n", iface);
3253 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3254 if (shader) IWineD3DVertexShader_AddRef(shader);
3256 TRACE("Returning %p.\n", shader);
3260 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3261 IWineD3DDevice *iface,
3263 CONST BOOL *srcData,
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3269 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3270 iface, srcData, start, count);
3272 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3274 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3275 for (i = 0; i < cnt; i++)
3276 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3278 for (i = start; i < cnt + start; ++i) {
3279 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3282 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3287 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3288 IWineD3DDevice *iface,
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int cnt = min(count, MAX_CONST_B - start);
3296 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3297 iface, dstData, start, count);
3299 if (!dstData || cnt < 0)
3300 return WINED3DERR_INVALIDCALL;
3302 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3306 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3307 IWineD3DDevice *iface,
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3315 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3316 iface, srcData, start, count);
3318 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3320 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3321 for (i = 0; i < cnt; i++)
3322 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3323 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3325 for (i = start; i < cnt + start; ++i) {
3326 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3329 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3334 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3335 IWineD3DDevice *iface,
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341 int cnt = min(count, MAX_CONST_I - start);
3343 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3344 iface, dstData, start, count);
3346 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3347 return WINED3DERR_INVALIDCALL;
3349 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3353 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3354 IWineD3DDevice *iface,
3356 CONST float *srcData,
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3362 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3363 iface, srcData, start, count);
3365 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3366 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3367 return WINED3DERR_INVALIDCALL;
3369 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3371 for (i = 0; i < count; i++)
3372 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3373 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3376 if (!This->isRecordingState)
3378 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3382 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3383 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3389 IWineD3DDevice *iface,
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 int cnt = min(count, This->d3d_vshader_constantF - start);
3397 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3398 iface, dstData, start, count);
3400 if (!dstData || cnt < 0)
3401 return WINED3DERR_INVALIDCALL;
3403 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3407 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3409 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3415 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3417 DWORD i = This->rev_tex_unit_map[unit];
3418 DWORD j = This->texUnitMap[stage];
3420 This->texUnitMap[stage] = unit;
3421 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3423 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3426 This->rev_tex_unit_map[unit] = stage;
3427 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3429 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3433 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3436 This->fixed_function_usage_map = 0;
3437 for (i = 0; i < MAX_TEXTURES; ++i)
3439 const struct wined3d_state *state = &This->stateBlock->state;
3440 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3441 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3442 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3443 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3444 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3445 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3446 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3447 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3449 if (color_op == WINED3DTOP_DISABLE) {
3450 /* Not used, and disable higher stages */
3454 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3455 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3456 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3457 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3458 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3459 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3460 This->fixed_function_usage_map |= (1 << i);
3463 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3464 This->fixed_function_usage_map |= (1 << (i + 1));
3469 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3471 unsigned int i, tex;
3474 device_update_fixed_function_usage_map(This);
3475 ffu_map = This->fixed_function_usage_map;
3477 if (This->max_ffp_textures == gl_info->limits.texture_stages
3478 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3480 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3482 if (!(ffu_map & 1)) continue;
3484 if (This->texUnitMap[i] != i) {
3485 device_map_stage(This, i, i);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3487 markTextureStagesDirty(This, i);
3493 /* Now work out the mapping */
3495 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3497 if (!(ffu_map & 1)) continue;
3499 if (This->texUnitMap[i] != tex) {
3500 device_map_stage(This, i, tex);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 markTextureStagesDirty(This, i);
3509 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3511 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3512 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3515 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3516 if (sampler_type[i] && This->texUnitMap[i] != i)
3518 device_map_stage(This, i, i);
3519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3520 if (i < gl_info->limits.texture_stages)
3522 markTextureStagesDirty(This, i);
3528 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3529 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3531 DWORD current_mapping = This->rev_tex_unit_map[unit];
3533 /* Not currently used */
3534 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3536 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3537 /* Used by a fragment sampler */
3539 if (!pshader_sampler_tokens) {
3540 /* No pixel shader, check fixed function */
3541 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3544 /* Pixel shader, check the shader's sampler map */
3545 return !pshader_sampler_tokens[current_mapping];
3548 /* Used by a vertex sampler */
3549 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3552 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3554 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3555 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3556 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3557 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3562 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3564 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3565 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3566 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3569 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3570 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3571 if (vshader_sampler_type[i])
3573 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3575 /* Already mapped somewhere */
3579 while (start >= 0) {
3580 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3582 device_map_stage(This, vsampler_idx, start);
3583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3595 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3597 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3598 const struct wined3d_state *state = &This->stateBlock->state;
3599 BOOL vs = use_vs(state);
3600 BOOL ps = use_ps(state);
3603 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3604 * that would be really messy and require shader recompilation
3605 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3606 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3608 if (ps) device_map_psamplers(This, gl_info);
3609 else device_map_fixed_function_samplers(This, gl_info);
3611 if (vs) device_map_vsamplers(This, ps, gl_info);
3614 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3618 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3619 This->updateStateBlock->changed.pixelShader = TRUE;
3621 /* Handle recording of state blocks */
3622 if (This->isRecordingState) {
3623 TRACE("Recording... not performing anything\n");
3626 if (This->isRecordingState) {
3627 TRACE("Recording... not performing anything\n");
3628 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3629 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3633 if(pShader == oldShader) {
3634 TRACE("App is setting the old pixel shader over, nothing to do\n");
3638 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3639 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3641 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3647 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3649 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3650 IWineD3DPixelShader *shader;
3652 TRACE("iface %p.\n", iface);
3654 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3655 if (shader) IWineD3DPixelShader_AddRef(shader);
3657 TRACE("Returning %p.\n", shader);
3661 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3662 IWineD3DDevice *iface,
3664 CONST BOOL *srcData,
3667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3668 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3670 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3671 iface, srcData, start, count);
3673 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3675 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3676 for (i = 0; i < cnt; i++)
3677 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3679 for (i = start; i < cnt + start; ++i) {
3680 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3683 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3688 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3689 IWineD3DDevice *iface,
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 int cnt = min(count, MAX_CONST_B - start);
3697 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3698 iface, dstData, start, count);
3700 if (!dstData || cnt < 0)
3701 return WINED3DERR_INVALIDCALL;
3703 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3707 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3708 IWineD3DDevice *iface,
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3716 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3717 iface, srcData, start, count);
3719 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3721 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3722 for (i = 0; i < cnt; i++)
3723 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3724 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3726 for (i = start; i < cnt + start; ++i) {
3727 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3730 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3735 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3736 IWineD3DDevice *iface,
3741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3742 int cnt = min(count, MAX_CONST_I - start);
3744 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3745 iface, dstData, start, count);
3747 if (!dstData || cnt < 0)
3748 return WINED3DERR_INVALIDCALL;
3750 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3754 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3755 IWineD3DDevice *iface,
3757 CONST float *srcData,
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3763 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3764 iface, srcData, start, count);
3766 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3767 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3768 return WINED3DERR_INVALIDCALL;
3770 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3772 for (i = 0; i < count; i++)
3773 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3774 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3777 if (!This->isRecordingState)
3779 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3783 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3784 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3790 IWineD3DDevice *iface,
3795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3796 int cnt = min(count, This->d3d_pshader_constantF - start);
3798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3799 iface, dstData, start, count);
3801 if (!dstData || cnt < 0)
3802 return WINED3DERR_INVALIDCALL;
3804 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3808 /* Context activation is done by the caller. */
3809 /* Do not call while under the GL lock. */
3810 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3811 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3812 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3815 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3816 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3819 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3823 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3825 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3828 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3830 ERR("Source has no position mask\n");
3831 return WINED3DERR_INVALIDCALL;
3834 if (!dest->resource.allocatedMemory)
3835 buffer_get_sysmem(dest, gl_info);
3837 /* Get a pointer into the destination vbo(create one if none exists) and
3838 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3840 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3842 dest->flags |= WINED3D_BUFFER_CREATEBO;
3843 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3846 if (dest->buffer_object)
3848 unsigned char extrabytes = 0;
3849 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3850 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3851 * this may write 4 extra bytes beyond the area that should be written
3853 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3854 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3855 if(!dest_conv_addr) {
3856 ERR("Out of memory\n");
3857 /* Continue without storing converted vertices */
3859 dest_conv = dest_conv_addr;
3862 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3864 static BOOL warned = FALSE;
3866 * The clipping code is not quite correct. Some things need
3867 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3868 * so disable clipping for now.
3869 * (The graphics in Half-Life are broken, and my processvertices
3870 * test crashes with IDirect3DDevice3)
3876 FIXME("Clipping is broken and disabled for now\n");
3878 } else doClip = FALSE;
3879 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3881 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3884 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3885 WINED3DTS_PROJECTION,
3887 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3888 WINED3DTS_WORLDMATRIX(0),
3891 TRACE("View mat:\n");
3892 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);
3893 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);
3894 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);
3895 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);
3897 TRACE("Proj mat:\n");
3898 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);
3899 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);
3900 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);
3901 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);
3903 TRACE("World mat:\n");
3904 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);
3905 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);
3906 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);
3907 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);
3909 /* Get the viewport */
3910 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3911 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3912 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3914 multiply_matrix(&mat,&view_mat,&world_mat);
3915 multiply_matrix(&mat,&proj_mat,&mat);
3917 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3919 for (i = 0; i < dwCount; i+= 1) {
3920 unsigned int tex_index;
3922 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3923 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3924 /* The position first */
3925 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3926 const float *p = (const float *)(element->data + i * element->stride);
3928 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3930 /* Multiplication with world, view and projection matrix */
3931 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);
3932 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);
3933 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);
3934 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);
3936 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3938 /* WARNING: The following things are taken from d3d7 and were not yet checked
3939 * against d3d8 or d3d9!
3942 /* Clipping conditions: From msdn
3944 * A vertex is clipped if it does not match the following requirements
3948 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3950 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3951 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3956 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3957 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3960 /* "Normal" viewport transformation (not clipped)
3961 * 1) The values are divided by rhw
3962 * 2) The y axis is negative, so multiply it with -1
3963 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3964 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3965 * 4) Multiply x with Width/2 and add Width/2
3966 * 5) The same for the height
3967 * 6) Add the viewpoint X and Y to the 2D coordinates and
3968 * The minimum Z value to z
3969 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3971 * Well, basically it's simply a linear transformation into viewport
3983 z *= vp.MaxZ - vp.MinZ;
3985 x += vp.Width / 2 + vp.X;
3986 y += vp.Height / 2 + vp.Y;
3991 /* That vertex got clipped
3992 * Contrary to OpenGL it is not dropped completely, it just
3993 * undergoes a different calculation.
3995 TRACE("Vertex got clipped\n");
4002 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4003 * outside of the main vertex buffer memory. That needs some more
4008 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4011 ( (float *) dest_ptr)[0] = x;
4012 ( (float *) dest_ptr)[1] = y;
4013 ( (float *) dest_ptr)[2] = z;
4014 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4016 dest_ptr += 3 * sizeof(float);
4018 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4019 dest_ptr += sizeof(float);
4024 ( (float *) dest_conv)[0] = x * w;
4025 ( (float *) dest_conv)[1] = y * w;
4026 ( (float *) dest_conv)[2] = z * w;
4027 ( (float *) dest_conv)[3] = w;
4029 dest_conv += 3 * sizeof(float);
4031 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4032 dest_conv += sizeof(float);
4036 if (DestFVF & WINED3DFVF_PSIZE) {
4037 dest_ptr += sizeof(DWORD);
4038 if(dest_conv) dest_conv += sizeof(DWORD);
4040 if (DestFVF & WINED3DFVF_NORMAL) {
4041 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4042 const float *normal = (const float *)(element->data + i * element->stride);
4043 /* AFAIK this should go into the lighting information */
4044 FIXME("Didn't expect the destination to have a normal\n");
4045 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4047 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4051 if (DestFVF & WINED3DFVF_DIFFUSE) {
4052 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4053 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4054 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4056 static BOOL warned = FALSE;
4059 ERR("No diffuse color in source, but destination has one\n");
4063 *( (DWORD *) dest_ptr) = 0xffffffff;
4064 dest_ptr += sizeof(DWORD);
4067 *( (DWORD *) dest_conv) = 0xffffffff;
4068 dest_conv += sizeof(DWORD);
4072 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4074 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4075 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4076 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4077 dest_conv += sizeof(DWORD);
4082 if (DestFVF & WINED3DFVF_SPECULAR)
4084 /* What's the color value in the feedback buffer? */
4085 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4086 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4087 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4089 static BOOL warned = FALSE;
4092 ERR("No specular color in source, but destination has one\n");
4096 *( (DWORD *) dest_ptr) = 0xFF000000;
4097 dest_ptr += sizeof(DWORD);
4100 *( (DWORD *) dest_conv) = 0xFF000000;
4101 dest_conv += sizeof(DWORD);
4105 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4107 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4108 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4109 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4110 dest_conv += sizeof(DWORD);
4115 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4116 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4117 const float *tex_coord = (const float *)(element->data + i * element->stride);
4118 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4120 ERR("No source texture, but destination requests one\n");
4121 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4122 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4125 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4127 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4137 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4138 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4139 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4140 dwCount * get_flexible_vertex_size(DestFVF),
4142 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4146 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4151 #undef copy_and_next
4153 /* Do not call while under the GL lock. */
4154 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4155 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 struct wined3d_stream_info stream_info;
4160 const struct wined3d_gl_info *gl_info;
4161 struct wined3d_context *context;
4162 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4165 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4168 ERR("Output vertex declaration not implemented yet\n");
4171 /* Need any context to write to the vbo. */
4172 context = context_acquire(This, NULL);
4173 gl_info = context->gl_info;
4175 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4176 * control the streamIsUP flag, thus restore it afterwards.
4178 This->stateBlock->state.user_stream = FALSE;
4179 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4180 This->stateBlock->state.user_stream = streamWasUP;
4182 if(vbo || SrcStartIndex) {
4184 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4185 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4187 * Also get the start index in, but only loop over all elements if there's something to add at all.
4189 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4191 struct wined3d_stream_info_element *e;
4193 if (!(stream_info.use_map & (1 << i))) continue;
4195 e = &stream_info.elements[i];
4196 if (e->buffer_object)
4198 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4199 e->buffer_object = 0;
4200 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4202 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4203 vb->buffer_object = 0;
4206 if (e->data) e->data += e->stride * SrcStartIndex;
4210 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4211 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4213 context_release(context);
4219 * Get / Set Texture Stage States
4220 * TODO: Verify against dx9 definitions
4222 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4225 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4228 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4230 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4232 WARN("Invalid Type %d passed.\n", Type);
4236 if (Stage >= gl_info->limits.texture_stages)
4238 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4239 Stage, gl_info->limits.texture_stages - 1);
4243 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4244 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4245 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4247 if (This->isRecordingState) {
4248 TRACE("Recording... not performing anything\n");
4252 /* Checked after the assignments to allow proper stateblock recording */
4253 if(oldValue == Value) {
4254 TRACE("App is setting the old value over, nothing to do\n");
4258 if (Stage > This->stateBlock->state.lowest_disabled_stage
4259 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4260 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4262 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4263 * Changes in other states are important on disabled stages too
4268 if(Type == WINED3DTSS_COLOROP) {
4271 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4272 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4273 * they have to be disabled
4275 * The current stage is dirtified below.
4277 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4279 TRACE("Additionally dirtifying stage %u\n", i);
4280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4282 This->stateBlock->state.lowest_disabled_stage = Stage;
4283 TRACE("New lowest disabled: %u\n", Stage);
4284 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4285 /* Previously disabled stage enabled. Stages above it may need enabling
4286 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4287 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4289 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4292 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4294 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4296 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4299 This->stateBlock->state.lowest_disabled_stage = i;
4300 TRACE("New lowest disabled: %u\n", i);
4304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4309 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4313 TRACE("iface %p, stage %u, state %s, value %p.\n",
4314 iface, Stage, debug_d3dtexturestate(Type), pValue);
4316 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4318 WARN("Invalid Type %d passed.\n", Type);
4322 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4323 TRACE("Returning %#x.\n", *pValue);
4331 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4332 DWORD stage, IWineD3DBaseTexture *texture)
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4336 IWineD3DBaseTexture *prev;
4338 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4340 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4341 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4343 /* Windows accepts overflowing this array... we do not. */
4344 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4346 WARN("Ignoring invalid stage %u.\n", stage);
4350 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4351 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4353 WARN("Rejecting attempt to set scratch texture.\n");
4354 return WINED3DERR_INVALIDCALL;
4357 This->updateStateBlock->changed.textures |= 1 << stage;
4359 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4360 TRACE("Previous texture %p.\n", prev);
4362 if (texture == prev)
4364 TRACE("App is setting the same texture again, nothing to do.\n");
4368 TRACE("Setting new texture to %p.\n", texture);
4369 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4371 if (This->isRecordingState)
4373 TRACE("Recording... not performing anything\n");
4375 if (texture) IWineD3DBaseTexture_AddRef(texture);
4376 if (prev) IWineD3DBaseTexture_Release(prev);
4383 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4384 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4385 GLenum dimensions = t->baseTexture.target;
4387 IWineD3DBaseTexture_AddRef(texture);
4389 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4392 if (!prev && stage < gl_info->limits.texture_stages)
4394 /* The source arguments for color and alpha ops have different
4395 * meanings when a NULL texture is bound, so the COLOROP and
4396 * ALPHAOP have to be dirtified. */
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4401 if (bind_count == 1) t->baseTexture.sampler = stage;
4406 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4407 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4409 IWineD3DBaseTexture_Release(prev);
4411 if (!texture && stage < gl_info->limits.texture_stages)
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4417 if (bind_count && t->baseTexture.sampler == stage)
4421 /* Search for other stages the texture is bound to. Shouldn't
4422 * happen if applications bind textures to a single stage only. */
4423 TRACE("Searching for other stages the texture is bound to.\n");
4424 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4426 if (This->updateStateBlock->state.textures[i] == t)
4428 TRACE("Texture is also bound to stage %u.\n", i);
4429 t->baseTexture.sampler = i;
4436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4441 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4446 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4447 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4450 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4452 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4453 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4456 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4458 IWineD3DBaseTexture_AddRef(*ppTexture);
4460 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4468 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4469 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4471 IWineD3DSwapChain *swapchain;
4474 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4475 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4477 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4480 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4484 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4485 IWineD3DSwapChain_Release(swapchain);
4488 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4495 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 WARN("(%p) : stub, calling idirect3d for now\n", This);
4498 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4501 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DSwapChain *swapChain;
4506 if(iSwapChain > 0) {
4507 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4508 if (hr == WINED3D_OK) {
4509 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4510 IWineD3DSwapChain_Release(swapChain);
4512 FIXME("(%p) Error getting display mode\n", This);
4515 /* Don't read the real display mode,
4516 but return the stored mode instead. X11 can't change the color
4517 depth, and some apps are pretty angry if they SetDisplayMode from
4518 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4520 Also don't relay to the swapchain because with ddraw it's possible
4521 that there isn't a swapchain at all */
4522 pMode->Width = This->ddraw_width;
4523 pMode->Height = This->ddraw_height;
4524 pMode->Format = This->ddraw_format;
4525 pMode->RefreshRate = 0;
4533 * Stateblock related functions
4536 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 IWineD3DStateBlock *stateblock;
4541 TRACE("(%p)\n", This);
4543 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4545 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4546 if (FAILED(hr)) return hr;
4548 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4549 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4550 This->isRecordingState = TRUE;
4552 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4557 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4561 if (!This->isRecordingState) {
4562 WARN("(%p) not recording! returning error\n", This);
4563 *ppStateBlock = NULL;
4564 return WINED3DERR_INVALIDCALL;
4567 stateblock_init_contained_states(object);
4569 *ppStateBlock = (IWineD3DStateBlock*) object;
4570 This->isRecordingState = FALSE;
4571 This->updateStateBlock = This->stateBlock;
4572 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4573 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4574 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4579 * Scene related functions
4581 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4582 /* At the moment we have no need for any functionality at the beginning
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 TRACE("(%p)\n", This);
4588 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4589 return WINED3DERR_INVALIDCALL;
4591 This->inScene = TRUE;
4595 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 struct wined3d_context *context;
4600 TRACE("(%p)\n", This);
4602 if(!This->inScene) {
4603 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4604 return WINED3DERR_INVALIDCALL;
4607 context = context_acquire(This, NULL);
4608 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4610 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4612 context_release(context);
4614 This->inScene = FALSE;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4619 const RECT *pSourceRect, const RECT *pDestRect,
4620 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4622 IWineD3DSwapChain *swapChain = NULL;
4624 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4626 TRACE("iface %p.\n", iface);
4628 for(i = 0 ; i < swapchains ; i ++) {
4630 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4631 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4632 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4633 IWineD3DSwapChain_Release(swapChain);
4639 /* Do not call while under the GL lock. */
4640 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4641 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4643 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4644 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4647 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4648 iface, rect_count, rects, flags, color, depth, stencil);
4650 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4652 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4653 /* TODO: What about depth stencil buffers without stencil bits? */
4654 return WINED3DERR_INVALIDCALL;
4657 device_get_draw_rect(device, &draw_rect);
4659 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4660 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4667 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4668 WINED3DPRIMITIVETYPE primitive_type)
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4674 This->updateStateBlock->changed.primitive_type = TRUE;
4675 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4678 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4679 WINED3DPRIMITIVETYPE *primitive_type)
4681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4685 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4687 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4690 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4694 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4696 if (!This->stateBlock->state.vertex_declaration)
4698 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4699 return WINED3DERR_INVALIDCALL;
4702 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4703 if (This->stateBlock->state.user_stream)
4705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4706 This->stateBlock->state.user_stream = FALSE;
4709 if (This->stateBlock->state.load_base_vertex_index)
4711 This->stateBlock->state.load_base_vertex_index = 0;
4712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4714 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4715 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4719 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 struct wined3d_buffer *index_buffer;
4726 index_buffer = This->stateBlock->state.index_buffer;
4729 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4730 * without an index buffer set. (The first time at least...)
4731 * D3D8 simply dies, but I doubt it can do much harm to return
4732 * D3DERR_INVALIDCALL there as well. */
4733 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4734 return WINED3DERR_INVALIDCALL;
4737 if (!This->stateBlock->state.vertex_declaration)
4739 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4740 return WINED3DERR_INVALIDCALL;
4743 if (This->stateBlock->state.user_stream)
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4746 This->stateBlock->state.user_stream = FALSE;
4748 vbo = index_buffer->buffer_object;
4750 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4752 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4757 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4759 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4763 drawPrimitive(iface, index_count, startIndex, idxStride,
4764 vbo ? NULL : index_buffer->resource.allocatedMemory);
4769 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4770 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4773 struct wined3d_stream_state *stream;
4776 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4777 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4779 if (!This->stateBlock->state.vertex_declaration)
4781 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4786 stream = &This->stateBlock->state.streams[0];
4787 vb = (IWineD3DBuffer *)stream->buffer;
4788 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4789 if (vb) IWineD3DBuffer_Release(vb);
4791 stream->stride = VertexStreamZeroStride;
4792 This->stateBlock->state.user_stream = TRUE;
4793 This->stateBlock->state.load_base_vertex_index = 0;
4795 /* TODO: Only mark dirty if drawing from a different UP address */
4796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4798 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4800 /* MSDN specifies stream zero settings must be set to NULL */
4801 stream->buffer = NULL;
4804 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4805 * the new stream sources or use UP drawing again
4810 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4811 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4812 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 struct wined3d_stream_state *stream;
4820 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4821 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4823 if (!This->stateBlock->state.vertex_declaration)
4825 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4826 return WINED3DERR_INVALIDCALL;
4829 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4835 stream = &This->stateBlock->state.streams[0];
4836 vb = (IWineD3DBuffer *)stream->buffer;
4837 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4838 if (vb) IWineD3DBuffer_Release(vb);
4840 stream->stride = VertexStreamZeroStride;
4841 This->stateBlock->state.user_stream = TRUE;
4843 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4844 This->stateBlock->state.base_vertex_index = 0;
4845 This->stateBlock->state.load_base_vertex_index = 0;
4846 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4850 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4852 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4853 stream->buffer = NULL;
4855 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4858 IWineD3DBuffer_Release(ib);
4859 This->stateBlock->state.index_buffer = NULL;
4861 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4862 * SetStreamSource to specify a vertex buffer
4868 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4869 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4873 /* Mark the state dirty until we have nicer tracking
4874 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4879 This->stateBlock->state.base_vertex_index = 0;
4880 This->up_strided = DrawPrimStrideData;
4881 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4882 This->up_strided = NULL;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4887 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4888 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4891 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4893 /* Mark the state dirty until we have nicer tracking
4894 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4899 This->stateBlock->state.user_stream = TRUE;
4900 This->stateBlock->state.base_vertex_index = 0;
4901 This->up_strided = DrawPrimStrideData;
4902 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4903 This->up_strided = NULL;
4907 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4908 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4909 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4911 WINED3DLOCKED_BOX src;
4912 WINED3DLOCKED_BOX dst;
4915 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4916 iface, pSourceVolume, pDestinationVolume);
4918 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4919 * dirtification to improve loading performance.
4921 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4922 if (FAILED(hr)) return hr;
4923 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4926 IWineD3DVolume_Unmap(pSourceVolume);
4930 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4932 hr = IWineD3DVolume_Unmap(pDestinationVolume);
4934 IWineD3DVolume_Unmap(pSourceVolume);
4936 hr = IWineD3DVolume_Unmap(pSourceVolume);
4941 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4942 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4944 unsigned int level_count, i;
4945 WINED3DRESOURCETYPE type;
4948 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4950 /* Verify that the source and destination textures are non-NULL. */
4951 if (!src_texture || !dst_texture)
4953 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4954 return WINED3DERR_INVALIDCALL;
4957 if (src_texture == dst_texture)
4959 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4960 return WINED3DERR_INVALIDCALL;
4963 /* Verify that the source and destination textures are the same type. */
4964 type = IWineD3DBaseTexture_GetType(src_texture);
4965 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4967 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4968 return WINED3DERR_INVALIDCALL;
4971 /* Check that both textures have the identical numbers of levels. */
4972 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4973 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4975 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4976 return WINED3DERR_INVALIDCALL;
4979 /* Make sure that the destination texture is loaded. */
4980 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4982 /* Update every surface level of the texture. */
4985 case WINED3DRTYPE_TEXTURE:
4987 IWineD3DSurface *src_surface;
4988 IWineD3DSurface *dst_surface;
4990 for (i = 0; i < level_count; ++i)
4992 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4993 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4994 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4995 IWineD3DSurface_Release(dst_surface);
4996 IWineD3DSurface_Release(src_surface);
4999 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5006 case WINED3DRTYPE_CUBETEXTURE:
5008 IWineD3DSurface *src_surface;
5009 IWineD3DSurface *dst_surface;
5010 WINED3DCUBEMAP_FACES face;
5012 for (i = 0; i < level_count; ++i)
5014 /* Update each cube face. */
5015 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5017 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5018 face, i, &src_surface);
5019 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5020 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5021 face, i, &dst_surface);
5022 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5023 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5024 IWineD3DSurface_Release(dst_surface);
5025 IWineD3DSurface_Release(src_surface);
5028 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5036 case WINED3DRTYPE_VOLUMETEXTURE:
5038 IWineD3DVolume *src_volume;
5039 IWineD3DVolume *dst_volume;
5041 for (i = 0; i < level_count; ++i)
5043 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5044 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5045 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5046 IWineD3DVolume_Release(dst_volume);
5047 IWineD3DVolume_Release(src_volume);
5050 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5058 FIXME("Unsupported texture type %#x.\n", type);
5059 return WINED3DERR_INVALIDCALL;
5065 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5066 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5068 IWineD3DSwapChain *swapchain;
5071 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5073 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5074 if (FAILED(hr)) return hr;
5076 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5077 IWineD3DSwapChain_Release(swapchain);
5082 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5084 IWineD3DBaseTextureImpl *texture;
5087 TRACE("(%p) : %p\n", This, pNumPasses);
5089 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5091 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5093 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5094 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5096 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5098 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5099 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5102 texture = This->stateBlock->state.textures[i];
5103 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5105 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5107 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5110 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5112 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5115 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5116 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5118 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5123 /* return a sensible default */
5126 TRACE("returning D3D_OK\n");
5130 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5134 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5136 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5137 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5138 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5140 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5145 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 PALETTEENTRY **palettes;
5151 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5153 if (PaletteNumber >= MAX_PALETTES) {
5154 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5155 return WINED3DERR_INVALIDCALL;
5158 if (PaletteNumber >= This->NumberOfPalettes) {
5159 NewSize = This->NumberOfPalettes;
5162 } while(PaletteNumber >= NewSize);
5163 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5165 ERR("Out of memory!\n");
5166 return E_OUTOFMEMORY;
5168 This->palettes = palettes;
5169 This->NumberOfPalettes = NewSize;
5172 if (!This->palettes[PaletteNumber]) {
5173 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5174 if (!This->palettes[PaletteNumber]) {
5175 ERR("Out of memory!\n");
5176 return E_OUTOFMEMORY;
5180 for (j = 0; j < 256; ++j) {
5181 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5182 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5183 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5184 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5186 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5187 TRACE("(%p) : returning\n", This);
5191 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5194 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5195 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5196 /* What happens in such situation isn't documented; Native seems to silently abort
5197 on such conditions. Return Invalid Call. */
5198 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5199 return WINED3DERR_INVALIDCALL;
5201 for (j = 0; j < 256; ++j) {
5202 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5203 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5204 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5205 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5207 TRACE("(%p) : returning\n", This);
5211 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5213 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5214 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5215 (tested with reference rasterizer). Return Invalid Call. */
5216 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5217 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5218 return WINED3DERR_INVALIDCALL;
5220 /*TODO: stateblocks */
5221 if (This->currentPalette != PaletteNumber) {
5222 This->currentPalette = PaletteNumber;
5223 dirtify_p8_texture_samplers(This);
5225 TRACE("(%p) : returning\n", This);
5229 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5234 WARN("(%p) : returning Invalid Call\n", This);
5235 return WINED3DERR_INVALIDCALL;
5237 /*TODO: stateblocks */
5238 *PaletteNumber = This->currentPalette;
5239 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5243 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5248 FIXME("(%p) : stub\n", This);
5252 This->softwareVertexProcessing = bSoftware;
5257 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5262 FIXME("(%p) : stub\n", This);
5265 return This->softwareVertexProcessing;
5268 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5269 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5271 IWineD3DSwapChain *swapchain;
5274 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5275 iface, swapchain_idx, raster_status);
5277 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5280 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5284 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5285 IWineD3DSwapChain_Release(swapchain);
5288 WARN("Failed to get raster status, hr %#x.\n", hr);
5295 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5298 if(nSegments != 0.0f) {
5301 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5308 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5313 FIXME("iface %p stub!\n", iface);
5319 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5320 IWineD3DSurface *src_surface, const RECT *src_rect,
5321 IWineD3DSurface *dst_surface, const POINT *dst_point)
5323 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5324 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5326 const struct wined3d_format *src_format;
5327 const struct wined3d_format *dst_format;
5328 const struct wined3d_gl_info *gl_info;
5329 struct wined3d_context *context;
5330 const unsigned char *data;
5331 UINT update_w, update_h;
5332 CONVERT_TYPES convert;
5336 struct wined3d_format format;
5338 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5339 iface, src_surface, wine_dbgstr_rect(src_rect),
5340 dst_surface, wine_dbgstr_point(dst_point));
5342 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5344 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5345 src_surface, dst_surface);
5346 return WINED3DERR_INVALIDCALL;
5349 src_format = src_impl->resource.format;
5350 dst_format = dst_impl->resource.format;
5352 if (src_format->id != dst_format->id)
5354 WARN("Source and destination surfaces should have the same format.\n");
5355 return WINED3DERR_INVALIDCALL;
5358 dst_x = dst_point ? dst_point->x : 0;
5359 dst_y = dst_point ? dst_point->y : 0;
5361 /* This call loads the OpenGL surface directly, instead of copying the
5362 * surface to the destination's sysmem copy. If surface conversion is
5363 * needed, use BltFast instead to copy in sysmem and use regular surface
5365 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5366 if (convert != NO_CONVERSION || format.convert)
5367 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5369 context = context_acquire(This, NULL);
5370 gl_info = context->gl_info;
5373 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5374 checkGLcall("glActiveTextureARB");
5377 /* Make sure the surface is loaded and up to date */
5378 surface_internal_preload(dst_impl, SRGB_RGB);
5379 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5381 src_w = src_impl->currentDesc.Width;
5382 src_h = src_impl->currentDesc.Height;
5383 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5384 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5386 data = IWineD3DSurface_GetData(src_surface);
5387 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5391 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5393 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5394 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5395 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5399 data += (src_rect->top / src_format->block_height) * src_pitch;
5400 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5403 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5404 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5405 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5407 if (row_length == src_pitch)
5409 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5410 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5416 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5417 * can't use the unpack row length like below. */
5418 for (row = 0, y = dst_y; row < row_count; ++row)
5420 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5421 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5422 y += src_format->block_height;
5426 checkGLcall("glCompressedTexSubImage2DARB");
5432 data += src_rect->top * src_w * src_format->byte_count;
5433 data += src_rect->left * src_format->byte_count;
5436 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5437 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5438 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5440 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5441 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5442 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5443 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5444 checkGLcall("glTexSubImage2D");
5448 context_release(context);
5450 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5451 sampler = This->rev_tex_unit_map[0];
5452 if (sampler != WINED3D_UNMAPPED_STAGE)
5454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5460 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5462 struct WineD3DRectPatch *patch;
5463 GLenum old_primitive_type;
5467 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5469 if(!(Handle || pRectPatchInfo)) {
5470 /* TODO: Write a test for the return value, thus the FIXME */
5471 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5472 return WINED3DERR_INVALIDCALL;
5476 i = PATCHMAP_HASHFUNC(Handle);
5478 LIST_FOR_EACH(e, &This->patches[i]) {
5479 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5480 if(patch->Handle == Handle) {
5487 TRACE("Patch does not exist. Creating a new one\n");
5488 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5489 patch->Handle = Handle;
5490 list_add_head(&This->patches[i], &patch->entry);
5492 TRACE("Found existing patch %p\n", patch);
5495 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5496 * attributes we have to tesselate, read back, and draw. This needs a patch
5497 * management structure instance. Create one.
5499 * A possible improvement is to check if a vertex shader is used, and if not directly
5502 FIXME("Drawing an uncached patch. This is slow\n");
5503 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5506 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5507 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5508 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5511 TRACE("Tesselation density or patch info changed, retesselating\n");
5513 if(pRectPatchInfo) {
5514 patch->RectPatchInfo = *pRectPatchInfo;
5516 patch->numSegs[0] = pNumSegs[0];
5517 patch->numSegs[1] = pNumSegs[1];
5518 patch->numSegs[2] = pNumSegs[2];
5519 patch->numSegs[3] = pNumSegs[3];
5521 hr = tesselate_rectpatch(This, patch);
5523 WARN("Patch tesselation failed\n");
5525 /* Do not release the handle to store the params of the patch */
5527 HeapFree(GetProcessHeap(), 0, patch);
5533 This->currentPatch = patch;
5534 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5535 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5536 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5537 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5538 This->currentPatch = NULL;
5540 /* Destroy uncached patches */
5542 HeapFree(GetProcessHeap(), 0, patch->mem);
5543 HeapFree(GetProcessHeap(), 0, patch);
5548 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5549 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5551 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5552 iface, handle, segment_count, patch_info);
5557 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5560 struct WineD3DRectPatch *patch;
5562 TRACE("(%p) Handle(%d)\n", This, Handle);
5564 i = PATCHMAP_HASHFUNC(Handle);
5565 LIST_FOR_EACH(e, &This->patches[i]) {
5566 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5567 if(patch->Handle == Handle) {
5568 TRACE("Deleting patch %p\n", patch);
5569 list_remove(&patch->entry);
5570 HeapFree(GetProcessHeap(), 0, patch->mem);
5571 HeapFree(GetProcessHeap(), 0, patch);
5576 /* TODO: Write a test for the return value */
5577 FIXME("Attempt to destroy nonexistent patch\n");
5578 return WINED3DERR_INVALIDCALL;
5581 /* Do not call while under the GL lock. */
5582 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5583 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5585 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5587 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5588 iface, surface, wine_dbgstr_rect(rect),
5589 color->r, color->g, color->b, color->a);
5591 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5593 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5594 return WINED3DERR_INVALIDCALL;
5597 return surface_color_fill(s, rect, color);
5600 /* Do not call while under the GL lock. */
5601 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5602 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5604 IWineD3DResource *resource;
5607 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5610 ERR("Failed to get resource, hr %#x\n", hr);
5614 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5616 FIXME("Only supported on surface resources\n");
5617 IWineD3DResource_Release(resource);
5621 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5622 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5624 IWineD3DResource_Release(resource);
5627 /* rendertarget and depth stencil functions */
5628 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5629 DWORD render_target_idx, IWineD3DSurface **render_target)
5631 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5633 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5634 iface, render_target_idx, render_target);
5636 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5638 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5639 return WINED3DERR_INVALIDCALL;
5642 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5643 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5645 TRACE("Returning render target %p.\n", *render_target);
5650 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5652 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5654 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5656 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5657 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5658 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5659 IWineD3DSurface_AddRef(*depth_stencil);
5664 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5665 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5667 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5668 IWineD3DSurfaceImpl *prev;
5670 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5671 iface, render_target_idx, render_target, set_viewport);
5673 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5675 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5676 return WINED3DERR_INVALIDCALL;
5679 prev = device->render_targets[render_target_idx];
5680 if (render_target == (IWineD3DSurface *)prev)
5682 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5686 /* Render target 0 can't be set to NULL. */
5687 if (!render_target && !render_target_idx)
5689 WARN("Trying to set render target 0 to NULL.\n");
5690 return WINED3DERR_INVALIDCALL;
5693 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5695 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5696 return WINED3DERR_INVALIDCALL;
5699 if (render_target) IWineD3DSurface_AddRef(render_target);
5700 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5701 /* Release after the assignment, to prevent device_resource_released()
5702 * from seeing the surface as still in use. */
5703 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5705 /* Render target 0 is special. */
5706 if (!render_target_idx && set_viewport)
5708 /* Set the viewport and scissor rectangles, if requested. Tests show
5709 * that stateblock recording is ignored, the change goes directly
5710 * into the primary stateblock. */
5711 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5712 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5713 device->stateBlock->state.viewport.X = 0;
5714 device->stateBlock->state.viewport.Y = 0;
5715 device->stateBlock->state.viewport.MaxZ = 1.0f;
5716 device->stateBlock->state.viewport.MinZ = 0.0f;
5717 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5719 device->stateBlock->state.scissor_rect.top = 0;
5720 device->stateBlock->state.scissor_rect.left = 0;
5721 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5722 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5723 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5729 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5732 IWineD3DSurfaceImpl *tmp;
5734 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5736 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5738 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5742 if (This->depth_stencil)
5744 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5745 || This->depth_stencil->Flags & SFLAG_DISCARD)
5747 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5748 This->depth_stencil->currentDesc.Width,
5749 This->depth_stencil->currentDesc.Height);
5750 if (This->depth_stencil == This->onscreen_depth_stencil)
5752 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5753 This->onscreen_depth_stencil = NULL;
5758 tmp = This->depth_stencil;
5759 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5760 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5761 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5763 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5765 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5774 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5775 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5778 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5779 WINED3DLOCKED_RECT lockedRect;
5781 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5782 iface, XHotSpot, YHotSpot, cursor_image);
5784 /* some basic validation checks */
5785 if (This->cursorTexture)
5787 struct wined3d_context *context = context_acquire(This, NULL);
5789 glDeleteTextures(1, &This->cursorTexture);
5791 context_release(context);
5792 This->cursorTexture = 0;
5795 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5796 This->haveHardwareCursor = TRUE;
5798 This->haveHardwareCursor = FALSE;
5802 WINED3DLOCKED_RECT rect;
5804 /* MSDN: Cursor must be A8R8G8B8 */
5805 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5807 WARN("surface %p has an invalid format.\n", cursor_image);
5808 return WINED3DERR_INVALIDCALL;
5811 /* MSDN: Cursor must be smaller than the display mode */
5812 if (s->currentDesc.Width > This->ddraw_width
5813 || s->currentDesc.Height > This->ddraw_height)
5815 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5816 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5817 return WINED3DERR_INVALIDCALL;
5820 if (!This->haveHardwareCursor) {
5821 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5823 /* Do not store the surface's pointer because the application may
5824 * release it after setting the cursor image. Windows doesn't
5825 * addref the set surface, so we can't do this either without
5826 * creating circular refcount dependencies. Copy out the gl texture
5829 This->cursorWidth = s->currentDesc.Width;
5830 This->cursorHeight = s->currentDesc.Height;
5831 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5833 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5834 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5835 struct wined3d_context *context;
5836 char *mem, *bits = rect.pBits;
5837 GLint intfmt = format->glInternal;
5838 GLint gl_format = format->glFormat;
5839 GLint type = format->glType;
5840 INT height = This->cursorHeight;
5841 INT width = This->cursorWidth;
5842 INT bpp = format->byte_count;
5846 /* Reformat the texture memory (pitch and width can be
5848 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5849 for(i = 0; i < height; i++)
5850 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5851 IWineD3DSurface_Unmap(cursor_image);
5853 context = context_acquire(This, NULL);
5857 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5859 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5860 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5863 /* Make sure that a proper texture unit is selected */
5864 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5865 checkGLcall("glActiveTextureARB");
5866 sampler = This->rev_tex_unit_map[0];
5867 if (sampler != WINED3D_UNMAPPED_STAGE)
5869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5871 /* Create a new cursor texture */
5872 glGenTextures(1, &This->cursorTexture);
5873 checkGLcall("glGenTextures");
5874 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5875 checkGLcall("glBindTexture");
5876 /* Copy the bitmap memory into the cursor texture */
5877 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5878 HeapFree(GetProcessHeap(), 0, mem);
5879 checkGLcall("glTexImage2D");
5881 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5883 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5884 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5889 context_release(context);
5893 FIXME("A cursor texture was not returned.\n");
5894 This->cursorTexture = 0;
5899 /* Draw a hardware cursor */
5900 ICONINFO cursorInfo;
5902 /* Create and clear maskBits because it is not needed for
5903 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5905 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5906 (s->currentDesc.Width * s->currentDesc.Height / 8));
5907 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5908 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5909 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5911 cursorInfo.fIcon = FALSE;
5912 cursorInfo.xHotspot = XHotSpot;
5913 cursorInfo.yHotspot = YHotSpot;
5914 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5915 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5916 IWineD3DSurface_Unmap(cursor_image);
5917 /* Create our cursor and clean up. */
5918 cursor = CreateIconIndirect(&cursorInfo);
5920 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5921 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5922 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5923 This->hardwareCursor = cursor;
5924 HeapFree(GetProcessHeap(), 0, maskBits);
5928 This->xHotSpot = XHotSpot;
5929 This->yHotSpot = YHotSpot;
5933 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5935 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5937 This->xScreenSpace = XScreenSpace;
5938 This->yScreenSpace = YScreenSpace;
5944 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5946 BOOL oldVisible = This->bCursorVisible;
5949 TRACE("(%p) : visible(%d)\n", This, bShow);
5952 * When ShowCursor is first called it should make the cursor appear at the OS's last
5953 * known cursor position. Because of this, some applications just repetitively call
5954 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5957 This->xScreenSpace = pt.x;
5958 This->yScreenSpace = pt.y;
5960 if (This->haveHardwareCursor) {
5961 This->bCursorVisible = bShow;
5963 SetCursor(This->hardwareCursor);
5969 if (This->cursorTexture)
5970 This->bCursorVisible = bShow;
5976 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5977 TRACE("checking resource %p for eviction\n", resource);
5978 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5979 TRACE("Evicting %p\n", resource);
5980 IWineD3DResource_UnLoad(resource);
5982 IWineD3DResource_Release(resource);
5986 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5988 TRACE("iface %p.\n", iface);
5990 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5991 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5992 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
5997 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
5999 IWineD3DDeviceImpl *device = surface->resource.device;
6000 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6002 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6003 if(surface->Flags & SFLAG_DIBSECTION) {
6004 /* Release the DC */
6005 SelectObject(surface->hDC, surface->dib.holdbitmap);
6006 DeleteDC(surface->hDC);
6007 /* Release the DIB section */
6008 DeleteObject(surface->dib.DIBsection);
6009 surface->dib.bitmap_data = NULL;
6010 surface->resource.allocatedMemory = NULL;
6011 surface->Flags &= ~SFLAG_DIBSECTION;
6013 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6014 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6015 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6016 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6018 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6019 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6021 surface->pow2Width = surface->pow2Height = 1;
6022 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6023 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6026 if (surface->texture_name)
6028 struct wined3d_context *context = context_acquire(device, NULL);
6030 glDeleteTextures(1, &surface->texture_name);
6032 context_release(context);
6033 surface->texture_name = 0;
6034 surface->Flags &= ~SFLAG_CLIENT;
6036 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6037 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6038 surface->Flags |= SFLAG_NONPOW2;
6040 surface->Flags &= ~SFLAG_NONPOW2;
6042 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6043 surface->resource.allocatedMemory = NULL;
6044 surface->resource.heapMemory = NULL;
6045 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6047 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6049 if (!surface_init_sysmem(surface))
6051 return E_OUTOFMEMORY;
6056 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6057 TRACE("Unloading resource %p\n", resource);
6058 IWineD3DResource_UnLoad(resource);
6059 IWineD3DResource_Release(resource);
6063 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6066 WINED3DDISPLAYMODE m;
6069 /* All Windowed modes are supported, as is leaving the current mode */
6070 if(pp->Windowed) return TRUE;
6071 if(!pp->BackBufferWidth) return TRUE;
6072 if(!pp->BackBufferHeight) return TRUE;
6074 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6075 for(i = 0; i < count; i++) {
6076 memset(&m, 0, sizeof(m));
6077 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6079 ERR("EnumAdapterModes failed\n");
6081 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6082 /* Mode found, it is supported */
6086 /* Mode not found -> not supported */
6090 /* Do not call while under the GL lock. */
6091 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6094 const struct wined3d_gl_info *gl_info;
6095 struct wined3d_context *context;
6096 IWineD3DBaseShaderImpl *shader;
6098 context = context_acquire(This, NULL);
6099 gl_info = context->gl_info;
6101 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6102 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6103 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6107 if(This->depth_blt_texture) {
6108 glDeleteTextures(1, &This->depth_blt_texture);
6109 This->depth_blt_texture = 0;
6111 if (This->depth_blt_rb) {
6112 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6113 This->depth_blt_rb = 0;
6114 This->depth_blt_rb_w = 0;
6115 This->depth_blt_rb_h = 0;
6119 This->blitter->free_private(iface);
6120 This->frag_pipe->free_private(iface);
6121 This->shader_backend->shader_free_private(iface);
6122 destroy_dummy_textures(This, gl_info);
6124 context_release(context);
6126 while (This->numContexts)
6128 context_destroy(This, This->contexts[0]);
6130 HeapFree(GetProcessHeap(), 0, swapchain->context);
6131 swapchain->context = NULL;
6132 swapchain->num_contexts = 0;
6135 /* Do not call while under the GL lock. */
6136 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6139 struct wined3d_context *context;
6141 IWineD3DSurfaceImpl *target;
6143 /* Recreate the primary swapchain's context */
6144 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6145 if (!swapchain->context)
6147 ERR("Failed to allocate memory for swapchain context array.\n");
6148 return E_OUTOFMEMORY;
6151 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6152 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6154 WARN("Failed to create context.\n");
6155 HeapFree(GetProcessHeap(), 0, swapchain->context);
6159 swapchain->context[0] = context;
6160 swapchain->num_contexts = 1;
6161 create_dummy_textures(This);
6162 context_release(context);
6164 hr = This->shader_backend->shader_alloc_private(iface);
6167 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6171 hr = This->frag_pipe->alloc_private(iface);
6174 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6175 This->shader_backend->shader_free_private(iface);
6179 hr = This->blitter->alloc_private(iface);
6182 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6183 This->frag_pipe->free_private(iface);
6184 This->shader_backend->shader_free_private(iface);
6191 context_acquire(This, NULL);
6192 destroy_dummy_textures(This, context->gl_info);
6193 context_release(context);
6194 context_destroy(This, context);
6195 HeapFree(GetProcessHeap(), 0, swapchain->context);
6196 swapchain->num_contexts = 0;
6200 /* Do not call while under the GL lock. */
6201 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6202 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6205 IWineD3DSwapChainImpl *swapchain;
6207 BOOL DisplayModeChanged = FALSE;
6208 WINED3DDISPLAYMODE mode;
6209 TRACE("(%p)\n", This);
6211 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6213 ERR("Failed to get the first implicit swapchain\n");
6217 if(!is_display_mode_supported(This, pPresentationParameters)) {
6218 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6219 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6220 pPresentationParameters->BackBufferHeight);
6221 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6222 return WINED3DERR_INVALIDCALL;
6225 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6226 * on an existing gl context, so there's no real need for recreation.
6228 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6230 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6232 TRACE("New params:\n");
6233 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6234 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6235 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6236 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6237 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6238 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6239 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6240 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6241 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6242 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6243 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6244 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6245 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6247 /* No special treatment of these parameters. Just store them */
6248 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6249 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6250 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6251 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6253 /* What to do about these? */
6254 if (pPresentationParameters->BackBufferCount
6255 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6256 ERR("Cannot change the back buffer count yet\n");
6258 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6259 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6260 ERR("Cannot change the back buffer format yet\n");
6263 if (pPresentationParameters->hDeviceWindow
6264 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6265 ERR("Cannot change the device window yet\n");
6267 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6271 TRACE("Creating the depth stencil buffer\n");
6273 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6274 pPresentationParameters->BackBufferWidth,
6275 pPresentationParameters->BackBufferHeight,
6276 pPresentationParameters->AutoDepthStencilFormat,
6277 pPresentationParameters->MultiSampleType,
6278 pPresentationParameters->MultiSampleQuality,
6280 (IWineD3DSurface **)&This->auto_depth_stencil);
6283 ERR("Failed to create the depth stencil buffer\n");
6284 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6285 return WINED3DERR_INVALIDCALL;
6289 if (This->onscreen_depth_stencil)
6291 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6292 This->onscreen_depth_stencil = NULL;
6295 /* Reset the depth stencil */
6296 if (pPresentationParameters->EnableAutoDepthStencil)
6297 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6299 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6301 TRACE("Resetting stateblock\n");
6302 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6303 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6305 delete_opengl_contexts(iface, swapchain);
6307 if(pPresentationParameters->Windowed) {
6308 mode.Width = swapchain->orig_width;
6309 mode.Height = swapchain->orig_height;
6310 mode.RefreshRate = 0;
6311 mode.Format = swapchain->presentParms.BackBufferFormat;
6313 mode.Width = pPresentationParameters->BackBufferWidth;
6314 mode.Height = pPresentationParameters->BackBufferHeight;
6315 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6316 mode.Format = swapchain->presentParms.BackBufferFormat;
6319 /* Should Width == 800 && Height == 0 set 800x600? */
6320 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6321 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6322 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6326 if(!pPresentationParameters->Windowed) {
6327 DisplayModeChanged = TRUE;
6329 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6330 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6332 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6335 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6339 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6341 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6344 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6348 if (This->auto_depth_stencil)
6350 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6353 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6359 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6360 || DisplayModeChanged)
6362 BOOL filter = This->filter_messages;
6363 This->filter_messages = TRUE;
6365 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6367 if (!pPresentationParameters->Windowed)
6369 if (swapchain->presentParms.Windowed)
6371 HWND focus_window = This->createParms.hFocusWindow;
6372 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6373 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6375 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6376 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6380 /* switch from windowed to fs */
6381 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6382 pPresentationParameters->BackBufferHeight);
6386 /* Fullscreen -> fullscreen mode change */
6387 MoveWindow(swapchain->device_window, 0, 0,
6388 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6392 else if (!swapchain->presentParms.Windowed)
6394 /* Fullscreen -> windowed switch */
6395 swapchain_restore_fullscreen_window(swapchain);
6396 IWineD3DDevice_ReleaseFocusWindow(iface);
6398 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6400 This->filter_messages = filter;
6402 else if (!pPresentationParameters->Windowed)
6404 DWORD style = This->style, exStyle = This->exStyle;
6405 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6406 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6407 * Reset to clear up their mess. Guild Wars also loses the device during that.
6411 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6412 pPresentationParameters->BackBufferHeight);
6413 This->style = style;
6414 This->exStyle = exStyle;
6417 /* Note: No parent needed for initial internal stateblock */
6418 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6419 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6420 else TRACE("Created stateblock %p\n", This->stateBlock);
6421 This->updateStateBlock = This->stateBlock;
6422 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6424 stateblock_init_default_state(This->stateBlock);
6426 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6429 GetClientRect(swapchain->win_handle, &client_rect);
6431 if(!swapchain->presentParms.BackBufferCount)
6433 TRACE("Single buffered rendering\n");
6434 swapchain->render_to_fbo = FALSE;
6436 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6437 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6439 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6440 swapchain->presentParms.BackBufferWidth,
6441 swapchain->presentParms.BackBufferHeight,
6442 client_rect.right, client_rect.bottom);
6443 swapchain->render_to_fbo = TRUE;
6447 TRACE("Rendering directly to GL_BACK\n");
6448 swapchain->render_to_fbo = FALSE;
6452 hr = create_primary_opengl_context(iface, swapchain);
6453 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6455 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6461 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6463 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6465 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6471 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6473 TRACE("(%p) : pParameters %p\n", This, pParameters);
6475 *pParameters = This->createParms;
6479 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6480 IWineD3DSwapChain *swapchain;
6482 TRACE("Relaying to swapchain\n");
6484 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6485 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6486 IWineD3DSwapChain_Release(swapchain);
6490 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6491 IWineD3DSwapChain *swapchain;
6493 TRACE("Relaying to swapchain\n");
6495 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6496 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6497 IWineD3DSwapChain_Release(swapchain);
6502 /** ********************************************************
6503 * Notification functions
6504 ** ********************************************************/
6505 /** This function must be called in the release of a resource when ref == 0,
6506 * the contents of resource must still be correct,
6507 * any handles to other resource held by the caller must be closed
6508 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6509 *****************************************************/
6510 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6512 TRACE("(%p) : Adding resource %p\n", This, resource);
6514 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6517 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6519 TRACE("(%p) : Removing resource %p\n", This, resource);
6521 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6524 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6526 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6529 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6531 context_resource_released(device, resource, type);
6535 case WINED3DRTYPE_SURFACE:
6536 if (!device->d3d_initialized) break;
6538 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6540 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6542 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6543 device->render_targets[i] = NULL;
6547 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6549 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6550 device->depth_stencil = NULL;
6554 case WINED3DRTYPE_TEXTURE:
6555 case WINED3DRTYPE_CUBETEXTURE:
6556 case WINED3DRTYPE_VOLUMETEXTURE:
6557 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6559 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6561 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6562 resource, device->stateBlock, i);
6563 device->stateBlock->state.textures[i] = NULL;
6566 if (device->updateStateBlock != device->stateBlock
6567 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6569 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6570 resource, device->updateStateBlock, i);
6571 device->updateStateBlock->state.textures[i] = NULL;
6576 case WINED3DRTYPE_BUFFER:
6577 for (i = 0; i < MAX_STREAMS; ++i)
6579 if (device->stateBlock
6580 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6582 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6583 resource, device->stateBlock, i);
6584 device->stateBlock->state.streams[i].buffer = NULL;
6587 if (device->updateStateBlock != device->stateBlock
6588 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6590 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6591 resource, device->updateStateBlock, i);
6592 device->updateStateBlock->state.streams[i].buffer = NULL;
6597 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6599 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6600 resource, device->stateBlock);
6601 device->stateBlock->state.index_buffer = NULL;
6604 if (device->updateStateBlock != device->stateBlock
6605 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6607 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6608 resource, device->updateStateBlock);
6609 device->updateStateBlock->state.index_buffer = NULL;
6617 /* Remove the resource from the resourceStore */
6618 device_resource_remove(device, resource);
6620 TRACE("Resource released.\n");
6623 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6625 IWineD3DResourceImpl *resource, *cursor;
6627 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6629 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6630 TRACE("enumerating resource %p\n", resource);
6631 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6632 ret = pCallback((IWineD3DResource *) resource, pData);
6633 if(ret == S_FALSE) {
6634 TRACE("Canceling enumeration\n");
6641 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6644 IWineD3DResourceImpl *resource;
6646 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6648 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6649 if (type == WINED3DRTYPE_SURFACE)
6651 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6653 TRACE("Found surface %p for dc %p.\n", resource, dc);
6654 *surface = (IWineD3DSurface *)resource;
6660 return WINED3DERR_INVALIDCALL;
6663 /**********************************************************
6664 * IWineD3DDevice VTbl follows
6665 **********************************************************/
6667 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6669 /*** IUnknown methods ***/
6670 IWineD3DDeviceImpl_QueryInterface,
6671 IWineD3DDeviceImpl_AddRef,
6672 IWineD3DDeviceImpl_Release,
6673 /*** IWineD3DDevice methods ***/
6674 /*** Creation methods**/
6675 IWineD3DDeviceImpl_CreateBuffer,
6676 IWineD3DDeviceImpl_CreateVertexBuffer,
6677 IWineD3DDeviceImpl_CreateIndexBuffer,
6678 IWineD3DDeviceImpl_CreateStateBlock,
6679 IWineD3DDeviceImpl_CreateSurface,
6680 IWineD3DDeviceImpl_CreateRendertargetView,
6681 IWineD3DDeviceImpl_CreateTexture,
6682 IWineD3DDeviceImpl_CreateVolumeTexture,
6683 IWineD3DDeviceImpl_CreateVolume,
6684 IWineD3DDeviceImpl_CreateCubeTexture,
6685 IWineD3DDeviceImpl_CreateQuery,
6686 IWineD3DDeviceImpl_CreateSwapChain,
6687 IWineD3DDeviceImpl_CreateVertexDeclaration,
6688 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6689 IWineD3DDeviceImpl_CreateVertexShader,
6690 IWineD3DDeviceImpl_CreateGeometryShader,
6691 IWineD3DDeviceImpl_CreatePixelShader,
6692 IWineD3DDeviceImpl_CreatePalette,
6693 /*** Odd functions **/
6694 IWineD3DDeviceImpl_Init3D,
6695 IWineD3DDeviceImpl_InitGDI,
6696 IWineD3DDeviceImpl_Uninit3D,
6697 IWineD3DDeviceImpl_UninitGDI,
6698 IWineD3DDeviceImpl_SetMultithreaded,
6699 IWineD3DDeviceImpl_EvictManagedResources,
6700 IWineD3DDeviceImpl_GetAvailableTextureMem,
6701 IWineD3DDeviceImpl_GetBackBuffer,
6702 IWineD3DDeviceImpl_GetCreationParameters,
6703 IWineD3DDeviceImpl_GetDeviceCaps,
6704 IWineD3DDeviceImpl_GetDirect3D,
6705 IWineD3DDeviceImpl_GetDisplayMode,
6706 IWineD3DDeviceImpl_SetDisplayMode,
6707 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6708 IWineD3DDeviceImpl_GetRasterStatus,
6709 IWineD3DDeviceImpl_GetSwapChain,
6710 IWineD3DDeviceImpl_Reset,
6711 IWineD3DDeviceImpl_SetDialogBoxMode,
6712 IWineD3DDeviceImpl_SetCursorProperties,
6713 IWineD3DDeviceImpl_SetCursorPosition,
6714 IWineD3DDeviceImpl_ShowCursor,
6715 /*** Getters and setters **/
6716 IWineD3DDeviceImpl_SetClipPlane,
6717 IWineD3DDeviceImpl_GetClipPlane,
6718 IWineD3DDeviceImpl_SetClipStatus,
6719 IWineD3DDeviceImpl_GetClipStatus,
6720 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6721 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6722 IWineD3DDeviceImpl_SetDepthStencilSurface,
6723 IWineD3DDeviceImpl_GetDepthStencilSurface,
6724 IWineD3DDeviceImpl_SetGammaRamp,
6725 IWineD3DDeviceImpl_GetGammaRamp,
6726 IWineD3DDeviceImpl_SetIndexBuffer,
6727 IWineD3DDeviceImpl_GetIndexBuffer,
6728 IWineD3DDeviceImpl_SetBaseVertexIndex,
6729 IWineD3DDeviceImpl_GetBaseVertexIndex,
6730 IWineD3DDeviceImpl_SetLight,
6731 IWineD3DDeviceImpl_GetLight,
6732 IWineD3DDeviceImpl_SetLightEnable,
6733 IWineD3DDeviceImpl_GetLightEnable,
6734 IWineD3DDeviceImpl_SetMaterial,
6735 IWineD3DDeviceImpl_GetMaterial,
6736 IWineD3DDeviceImpl_SetNPatchMode,
6737 IWineD3DDeviceImpl_GetNPatchMode,
6738 IWineD3DDeviceImpl_SetPaletteEntries,
6739 IWineD3DDeviceImpl_GetPaletteEntries,
6740 IWineD3DDeviceImpl_SetPixelShader,
6741 IWineD3DDeviceImpl_GetPixelShader,
6742 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6743 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6744 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6745 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6746 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6747 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6748 IWineD3DDeviceImpl_SetRenderState,
6749 IWineD3DDeviceImpl_GetRenderState,
6750 IWineD3DDeviceImpl_SetRenderTarget,
6751 IWineD3DDeviceImpl_GetRenderTarget,
6752 IWineD3DDeviceImpl_SetSamplerState,
6753 IWineD3DDeviceImpl_GetSamplerState,
6754 IWineD3DDeviceImpl_SetScissorRect,
6755 IWineD3DDeviceImpl_GetScissorRect,
6756 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6757 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6758 IWineD3DDeviceImpl_SetStreamSource,
6759 IWineD3DDeviceImpl_GetStreamSource,
6760 IWineD3DDeviceImpl_SetStreamSourceFreq,
6761 IWineD3DDeviceImpl_GetStreamSourceFreq,
6762 IWineD3DDeviceImpl_SetTexture,
6763 IWineD3DDeviceImpl_GetTexture,
6764 IWineD3DDeviceImpl_SetTextureStageState,
6765 IWineD3DDeviceImpl_GetTextureStageState,
6766 IWineD3DDeviceImpl_SetTransform,
6767 IWineD3DDeviceImpl_GetTransform,
6768 IWineD3DDeviceImpl_SetVertexDeclaration,
6769 IWineD3DDeviceImpl_GetVertexDeclaration,
6770 IWineD3DDeviceImpl_SetVertexShader,
6771 IWineD3DDeviceImpl_GetVertexShader,
6772 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6773 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6774 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6775 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6776 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6777 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6778 IWineD3DDeviceImpl_SetViewport,
6779 IWineD3DDeviceImpl_GetViewport,
6780 IWineD3DDeviceImpl_MultiplyTransform,
6781 IWineD3DDeviceImpl_ValidateDevice,
6782 IWineD3DDeviceImpl_ProcessVertices,
6783 /*** State block ***/
6784 IWineD3DDeviceImpl_BeginStateBlock,
6785 IWineD3DDeviceImpl_EndStateBlock,
6786 /*** Scene management ***/
6787 IWineD3DDeviceImpl_BeginScene,
6788 IWineD3DDeviceImpl_EndScene,
6789 IWineD3DDeviceImpl_Present,
6790 IWineD3DDeviceImpl_Clear,
6791 IWineD3DDeviceImpl_ClearRendertargetView,
6793 IWineD3DDeviceImpl_SetPrimitiveType,
6794 IWineD3DDeviceImpl_GetPrimitiveType,
6795 IWineD3DDeviceImpl_DrawPrimitive,
6796 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6797 IWineD3DDeviceImpl_DrawPrimitiveUP,
6798 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6799 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6800 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6801 IWineD3DDeviceImpl_DrawRectPatch,
6802 IWineD3DDeviceImpl_DrawTriPatch,
6803 IWineD3DDeviceImpl_DeletePatch,
6804 IWineD3DDeviceImpl_ColorFill,
6805 IWineD3DDeviceImpl_UpdateTexture,
6806 IWineD3DDeviceImpl_UpdateSurface,
6807 IWineD3DDeviceImpl_GetFrontBufferData,
6808 /*** object tracking ***/
6809 IWineD3DDeviceImpl_EnumResources,
6810 IWineD3DDeviceImpl_GetSurfaceFromDC,
6811 IWineD3DDeviceImpl_AcquireFocusWindow,
6812 IWineD3DDeviceImpl_ReleaseFocusWindow,
6815 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6816 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6817 IWineD3DDeviceParent *device_parent)
6819 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6820 const struct fragment_pipeline *fragment_pipeline;
6821 struct shader_caps shader_caps;
6822 struct fragment_caps ffp_caps;
6823 WINED3DDISPLAYMODE mode;
6827 device->lpVtbl = &IWineD3DDevice_Vtbl;
6829 device->wined3d = (IWineD3D *)wined3d;
6830 IWineD3D_AddRef(device->wined3d);
6831 device->adapter = wined3d->adapter_count ? adapter : NULL;
6832 device->device_parent = device_parent;
6833 list_init(&device->resources);
6834 list_init(&device->shaders);
6836 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6837 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6839 /* Get the initial screen setup for ddraw. */
6840 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6843 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6844 IWineD3D_Release(device->wined3d);
6847 device->ddraw_width = mode.Width;
6848 device->ddraw_height = mode.Height;
6849 device->ddraw_format = mode.Format;
6851 /* Save the creation parameters. */
6852 device->createParms.AdapterOrdinal = adapter_idx;
6853 device->createParms.DeviceType = device_type;
6854 device->createParms.hFocusWindow = focus_window;
6855 device->createParms.BehaviorFlags = flags;
6857 device->devType = device_type;
6858 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6860 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6861 device->shader_backend = adapter->shader_backend;
6863 if (device->shader_backend)
6865 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6866 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6867 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6868 device->vs_clipping = shader_caps.VSClipping;
6870 fragment_pipeline = adapter->fragment_pipe;
6871 device->frag_pipe = fragment_pipeline;
6872 if (fragment_pipeline)
6874 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6875 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6877 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6878 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6881 ERR("Failed to compile state table, hr %#x.\n", hr);
6882 IWineD3D_Release(device->wined3d);
6886 device->blitter = adapter->blitter;
6892 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6893 DWORD rep = This->StateTable[state].representative;
6894 struct wined3d_context *context;
6899 for(i = 0; i < This->numContexts; i++) {
6900 context = This->contexts[i];
6901 if(isStateDirty(context, rep)) continue;
6903 context->dirtyArray[context->numDirtyEntries++] = rep;
6904 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6905 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6906 context->isStateDirty[idx] |= (1 << shift);
6910 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6912 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6913 *width = context->current_rt->pow2Width;
6914 *height = context->current_rt->pow2Height;
6917 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6919 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6920 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6921 * current context's drawable, which is the size of the back buffer of the swapchain
6922 * the active context belongs to. */
6923 *width = swapchain->presentParms.BackBufferWidth;
6924 *height = swapchain->presentParms.BackBufferHeight;
6927 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6928 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6930 if (device->filter_messages)
6932 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6933 window, message, wparam, lparam);
6934 return DefWindowProcW(window, message, wparam, lparam);
6937 if (message == WM_DESTROY)
6939 TRACE("unregister window %p.\n", window);
6940 wined3d_unregister_window(window);
6942 if (device->focus_window == window) device->focus_window = NULL;
6943 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6946 return CallWindowProcW(proc, window, message, wparam, lparam);