2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009-2010 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
211 data = (BYTE *)buffer;
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory(buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
436 device->useDrawStridedSlow = FALSE;
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.texture_ops->texture_preload(texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
691 context_release(context);
692 WARN("Failed to apply clear state, skipping clear.\n");
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(¤t_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 IWineD3DResourceImpl *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
875 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource, debug_d3dresourcetype(type), type);
881 if(This->contexts) ERR("Context array not freed!\n");
882 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
883 This->haveHardwareCursor = FALSE;
885 IWineD3D_Release(This->wined3d);
886 This->wined3d = NULL;
887 HeapFree(GetProcessHeap(), 0, This);
888 TRACE("Freed device %p\n", This);
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
895 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 struct wined3d_buffer *object;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY;
910 FIXME("Ignoring access flags (pool)\n");
912 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
913 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
916 WARN("Failed to initialize buffer, hr %#x.\n", hr);
917 HeapFree(GetProcessHeap(), 0, object);
920 object->desc = *desc;
922 TRACE("Created buffer %p.\n", object);
924 *buffer = (IWineD3DBuffer *)object;
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
930 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
931 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 struct wined3d_buffer *object;
937 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
938 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
940 if (Pool == WINED3DPOOL_SCRATCH)
942 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
943 * anyway, SCRATCH vertex buffers aren't usable anywhere
945 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 *ppVertexBuffer = NULL;
947 return WINED3DERR_INVALIDCALL;
950 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
953 ERR("Out of memory\n");
954 *ppVertexBuffer = NULL;
955 return WINED3DERR_OUTOFVIDEOMEMORY;
958 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
959 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
962 WARN("Failed to initialize buffer, hr %#x.\n", hr);
963 HeapFree(GetProcessHeap(), 0, object);
967 TRACE("Created buffer %p.\n", object);
968 *ppVertexBuffer = (IWineD3DBuffer *)object;
973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
974 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
975 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
978 struct wined3d_buffer *object;
981 TRACE("(%p) Creating index buffer\n", This);
983 /* Allocate the storage for the device */
984 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
987 ERR("Out of memory\n");
988 *ppIndexBuffer = NULL;
989 return WINED3DERR_OUTOFVIDEOMEMORY;
992 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
993 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
997 WARN("Failed to initialize buffer, hr %#x\n", hr);
998 HeapFree(GetProcessHeap(), 0, object);
1002 TRACE("Created buffer %p.\n", object);
1004 *ppIndexBuffer = (IWineD3DBuffer *) object;
1009 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1010 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 IWineD3DStateBlockImpl *object;
1016 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1019 ERR("Failed to allocate stateblock memory.\n");
1020 return E_OUTOFMEMORY;
1023 hr = stateblock_init(object, This, type);
1026 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1027 HeapFree(GetProcessHeap(), 0, object);
1031 TRACE("Created stateblock %p.\n", object);
1032 *stateblock = (IWineD3DStateBlock *)object;
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1038 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1039 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1040 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1043 IWineD3DSurfaceImpl *object;
1046 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1047 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1048 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1049 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1050 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1052 if (Impl == SURFACE_OPENGL && !This->adapter)
1054 ERR("OpenGL surfaces are not available without OpenGL.\n");
1055 return WINED3DERR_NOTAVAILABLE;
1058 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1061 ERR("Failed to allocate surface memory.\n");
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1066 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1069 WARN("Failed to initialize surface, returning %#x.\n", hr);
1070 HeapFree(GetProcessHeap(), 0, object);
1074 TRACE("(%p) : Created surface %p\n", This, object);
1076 *surface = (IWineD3DSurface *)object;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1082 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1084 struct wined3d_rendertarget_view *object;
1086 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1087 iface, resource, parent, rendertarget_view);
1089 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1092 ERR("Failed to allocate memory\n");
1093 return E_OUTOFMEMORY;
1096 wined3d_rendertarget_view_init(object, (IWineD3DResourceImpl *)resource, parent);
1098 TRACE("Created render target view %p.\n", object);
1099 *rendertarget_view = (IWineD3DRendertargetView *)object;
1104 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1105 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1106 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1112 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1113 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1114 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1116 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1119 ERR("Out of memory\n");
1121 return WINED3DERR_OUTOFVIDEOMEMORY;
1124 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1127 WARN("Failed to initialize texture, returning %#x\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1133 *ppTexture = (IWineD3DTexture *)object;
1135 TRACE("(%p) : Created texture %p\n", This, object);
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1141 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1142 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DVolumeTextureImpl *object;
1148 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1149 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1151 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1154 ERR("Out of memory\n");
1155 *ppVolumeTexture = NULL;
1156 return WINED3DERR_OUTOFVIDEOMEMORY;
1159 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1162 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1163 HeapFree(GetProcessHeap(), 0, object);
1164 *ppVolumeTexture = NULL;
1168 TRACE("(%p) : Created volume texture %p.\n", This, object);
1169 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1175 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1176 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 IWineD3DVolumeImpl *object;
1182 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1183 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1185 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1188 ERR("Out of memory\n");
1190 return WINED3DERR_OUTOFVIDEOMEMORY;
1193 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1196 WARN("Failed to initialize volume, returning %#x.\n", hr);
1197 HeapFree(GetProcessHeap(), 0, object);
1201 TRACE("(%p) : Created volume %p.\n", This, object);
1202 *ppVolume = (IWineD3DVolume *)object;
1207 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1208 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1209 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1212 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1215 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1218 ERR("Out of memory\n");
1219 *ppCubeTexture = NULL;
1220 return WINED3DERR_OUTOFVIDEOMEMORY;
1223 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1226 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1227 HeapFree(GetProcessHeap(), 0, object);
1228 *ppCubeTexture = NULL;
1232 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1233 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1239 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1242 IWineD3DQueryImpl *object;
1245 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1247 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1250 ERR("Failed to allocate query memory.\n");
1251 return E_OUTOFMEMORY;
1254 hr = query_init(object, This, type);
1257 WARN("Failed to initialize query, hr %#x.\n", hr);
1258 HeapFree(GetProcessHeap(), 0, object);
1262 TRACE("Created query %p.\n", object);
1263 *query = (IWineD3DQuery *)object;
1268 /* Do not call while under the GL lock. */
1269 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1270 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1271 void *parent, IWineD3DSwapChain **swapchain)
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DSwapChainImpl *object;
1277 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1278 iface, present_parameters, swapchain, parent, surface_type);
1280 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1283 ERR("Failed to allocate swapchain memory.\n");
1284 return E_OUTOFMEMORY;
1287 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1290 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1291 HeapFree(GetProcessHeap(), 0, object);
1295 TRACE("Created swapchain %p.\n", object);
1296 *swapchain = (IWineD3DSwapChain *)object;
1301 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1302 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 TRACE("(%p)\n", This);
1306 return This->NumberOfSwapChains;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1311 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1313 if (iSwapChain < This->NumberOfSwapChains)
1315 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1316 IWineD3DSwapChain_AddRef(*pSwapChain);
1317 TRACE("(%p) returning %p\n", This, *pSwapChain);
1320 TRACE("Swapchain out of range\n");
1322 return WINED3DERR_INVALIDCALL;
1326 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1327 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1328 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1331 IWineD3DVertexDeclarationImpl *object = NULL;
1334 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1335 iface, declaration, parent, elements, element_count);
1337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1340 ERR("Failed to allocate vertex declaration memory.\n");
1341 return E_OUTOFMEMORY;
1344 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1347 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1348 HeapFree(GetProcessHeap(), 0, object);
1352 TRACE("Created vertex declaration %p.\n", object);
1353 *declaration = (IWineD3DVertexDeclaration *)object;
1358 struct wined3d_fvf_convert_state
1360 const struct wined3d_gl_info *gl_info;
1361 WINED3DVERTEXELEMENT *elements;
1366 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1367 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1369 WINED3DVERTEXELEMENT *elements = state->elements;
1370 const struct wined3d_format *format;
1371 UINT offset = state->offset;
1372 UINT idx = state->idx;
1374 elements[idx].format = format_id;
1375 elements[idx].input_slot = 0;
1376 elements[idx].offset = offset;
1377 elements[idx].output_slot = 0;
1378 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1379 elements[idx].usage = usage;
1380 elements[idx].usage_idx = usage_idx;
1382 format = wined3d_get_format(state->gl_info, format_id);
1383 state->offset += format->component_count * format->component_size;
1387 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1388 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1390 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1391 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1392 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1393 BOOL has_blend_idx = has_blend &&
1394 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1395 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1396 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1397 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1398 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1399 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1400 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1402 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1403 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1404 struct wined3d_fvf_convert_state state;
1407 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1408 if (has_blend_idx) num_blends--;
1410 /* Compute declaration size */
1411 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1412 has_psize + has_diffuse + has_specular + num_textures;
1414 state.gl_info = gl_info;
1415 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1416 if (!state.elements) return ~0U;
1422 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1424 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1425 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1427 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1430 if (has_blend && (num_blends > 0))
1432 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1433 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1439 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1448 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1451 ERR("Unexpected amount of blend values: %u\n", num_blends);
1458 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1459 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1460 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1462 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1464 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1467 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1468 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1469 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1470 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1472 for (idx = 0; idx < num_textures; ++idx)
1474 switch ((texcoords >> (idx * 2)) & 0x03)
1476 case WINED3DFVF_TEXTUREFORMAT1:
1477 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 case WINED3DFVF_TEXTUREFORMAT2:
1480 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 case WINED3DFVF_TEXTUREFORMAT3:
1483 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 case WINED3DFVF_TEXTUREFORMAT4:
1486 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1491 *ppVertexElements = state.elements;
1495 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1496 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1497 IWineD3DVertexDeclaration **declaration)
1499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1500 WINED3DVERTEXELEMENT *elements;
1504 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1506 size = ConvertFvfToDeclaration(This, fvf, &elements);
1507 if (size == ~0U) return E_OUTOFMEMORY;
1509 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1510 HeapFree(GetProcessHeap(), 0, elements);
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1515 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1516 void *parent, const struct wined3d_parent_ops *parent_ops,
1517 IWineD3DVertexShader **ppVertexShader)
1519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1520 IWineD3DVertexShaderImpl *object;
1523 if (This->vs_selected_mode == SHADER_NONE)
1524 return WINED3DERR_INVALIDCALL;
1526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1529 ERR("Failed to allocate shader memory.\n");
1530 return E_OUTOFMEMORY;
1533 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1536 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1537 HeapFree(GetProcessHeap(), 0, object);
1541 TRACE("Created vertex shader %p.\n", object);
1542 *ppVertexShader = (IWineD3DVertexShader *)object;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1548 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1549 void *parent, const struct wined3d_parent_ops *parent_ops,
1550 IWineD3DGeometryShader **shader)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 struct wined3d_geometryshader *object;
1556 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1559 ERR("Failed to allocate shader memory.\n");
1560 return E_OUTOFMEMORY;
1563 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1566 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1567 HeapFree(GetProcessHeap(), 0, object);
1571 TRACE("Created geometry shader %p.\n", object);
1572 *shader = (IWineD3DGeometryShader *)object;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1578 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1579 void *parent, const struct wined3d_parent_ops *parent_ops,
1580 IWineD3DPixelShader **ppPixelShader)
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 IWineD3DPixelShaderImpl *object;
1586 if (This->ps_selected_mode == SHADER_NONE)
1587 return WINED3DERR_INVALIDCALL;
1589 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1592 ERR("Failed to allocate shader memory.\n");
1593 return E_OUTOFMEMORY;
1596 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1599 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1600 HeapFree(GetProcessHeap(), 0, object);
1604 TRACE("Created pixel shader %p.\n", object);
1605 *ppPixelShader = (IWineD3DPixelShader *)object;
1610 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1611 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1614 IWineD3DPaletteImpl *object;
1617 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1618 iface, flags, PalEnt, Palette, parent);
1620 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1623 ERR("Failed to allocate palette memory.\n");
1624 return E_OUTOFMEMORY;
1627 hr = wined3d_palette_init(object, This, flags, PalEnt, parent);
1630 WARN("Failed to initialize palette, hr %#x.\n", hr);
1631 HeapFree(GetProcessHeap(), 0, object);
1635 TRACE("Created palette %p.\n", object);
1636 *Palette = (IWineD3DPalette *)object;
1641 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1645 HDC dcb = NULL, dcs = NULL;
1646 WINEDDCOLORKEY colorkey;
1648 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1651 GetObjectA(hbm, sizeof(BITMAP), &bm);
1652 dcb = CreateCompatibleDC(NULL);
1654 SelectObject(dcb, hbm);
1658 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1659 * couldn't be loaded
1661 memset(&bm, 0, sizeof(bm));
1666 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1667 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1668 &wined3d_null_parent_ops, &This->logo_surface);
1671 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1676 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1677 if(FAILED(hr)) goto out;
1678 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1679 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1681 colorkey.dwColorSpaceLowValue = 0;
1682 colorkey.dwColorSpaceHighValue = 0;
1683 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1687 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1688 /* Fill the surface with a white color to show that wined3d is there */
1689 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1693 if (dcb) DeleteDC(dcb);
1694 if (hbm) DeleteObject(hbm);
1697 /* Context activation is done by the caller. */
1698 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1700 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1702 /* Under DirectX you can have texture stage operations even if no texture is
1703 bound, whereas opengl will only do texture operations when a valid texture is
1704 bound. We emulate this by creating dummy textures and binding them to each
1705 texture stage, but disable all stages by default. Hence if a stage is enabled
1706 then the default texture will kick in until replaced by a SetTexture call */
1709 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1711 /* The dummy texture does not have client storage backing */
1712 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1713 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1716 for (i = 0; i < gl_info->limits.textures; ++i)
1718 GLubyte white = 255;
1720 /* Make appropriate texture active */
1721 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1722 checkGLcall("glActiveTextureARB");
1724 /* Generate an opengl texture name */
1725 glGenTextures(1, &This->dummyTextureName[i]);
1726 checkGLcall("glGenTextures");
1727 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1729 /* Generate a dummy 2d texture (not using 1d because they cause many
1730 * DRI drivers fall back to sw) */
1731 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1732 checkGLcall("glBindTexture");
1734 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1735 checkGLcall("glTexImage2D");
1738 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1740 /* Reenable because if supported it is enabled by default */
1741 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1742 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1748 /* Context activation is done by the caller. */
1749 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1752 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1753 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1756 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1759 static LONG fullscreen_style(LONG style)
1761 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1762 style |= WS_POPUP | WS_SYSMENU;
1763 style &= ~(WS_CAPTION | WS_THICKFRAME);
1768 static LONG fullscreen_exstyle(LONG exstyle)
1770 /* Filter out window decorations. */
1771 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1776 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1778 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1779 BOOL filter_messages;
1780 LONG style, exstyle;
1782 TRACE("Setting up window %p for fullscreen mode.\n", window);
1784 if (device->style || device->exStyle)
1786 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1787 window, device->style, device->exStyle);
1790 device->style = GetWindowLongW(window, GWL_STYLE);
1791 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1793 style = fullscreen_style(device->style);
1794 exstyle = fullscreen_exstyle(device->exStyle);
1796 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1797 device->style, device->exStyle, style, exstyle);
1799 filter_messages = device->filter_messages;
1800 device->filter_messages = TRUE;
1802 SetWindowLongW(window, GWL_STYLE, style);
1803 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1804 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1806 device->filter_messages = filter_messages;
1809 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1811 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1812 BOOL filter_messages;
1813 LONG style, exstyle;
1815 if (!device->style && !device->exStyle) return;
1817 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1818 window, device->style, device->exStyle);
1820 style = GetWindowLongW(window, GWL_STYLE);
1821 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1823 filter_messages = device->filter_messages;
1824 device->filter_messages = TRUE;
1826 /* Only restore the style if the application didn't modify it during the
1827 * fullscreen phase. Some applications change it before calling Reset()
1828 * when switching between windowed and fullscreen modes (HL2), some
1829 * depend on the original style (Eve Online). */
1830 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1832 SetWindowLongW(window, GWL_STYLE, device->style);
1833 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1835 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1837 device->filter_messages = filter_messages;
1839 /* Delete the old values. */
1841 device->exStyle = 0;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1846 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1848 TRACE("iface %p, window %p.\n", iface, window);
1850 if (!wined3d_register_window(window, device))
1852 ERR("Failed to register window %p.\n", window);
1856 device->focus_window = window;
1857 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1862 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1864 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1866 TRACE("iface %p.\n", iface);
1868 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1869 device->focus_window = NULL;
1872 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1873 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1876 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1877 IWineD3DSwapChainImpl *swapchain = NULL;
1878 struct wined3d_context *context;
1883 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1885 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1886 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1888 TRACE("(%p) : Creating stateblock\n", This);
1889 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1892 WARN("Failed to create stateblock\n");
1895 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1896 This->updateStateBlock = This->stateBlock;
1897 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1899 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1900 sizeof(*This->render_targets) * gl_info->limits.buffers);
1902 This->NumberOfPalettes = 1;
1903 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1904 if (!This->palettes || !This->render_targets)
1906 ERR("Out of memory!\n");
1910 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1911 if(!This->palettes[0]) {
1912 ERR("Out of memory!\n");
1916 for (i = 0; i < 256; ++i) {
1917 This->palettes[0][i].peRed = 0xFF;
1918 This->palettes[0][i].peGreen = 0xFF;
1919 This->palettes[0][i].peBlue = 0xFF;
1920 This->palettes[0][i].peFlags = 0xFF;
1922 This->currentPalette = 0;
1924 /* Initialize the texture unit mapping to a 1:1 mapping */
1925 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1927 if (state < gl_info->limits.fragment_samplers)
1929 This->texUnitMap[state] = state;
1930 This->rev_tex_unit_map[state] = state;
1932 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1933 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1937 /* Setup the implicit swapchain. This also initializes a context. */
1938 TRACE("Creating implicit swapchain\n");
1939 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1940 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1943 WARN("Failed to create implicit swapchain\n");
1947 This->NumberOfSwapChains = 1;
1948 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1949 if (!This->swapchains)
1951 ERR("Out of memory!\n");
1954 This->swapchains[0] = swapchain;
1956 if (swapchain->back_buffers && swapchain->back_buffers[0])
1958 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1959 This->render_targets[0] = swapchain->back_buffers[0];
1963 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1964 This->render_targets[0] = swapchain->front_buffer;
1966 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1968 /* Depth Stencil support */
1969 This->depth_stencil = This->auto_depth_stencil;
1970 if (This->depth_stencil)
1971 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1973 hr = This->shader_backend->shader_alloc_private(This);
1975 TRACE("Shader private data couldn't be allocated\n");
1978 hr = This->frag_pipe->alloc_private(This);
1980 TRACE("Fragment pipeline private data couldn't be allocated\n");
1983 hr = This->blitter->alloc_private(This);
1985 TRACE("Blitter private data couldn't be allocated\n");
1989 /* Set up some starting GL setup */
1991 /* Setup all the devices defaults */
1992 stateblock_init_default_state(This->stateBlock);
1994 context = context_acquire(This, swapchain->front_buffer);
1996 create_dummy_textures(This);
2000 /* Initialize the current view state */
2001 This->view_ident = 1;
2002 This->contexts[0]->last_was_rhw = 0;
2003 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2004 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2006 switch(wined3d_settings.offscreen_rendering_mode) {
2008 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2011 case ORM_BACKBUFFER:
2013 if (context_get_current()->aux_buffers > 0)
2015 TRACE("Using auxilliary buffer for offscreen rendering\n");
2016 This->offscreenBuffer = GL_AUX0;
2018 TRACE("Using back buffer for offscreen rendering\n");
2019 This->offscreenBuffer = GL_BACK;
2024 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2027 context_release(context);
2029 /* Clear the screen */
2030 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2031 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2034 This->d3d_initialized = TRUE;
2036 if(wined3d_settings.logo) {
2037 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2039 This->highest_dirty_ps_const = 0;
2040 This->highest_dirty_vs_const = 0;
2044 HeapFree(GetProcessHeap(), 0, This->render_targets);
2045 HeapFree(GetProcessHeap(), 0, This->swapchains);
2046 This->NumberOfSwapChains = 0;
2047 if(This->palettes) {
2048 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2049 HeapFree(GetProcessHeap(), 0, This->palettes);
2051 This->NumberOfPalettes = 0;
2053 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2055 if(This->stateBlock) {
2056 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2057 This->stateBlock = NULL;
2059 if (This->blit_priv) {
2060 This->blitter->free_private(This);
2062 if (This->fragment_priv) {
2063 This->frag_pipe->free_private(This);
2065 if (This->shader_priv) {
2066 This->shader_backend->shader_free_private(This);
2071 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2072 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 IWineD3DSwapChainImpl *swapchain = NULL;
2078 /* Setup the implicit swapchain */
2079 TRACE("Creating implicit swapchain\n");
2080 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2081 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 WARN("Failed to create implicit swapchain\n");
2088 This->NumberOfSwapChains = 1;
2089 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2090 if (!This->swapchains)
2092 ERR("Out of memory!\n");
2095 This->swapchains[0] = swapchain;
2099 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2103 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2105 IWineD3DResource_UnLoad(resource);
2106 IWineD3DResource_Release(resource);
2110 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2111 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2114 const struct wined3d_gl_info *gl_info;
2115 struct wined3d_context *context;
2118 TRACE("(%p)\n", This);
2120 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2122 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2123 * it was created. Thus make sure a context is active for the glDelete* calls
2125 context = context_acquire(This, NULL);
2126 gl_info = context->gl_info;
2128 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2130 /* Unload resources */
2131 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2133 TRACE("Deleting high order patches\n");
2134 for(i = 0; i < PATCHMAP_SIZE; i++) {
2135 struct list *e1, *e2;
2136 struct WineD3DRectPatch *patch;
2137 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2138 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2139 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2143 /* Delete the mouse cursor texture */
2144 if(This->cursorTexture) {
2146 glDeleteTextures(1, &This->cursorTexture);
2148 This->cursorTexture = 0;
2151 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2152 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2154 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2155 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2158 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2159 * private data, it might contain opengl pointers
2161 if(This->depth_blt_texture) {
2163 glDeleteTextures(1, &This->depth_blt_texture);
2165 This->depth_blt_texture = 0;
2167 if (This->depth_blt_rb) {
2169 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2171 This->depth_blt_rb = 0;
2172 This->depth_blt_rb_w = 0;
2173 This->depth_blt_rb_h = 0;
2176 /* Release the update stateblock */
2177 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2178 if(This->updateStateBlock != This->stateBlock)
2179 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2181 This->updateStateBlock = NULL;
2183 { /* because were not doing proper internal refcounts releasing the primary state block
2184 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2185 to set this->stateBlock = NULL; first */
2186 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2187 This->stateBlock = NULL;
2189 /* Release the stateblock */
2190 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2191 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2195 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2196 This->blitter->free_private(This);
2197 This->frag_pipe->free_private(This);
2198 This->shader_backend->shader_free_private(This);
2200 /* Release the buffers (with sanity checks)*/
2201 if (This->onscreen_depth_stencil)
2203 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2204 This->onscreen_depth_stencil = NULL;
2207 if (This->depth_stencil)
2209 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2211 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2213 This->depth_stencil = NULL;
2214 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2215 && ds != This->auto_depth_stencil)
2217 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2221 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2222 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2224 TRACE("Setting rendertarget to NULL\n");
2225 This->render_targets[0] = NULL;
2227 if (This->auto_depth_stencil)
2229 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2231 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2233 This->auto_depth_stencil = NULL;
2236 context_release(context);
2238 for (i = 0; i < This->NumberOfSwapChains; ++i)
2240 TRACE("Releasing the implicit swapchain %u.\n", i);
2241 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2243 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2247 HeapFree(GetProcessHeap(), 0, This->swapchains);
2248 This->swapchains = NULL;
2249 This->NumberOfSwapChains = 0;
2251 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2252 HeapFree(GetProcessHeap(), 0, This->palettes);
2253 This->palettes = NULL;
2254 This->NumberOfPalettes = 0;
2256 HeapFree(GetProcessHeap(), 0, This->render_targets);
2257 This->render_targets = NULL;
2259 This->d3d_initialized = FALSE;
2264 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2268 for (i = 0; i < This->NumberOfSwapChains; ++i)
2270 TRACE("Releasing the implicit swapchain %u.\n", i);
2271 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2273 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2277 HeapFree(GetProcessHeap(), 0, This->swapchains);
2278 This->swapchains = NULL;
2279 This->NumberOfSwapChains = 0;
2283 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2284 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2285 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2287 * There is no way to deactivate thread safety once it is enabled.
2289 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2292 /*For now just store the flag(needed in case of ddraw) */
2293 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2296 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2297 const WINED3DDISPLAYMODE* pMode) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2304 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2306 /* Resize the screen even without a window:
2307 * The app could have unset it with SetCooperativeLevel, but not called
2308 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2309 * but we don't have any hwnd
2312 memset(&devmode, 0, sizeof(devmode));
2313 devmode.dmSize = sizeof(devmode);
2314 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2315 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2316 devmode.dmPelsWidth = pMode->Width;
2317 devmode.dmPelsHeight = pMode->Height;
2319 devmode.dmDisplayFrequency = pMode->RefreshRate;
2320 if (pMode->RefreshRate)
2321 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2323 /* Only change the mode if necessary */
2324 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2325 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2328 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2329 if (ret != DISP_CHANGE_SUCCESSFUL)
2331 if (devmode.dmDisplayFrequency)
2333 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2334 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2335 devmode.dmDisplayFrequency = 0;
2336 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2338 if(ret != DISP_CHANGE_SUCCESSFUL) {
2339 return WINED3DERR_NOTAVAILABLE;
2343 /* Store the new values */
2344 This->ddraw_width = pMode->Width;
2345 This->ddraw_height = pMode->Height;
2346 This->ddraw_format = pMode->Format;
2348 /* And finally clip mouse to our screen */
2349 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2350 ClipCursor(&clip_rc);
2355 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2357 *ppD3D = This->wined3d;
2358 TRACE("Returning %p.\n", *ppD3D);
2359 IWineD3D_AddRef(*ppD3D);
2363 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2366 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2367 (This->adapter->TextureRam/(1024*1024)),
2368 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2369 /* return simulated texture memory left */
2370 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2374 * Get / Set Stream Source
2376 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2377 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 struct wined3d_stream_state *stream;
2381 IWineD3DBuffer *oldSrc;
2383 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2384 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2386 if (StreamNumber >= MAX_STREAMS) {
2387 WARN("Stream out of range %d\n", StreamNumber);
2388 return WINED3DERR_INVALIDCALL;
2389 } else if(OffsetInBytes & 0x3) {
2390 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2391 return WINED3DERR_INVALIDCALL;
2394 stream = &This->updateStateBlock->state.streams[StreamNumber];
2395 oldSrc = (IWineD3DBuffer *)stream->buffer;
2397 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2399 if (oldSrc == pStreamData
2400 && stream->stride == Stride
2401 && stream->offset == OffsetInBytes)
2403 TRACE("Application is setting the old values over, nothing to do\n");
2407 stream->buffer = (struct wined3d_buffer *)pStreamData;
2410 stream->stride = Stride;
2411 stream->offset = OffsetInBytes;
2414 /* Handle recording of state blocks */
2415 if (This->isRecordingState) {
2416 TRACE("Recording... not performing anything\n");
2417 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2418 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2424 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2425 IWineD3DBuffer_AddRef(pStreamData);
2429 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2430 IWineD3DBuffer_Release(oldSrc);
2433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2438 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2439 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 struct wined3d_stream_state *stream;
2444 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2445 iface, StreamNumber, pStream, pOffset, pStride);
2447 if (StreamNumber >= MAX_STREAMS)
2449 WARN("Stream out of range %d\n", StreamNumber);
2450 return WINED3DERR_INVALIDCALL;
2453 stream = &This->stateBlock->state.streams[StreamNumber];
2454 *pStream = (IWineD3DBuffer *)stream->buffer;
2455 *pStride = stream->stride;
2456 if (pOffset) *pOffset = stream->offset;
2458 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2463 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 struct wined3d_stream_state *stream;
2466 UINT old_flags, oldFreq;
2468 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2470 /* Verify input at least in d3d9 this is invalid. */
2471 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2473 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2474 return WINED3DERR_INVALIDCALL;
2476 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2478 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2479 return WINED3DERR_INVALIDCALL;
2483 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2484 return WINED3DERR_INVALIDCALL;
2487 stream = &This->updateStateBlock->state.streams[StreamNumber];
2488 old_flags = stream->flags;
2489 oldFreq = stream->frequency;
2491 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2492 stream->frequency = Divider & 0x7FFFFF;
2494 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2496 if (stream->frequency != oldFreq || stream->flags != old_flags)
2497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2502 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 struct wined3d_stream_state *stream;
2506 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2508 stream = &This->updateStateBlock->state.streams[StreamNumber];
2509 *Divider = stream->flags | stream->frequency;
2511 TRACE("Returning %#x.\n", *Divider);
2517 * Get / Set & Multiply Transform
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 /* Most of this routine, comments included copied from ddraw tree initially: */
2523 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2525 /* Handle recording of state blocks */
2526 if (This->isRecordingState) {
2527 TRACE("Recording... not performing anything\n");
2528 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2529 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2534 * If the new matrix is the same as the current one,
2535 * we cut off any further processing. this seems to be a reasonable
2536 * optimization because as was noticed, some apps (warcraft3 for example)
2537 * tend towards setting the same matrix repeatedly for some reason.
2539 * From here on we assume that the new matrix is different, wherever it matters.
2541 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2543 TRACE("The app is setting the same matrix over again\n");
2548 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2552 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2553 where ViewMat = Camera space, WorldMat = world space.
2555 In OpenGL, camera and world space is combined into GL_MODELVIEW
2556 matrix. The Projection matrix stay projection matrix.
2559 /* Capture the times we can just ignore the change for now */
2560 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2561 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2562 /* Handled by the state manager */
2565 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2572 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2573 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2575 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2577 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2579 *matrix = device->stateBlock->state.transforms[state];
2584 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2585 const WINED3DMATRIX *mat = NULL;
2588 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2589 * below means it will be recorded in a state block change, but it
2590 * works regardless where it is recorded.
2591 * If this is found to be wrong, change to StateBlock.
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2596 if (State <= HIGHEST_TRANSFORMSTATE)
2598 mat = &This->updateStateBlock->state.transforms[State];
2602 FIXME("Unhandled transform state!!\n");
2605 multiply_matrix(&temp, mat, pMatrix);
2607 /* Apply change via set transform - will reapply to eg. lights this way */
2608 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2614 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2615 you can reference any indexes you want as long as that number max are enabled at any
2616 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2617 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2618 but when recording, just build a chain pretty much of commands to be replayed. */
2620 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2622 struct wined3d_light_info *object = NULL;
2623 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2627 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2629 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2633 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2634 return WINED3DERR_INVALIDCALL;
2637 switch(pLight->Type) {
2638 case WINED3DLIGHT_POINT:
2639 case WINED3DLIGHT_SPOT:
2640 case WINED3DLIGHT_PARALLELPOINT:
2641 case WINED3DLIGHT_GLSPOT:
2642 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2645 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2647 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2648 return WINED3DERR_INVALIDCALL;
2652 case WINED3DLIGHT_DIRECTIONAL:
2653 /* Ignores attenuation */
2657 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2658 return WINED3DERR_INVALIDCALL;
2661 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2663 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2664 if(object->OriginalIndex == Index) break;
2669 TRACE("Adding new light\n");
2670 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2672 ERR("Out of memory error when allocating a light\n");
2673 return E_OUTOFMEMORY;
2675 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2676 object->glIndex = -1;
2677 object->OriginalIndex = Index;
2680 /* Initialize the object */
2681 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,
2682 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2683 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2684 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2685 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2686 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2687 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2689 /* Save away the information */
2690 object->OriginalParms = *pLight;
2692 switch (pLight->Type) {
2693 case WINED3DLIGHT_POINT:
2695 object->lightPosn[0] = pLight->Position.x;
2696 object->lightPosn[1] = pLight->Position.y;
2697 object->lightPosn[2] = pLight->Position.z;
2698 object->lightPosn[3] = 1.0f;
2699 object->cutoff = 180.0f;
2703 case WINED3DLIGHT_DIRECTIONAL:
2705 object->lightPosn[0] = -pLight->Direction.x;
2706 object->lightPosn[1] = -pLight->Direction.y;
2707 object->lightPosn[2] = -pLight->Direction.z;
2708 object->lightPosn[3] = 0.0f;
2709 object->exponent = 0.0f;
2710 object->cutoff = 180.0f;
2713 case WINED3DLIGHT_SPOT:
2715 object->lightPosn[0] = pLight->Position.x;
2716 object->lightPosn[1] = pLight->Position.y;
2717 object->lightPosn[2] = pLight->Position.z;
2718 object->lightPosn[3] = 1.0f;
2721 object->lightDirn[0] = pLight->Direction.x;
2722 object->lightDirn[1] = pLight->Direction.y;
2723 object->lightDirn[2] = pLight->Direction.z;
2724 object->lightDirn[3] = 1.0f;
2727 * opengl-ish and d3d-ish spot lights use too different models for the
2728 * light "intensity" as a function of the angle towards the main light direction,
2729 * so we only can approximate very roughly.
2730 * however spot lights are rather rarely used in games (if ever used at all).
2731 * furthermore if still used, probably nobody pays attention to such details.
2733 if (!pLight->Falloff)
2735 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2736 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2737 * will always be 1.0 for both of them, and we don't have to care for the
2738 * rest of the rather complex calculation
2740 object->exponent = 0.0f;
2742 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2743 if (rho < 0.0001f) rho = 0.0001f;
2744 object->exponent = -0.3f/logf(cosf(rho/2));
2746 if (object->exponent > 128.0f)
2748 object->exponent = 128.0f;
2750 object->cutoff = (float) (pLight->Phi*90/M_PI);
2756 FIXME("Unrecognized light type %d\n", pLight->Type);
2759 /* Update the live definitions if the light is currently assigned a glIndex */
2760 if (object->glIndex != -1 && !This->isRecordingState) {
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2766 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2768 struct wined3d_light_info *lightInfo = NULL;
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2770 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2772 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2774 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2776 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2777 if(lightInfo->OriginalIndex == Index) break;
2783 TRACE("Light information requested but light not defined\n");
2784 return WINED3DERR_INVALIDCALL;
2787 *pLight = lightInfo->OriginalParms;
2792 * Get / Set Light Enable
2793 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2797 struct wined3d_light_info *lightInfo = NULL;
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2801 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2803 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2805 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2806 if(lightInfo->OriginalIndex == Index) break;
2809 TRACE("Found light: %p\n", lightInfo);
2811 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2814 TRACE("Light enabled requested but light not defined, so defining one!\n");
2815 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2817 /* Search for it again! Should be fairly quick as near head of list */
2818 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2820 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2821 if(lightInfo->OriginalIndex == Index) break;
2826 FIXME("Adding default lights has failed dismally\n");
2827 return WINED3DERR_INVALIDCALL;
2832 if(lightInfo->glIndex != -1) {
2833 if(!This->isRecordingState) {
2834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2837 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2838 lightInfo->glIndex = -1;
2840 TRACE("Light already disabled, nothing to do\n");
2842 lightInfo->enabled = FALSE;
2844 lightInfo->enabled = TRUE;
2845 if (lightInfo->glIndex != -1) {
2847 TRACE("Nothing to do as light was enabled\n");
2850 /* Find a free gl light */
2851 for (i = 0; i < This->maxConcurrentLights; ++i)
2853 if (!This->updateStateBlock->state.lights[i])
2855 This->updateStateBlock->state.lights[i] = lightInfo;
2856 lightInfo->glIndex = i;
2860 if(lightInfo->glIndex == -1) {
2861 /* Our tests show that Windows returns D3D_OK in this situation, even with
2862 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2863 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2864 * as well for those lights.
2866 * TODO: Test how this affects rendering
2868 WARN("Too many concurrently active lights\n");
2872 /* i == lightInfo->glIndex */
2873 if(!This->isRecordingState) {
2874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2882 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2884 struct wined3d_light_info *lightInfo = NULL;
2885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2888 TRACE("(%p) : for idx(%d)\n", This, Index);
2890 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2892 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2893 if(lightInfo->OriginalIndex == Index) break;
2899 TRACE("Light enabled state requested but light not defined\n");
2900 return WINED3DERR_INVALIDCALL;
2902 /* true is 128 according to SetLightEnable */
2903 *pEnable = lightInfo->enabled ? 128 : 0;
2908 * Get / Set Clip Planes
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2914 /* Validate Index */
2915 if (Index >= This->adapter->gl_info.limits.clipplanes)
2917 TRACE("Application has requested clipplane this device doesn't support\n");
2918 return WINED3DERR_INVALIDCALL;
2921 This->updateStateBlock->changed.clipplane |= 1 << Index;
2923 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2924 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2925 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2926 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2928 TRACE("Application is setting old values over, nothing to do\n");
2932 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2933 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2934 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2935 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2937 /* Handle recording of state blocks */
2938 if (This->isRecordingState) {
2939 TRACE("Recording... not performing anything\n");
2943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2948 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 TRACE("(%p) : for idx %d\n", This, Index);
2952 /* Validate Index */
2953 if (Index >= This->adapter->gl_info.limits.clipplanes)
2955 TRACE("Application has requested clipplane this device doesn't support\n");
2956 return WINED3DERR_INVALIDCALL;
2959 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2960 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2961 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2962 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2967 * Get / Set Clip Plane Status
2968 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2970 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 FIXME("(%p) : stub\n", This);
2975 return WINED3DERR_INVALIDCALL;
2977 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2978 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2982 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 FIXME("(%p) : stub\n", This);
2987 return WINED3DERR_INVALIDCALL;
2989 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2990 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2995 * Get / Set Material
2997 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 This->updateStateBlock->changed.material = TRUE;
3001 This->updateStateBlock->state.material = *pMaterial;
3003 /* Handle recording of state blocks */
3004 if (This->isRecordingState) {
3005 TRACE("Recording... not performing anything\n");
3009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3013 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 *pMaterial = This->updateStateBlock->state.material;
3016 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3017 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3018 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3019 pMaterial->Ambient.b, pMaterial->Ambient.a);
3020 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3021 pMaterial->Specular.b, pMaterial->Specular.a);
3022 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3023 pMaterial->Emissive.b, pMaterial->Emissive.a);
3024 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3032 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3033 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 IWineD3DBuffer *oldIdxs;
3038 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3039 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3041 This->updateStateBlock->changed.indices = TRUE;
3042 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3043 This->updateStateBlock->state.index_format = fmt;
3045 /* Handle recording of state blocks */
3046 if (This->isRecordingState) {
3047 TRACE("Recording... not performing anything\n");
3048 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3049 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3053 if(oldIdxs != pIndexData) {
3054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3056 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3057 IWineD3DBuffer_AddRef(pIndexData);
3060 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3061 IWineD3DBuffer_Release(oldIdxs);
3068 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3072 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3074 /* up ref count on ppindexdata */
3076 IWineD3DBuffer_AddRef(*ppIndexData);
3077 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3079 TRACE("(%p) No index data set\n", This);
3081 TRACE("Returning %p\n", *ppIndexData);
3086 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3087 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 TRACE("(%p)->(%d)\n", This, BaseIndex);
3091 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3093 TRACE("Application is setting the old value over, nothing to do\n");
3097 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3099 if (This->isRecordingState) {
3100 TRACE("Recording... not performing anything\n");
3103 /* The base vertex index affects the stream sources */
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 TRACE("(%p) : base_index %p\n", This, base_index);
3112 *base_index = This->stateBlock->state.base_vertex_index;
3114 TRACE("Returning %u\n", *base_index);
3120 * Get / Set Viewports
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 TRACE("(%p)\n", This);
3126 This->updateStateBlock->changed.viewport = TRUE;
3127 This->updateStateBlock->state.viewport = *pViewport;
3129 /* Handle recording of state blocks */
3130 if (This->isRecordingState) {
3131 TRACE("Recording... not performing anything\n");
3135 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3136 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p)\n", This);
3146 *pViewport = This->stateBlock->state.viewport;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3151 WINED3DRENDERSTATETYPE State, DWORD Value)
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 DWORD oldValue = This->stateBlock->state.render_states[State];
3156 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3158 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3159 This->updateStateBlock->state.render_states[State] = Value;
3161 /* Handle recording of state blocks */
3162 if (This->isRecordingState) {
3163 TRACE("Recording... not performing anything\n");
3167 /* Compared here and not before the assignment to allow proper stateblock recording */
3168 if(Value == oldValue) {
3169 TRACE("Application is setting the old value over, nothing to do\n");
3171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3178 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3184 *pValue = This->stateBlock->state.render_states[State];
3189 * Get / Set Sampler States
3190 * TODO: Verify against dx9 definitions
3193 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3198 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3200 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3201 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3204 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3206 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3207 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3210 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3211 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3212 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3214 /* Handle recording of state blocks */
3215 if (This->isRecordingState) {
3216 TRACE("Recording... not performing anything\n");
3220 if(oldValue == Value) {
3221 TRACE("Application is setting the old value over, nothing to do\n");
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3234 This, Sampler, debug_d3dsamplerstate(Type), Type);
3236 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3237 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3240 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3242 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3243 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3245 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3246 TRACE("(%p) : Returning %#x\n", This, *Value);
3251 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254 This->updateStateBlock->changed.scissorRect = TRUE;
3255 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3257 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3260 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3262 if(This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 *pRect = This->updateStateBlock->state.scissor_rect;
3276 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3280 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3282 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3284 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3286 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3287 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3289 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3290 This->updateStateBlock->changed.vertexDecl = TRUE;
3292 if (This->isRecordingState) {
3293 TRACE("Recording... not performing anything\n");
3295 } else if(pDecl == oldDecl) {
3296 /* Checked after the assignment to allow proper stateblock recording */
3297 TRACE("Application is setting the old declaration over, nothing to do\n");
3301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3305 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3310 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3311 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3315 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3320 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3321 This->updateStateBlock->changed.vertexShader = TRUE;
3323 if (This->isRecordingState) {
3324 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3325 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3326 TRACE("Recording... not performing anything\n");
3328 } else if(oldShader == pShader) {
3329 /* Checked here to allow proper stateblock recording */
3330 TRACE("App is setting the old shader over, nothing to do\n");
3334 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3335 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3336 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3343 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3345 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3346 IWineD3DVertexShader *shader;
3348 TRACE("iface %p.\n", iface);
3350 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3351 if (shader) IWineD3DVertexShader_AddRef(shader);
3353 TRACE("Returning %p.\n", shader);
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3358 IWineD3DDevice *iface,
3360 CONST BOOL *srcData,
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3366 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3367 iface, srcData, start, count);
3369 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3371 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3372 for (i = 0; i < cnt; i++)
3373 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3375 for (i = start; i < cnt + start; ++i) {
3376 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3379 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3385 IWineD3DDevice *iface,
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 int cnt = min(count, MAX_CONST_B - start);
3393 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3394 iface, dstData, start, count);
3396 if (!dstData || cnt < 0)
3397 return WINED3DERR_INVALIDCALL;
3399 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3404 IWineD3DDevice *iface,
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3412 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3413 iface, srcData, start, count);
3415 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3417 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3418 for (i = 0; i < cnt; i++)
3419 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3420 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3422 for (i = start; i < cnt + start; ++i) {
3423 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3426 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3431 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3432 IWineD3DDevice *iface,
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3438 int cnt = min(count, MAX_CONST_I - start);
3440 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3441 iface, dstData, start, count);
3443 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3444 return WINED3DERR_INVALIDCALL;
3446 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3450 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3451 IWineD3DDevice *iface,
3453 CONST float *srcData,
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3459 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3460 iface, srcData, start, count);
3462 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3463 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3464 return WINED3DERR_INVALIDCALL;
3466 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3468 for (i = 0; i < count; i++)
3469 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3470 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3473 if (!This->isRecordingState)
3475 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3479 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3480 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3485 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3486 IWineD3DDevice *iface,
3491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3492 int cnt = min(count, This->d3d_vshader_constantF - start);
3494 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3495 iface, dstData, start, count);
3497 if (!dstData || cnt < 0)
3498 return WINED3DERR_INVALIDCALL;
3500 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3504 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3506 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3512 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3514 DWORD i = This->rev_tex_unit_map[unit];
3515 DWORD j = This->texUnitMap[stage];
3517 This->texUnitMap[stage] = unit;
3518 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3520 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3523 This->rev_tex_unit_map[unit] = stage;
3524 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3526 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3530 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3533 This->fixed_function_usage_map = 0;
3534 for (i = 0; i < MAX_TEXTURES; ++i)
3536 const struct wined3d_state *state = &This->stateBlock->state;
3537 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3538 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3539 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3540 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3541 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3542 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3543 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3544 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3546 if (color_op == WINED3DTOP_DISABLE) {
3547 /* Not used, and disable higher stages */
3551 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3552 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3553 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3554 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3555 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3556 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3557 This->fixed_function_usage_map |= (1 << i);
3560 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3561 This->fixed_function_usage_map |= (1 << (i + 1));
3566 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3568 unsigned int i, tex;
3571 device_update_fixed_function_usage_map(This);
3572 ffu_map = This->fixed_function_usage_map;
3574 if (This->max_ffp_textures == gl_info->limits.texture_stages
3575 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3577 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3579 if (!(ffu_map & 1)) continue;
3581 if (This->texUnitMap[i] != i) {
3582 device_map_stage(This, i, i);
3583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3584 markTextureStagesDirty(This, i);
3590 /* Now work out the mapping */
3592 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3594 if (!(ffu_map & 1)) continue;
3596 if (This->texUnitMap[i] != tex) {
3597 device_map_stage(This, i, tex);
3598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3599 markTextureStagesDirty(This, i);
3606 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3608 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3609 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3612 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3613 if (sampler_type[i] && This->texUnitMap[i] != i)
3615 device_map_stage(This, i, i);
3616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3617 if (i < gl_info->limits.texture_stages)
3619 markTextureStagesDirty(This, i);
3625 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3626 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3628 DWORD current_mapping = This->rev_tex_unit_map[unit];
3630 /* Not currently used */
3631 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3633 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3634 /* Used by a fragment sampler */
3636 if (!pshader_sampler_tokens) {
3637 /* No pixel shader, check fixed function */
3638 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3641 /* Pixel shader, check the shader's sampler map */
3642 return !pshader_sampler_tokens[current_mapping];
3645 /* Used by a vertex sampler */
3646 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3649 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3651 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3652 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3653 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3654 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3659 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3661 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3662 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3663 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3666 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3667 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3668 if (vshader_sampler_type[i])
3670 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3672 /* Already mapped somewhere */
3676 while (start >= 0) {
3677 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3679 device_map_stage(This, vsampler_idx, start);
3680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3692 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3695 const struct wined3d_state *state = &This->stateBlock->state;
3696 BOOL vs = use_vs(state);
3697 BOOL ps = use_ps(state);
3700 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3701 * that would be really messy and require shader recompilation
3702 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3703 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3705 if (ps) device_map_psamplers(This, gl_info);
3706 else device_map_fixed_function_samplers(This, gl_info);
3708 if (vs) device_map_vsamplers(This, ps, gl_info);
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3715 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3716 This->updateStateBlock->changed.pixelShader = TRUE;
3718 /* Handle recording of state blocks */
3719 if (This->isRecordingState) {
3720 TRACE("Recording... not performing anything\n");
3723 if (This->isRecordingState) {
3724 TRACE("Recording... not performing anything\n");
3725 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3726 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3730 if(pShader == oldShader) {
3731 TRACE("App is setting the old pixel shader over, nothing to do\n");
3735 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3736 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3738 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3744 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3746 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3747 IWineD3DPixelShader *shader;
3749 TRACE("iface %p.\n", iface);
3751 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3752 if (shader) IWineD3DPixelShader_AddRef(shader);
3754 TRACE("Returning %p.\n", shader);
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3759 IWineD3DDevice *iface,
3761 CONST BOOL *srcData,
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3767 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3768 iface, srcData, start, count);
3770 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3772 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3773 for (i = 0; i < cnt; i++)
3774 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3776 for (i = start; i < cnt + start; ++i) {
3777 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3780 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3785 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3786 IWineD3DDevice *iface,
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 int cnt = min(count, MAX_CONST_B - start);
3794 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3795 iface, dstData, start, count);
3797 if (!dstData || cnt < 0)
3798 return WINED3DERR_INVALIDCALL;
3800 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3804 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3805 IWineD3DDevice *iface,
3810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3811 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3813 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3814 iface, srcData, start, count);
3816 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3818 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3819 for (i = 0; i < cnt; i++)
3820 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3821 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3823 for (i = start; i < cnt + start; ++i) {
3824 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3827 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3832 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3833 IWineD3DDevice *iface,
3838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3839 int cnt = min(count, MAX_CONST_I - start);
3841 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3842 iface, dstData, start, count);
3844 if (!dstData || cnt < 0)
3845 return WINED3DERR_INVALIDCALL;
3847 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3851 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3852 IWineD3DDevice *iface,
3854 CONST float *srcData,
3857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3860 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3861 iface, srcData, start, count);
3863 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3864 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3865 return WINED3DERR_INVALIDCALL;
3867 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3869 for (i = 0; i < count; i++)
3870 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3871 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3874 if (!This->isRecordingState)
3876 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3880 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3881 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3886 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3887 IWineD3DDevice *iface,
3892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3893 int cnt = min(count, This->d3d_pshader_constantF - start);
3895 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3896 iface, dstData, start, count);
3898 if (!dstData || cnt < 0)
3899 return WINED3DERR_INVALIDCALL;
3901 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3905 /* Context activation is done by the caller. */
3906 /* Do not call while under the GL lock. */
3907 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3908 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3909 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3912 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3913 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3916 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3920 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3922 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3925 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3927 ERR("Source has no position mask\n");
3928 return WINED3DERR_INVALIDCALL;
3931 if (!dest->resource.allocatedMemory)
3932 buffer_get_sysmem(dest, gl_info);
3934 /* Get a pointer into the destination vbo(create one if none exists) and
3935 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3937 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3939 dest->flags |= WINED3D_BUFFER_CREATEBO;
3940 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3943 if (dest->buffer_object)
3945 unsigned char extrabytes = 0;
3946 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3947 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3948 * this may write 4 extra bytes beyond the area that should be written
3950 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3951 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3952 if(!dest_conv_addr) {
3953 ERR("Out of memory\n");
3954 /* Continue without storing converted vertices */
3956 dest_conv = dest_conv_addr;
3959 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3961 static BOOL warned = FALSE;
3963 * The clipping code is not quite correct. Some things need
3964 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3965 * so disable clipping for now.
3966 * (The graphics in Half-Life are broken, and my processvertices
3967 * test crashes with IDirect3DDevice3)
3973 FIXME("Clipping is broken and disabled for now\n");
3975 } else doClip = FALSE;
3976 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3978 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3981 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3982 WINED3DTS_PROJECTION,
3984 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3985 WINED3DTS_WORLDMATRIX(0),
3988 TRACE("View mat:\n");
3989 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);
3990 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);
3991 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);
3992 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);
3994 TRACE("Proj mat:\n");
3995 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);
3996 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);
3997 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);
3998 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);
4000 TRACE("World mat:\n");
4001 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);
4002 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);
4003 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);
4004 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);
4006 /* Get the viewport */
4007 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4008 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4009 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4011 multiply_matrix(&mat,&view_mat,&world_mat);
4012 multiply_matrix(&mat,&proj_mat,&mat);
4014 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4016 for (i = 0; i < dwCount; i+= 1) {
4017 unsigned int tex_index;
4019 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4020 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4021 /* The position first */
4022 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4023 const float *p = (const float *)(element->data + i * element->stride);
4025 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4027 /* Multiplication with world, view and projection matrix */
4028 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);
4029 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);
4030 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);
4031 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);
4033 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4035 /* WARNING: The following things are taken from d3d7 and were not yet checked
4036 * against d3d8 or d3d9!
4039 /* Clipping conditions: From msdn
4041 * A vertex is clipped if it does not match the following requirements
4045 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4047 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4048 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4053 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4054 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4057 /* "Normal" viewport transformation (not clipped)
4058 * 1) The values are divided by rhw
4059 * 2) The y axis is negative, so multiply it with -1
4060 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4061 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4062 * 4) Multiply x with Width/2 and add Width/2
4063 * 5) The same for the height
4064 * 6) Add the viewpoint X and Y to the 2D coordinates and
4065 * The minimum Z value to z
4066 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4068 * Well, basically it's simply a linear transformation into viewport
4080 z *= vp.MaxZ - vp.MinZ;
4082 x += vp.Width / 2 + vp.X;
4083 y += vp.Height / 2 + vp.Y;
4088 /* That vertex got clipped
4089 * Contrary to OpenGL it is not dropped completely, it just
4090 * undergoes a different calculation.
4092 TRACE("Vertex got clipped\n");
4099 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4100 * outside of the main vertex buffer memory. That needs some more
4105 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4108 ( (float *) dest_ptr)[0] = x;
4109 ( (float *) dest_ptr)[1] = y;
4110 ( (float *) dest_ptr)[2] = z;
4111 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4113 dest_ptr += 3 * sizeof(float);
4115 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4116 dest_ptr += sizeof(float);
4121 ( (float *) dest_conv)[0] = x * w;
4122 ( (float *) dest_conv)[1] = y * w;
4123 ( (float *) dest_conv)[2] = z * w;
4124 ( (float *) dest_conv)[3] = w;
4126 dest_conv += 3 * sizeof(float);
4128 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4129 dest_conv += sizeof(float);
4133 if (DestFVF & WINED3DFVF_PSIZE) {
4134 dest_ptr += sizeof(DWORD);
4135 if(dest_conv) dest_conv += sizeof(DWORD);
4137 if (DestFVF & WINED3DFVF_NORMAL) {
4138 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4139 const float *normal = (const float *)(element->data + i * element->stride);
4140 /* AFAIK this should go into the lighting information */
4141 FIXME("Didn't expect the destination to have a normal\n");
4142 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4144 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4148 if (DestFVF & WINED3DFVF_DIFFUSE) {
4149 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4150 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4151 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4153 static BOOL warned = FALSE;
4156 ERR("No diffuse color in source, but destination has one\n");
4160 *( (DWORD *) dest_ptr) = 0xffffffff;
4161 dest_ptr += sizeof(DWORD);
4164 *( (DWORD *) dest_conv) = 0xffffffff;
4165 dest_conv += sizeof(DWORD);
4169 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4171 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4172 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4173 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4174 dest_conv += sizeof(DWORD);
4179 if (DestFVF & WINED3DFVF_SPECULAR)
4181 /* What's the color value in the feedback buffer? */
4182 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4183 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4184 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4186 static BOOL warned = FALSE;
4189 ERR("No specular color in source, but destination has one\n");
4193 *( (DWORD *) dest_ptr) = 0xFF000000;
4194 dest_ptr += sizeof(DWORD);
4197 *( (DWORD *) dest_conv) = 0xFF000000;
4198 dest_conv += sizeof(DWORD);
4202 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4204 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4205 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4206 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4207 dest_conv += sizeof(DWORD);
4212 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4213 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4214 const float *tex_coord = (const float *)(element->data + i * element->stride);
4215 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4217 ERR("No source texture, but destination requests one\n");
4218 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4219 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4222 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4224 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4234 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4235 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4236 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4237 dwCount * get_flexible_vertex_size(DestFVF),
4239 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4243 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4248 #undef copy_and_next
4250 /* Do not call while under the GL lock. */
4251 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4252 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD flags,
4255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4256 struct wined3d_stream_info stream_info;
4257 const struct wined3d_gl_info *gl_info;
4258 struct wined3d_context *context;
4259 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4262 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4265 ERR("Output vertex declaration not implemented yet\n");
4268 /* Need any context to write to the vbo. */
4269 context = context_acquire(This, NULL);
4270 gl_info = context->gl_info;
4272 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4273 * control the streamIsUP flag, thus restore it afterwards.
4275 This->stateBlock->state.user_stream = FALSE;
4276 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4277 This->stateBlock->state.user_stream = streamWasUP;
4279 if(vbo || SrcStartIndex) {
4281 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4282 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4284 * Also get the start index in, but only loop over all elements if there's something to add at all.
4286 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4288 struct wined3d_stream_info_element *e;
4290 if (!(stream_info.use_map & (1 << i))) continue;
4292 e = &stream_info.elements[i];
4293 if (e->buffer_object)
4295 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4296 e->buffer_object = 0;
4297 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4299 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4300 vb->buffer_object = 0;
4303 if (e->data) e->data += e->stride * SrcStartIndex;
4307 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4308 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4310 context_release(context);
4316 * Get / Set Texture Stage States
4317 * TODO: Verify against dx9 definitions
4319 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4322 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4325 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4327 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4329 WARN("Invalid Type %d passed.\n", Type);
4333 if (Stage >= gl_info->limits.texture_stages)
4335 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4336 Stage, gl_info->limits.texture_stages - 1);
4340 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4341 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4342 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4344 if (This->isRecordingState) {
4345 TRACE("Recording... not performing anything\n");
4349 /* Checked after the assignments to allow proper stateblock recording */
4350 if(oldValue == Value) {
4351 TRACE("App is setting the old value over, nothing to do\n");
4355 if (Stage > This->stateBlock->state.lowest_disabled_stage
4356 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4357 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4359 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4360 * Changes in other states are important on disabled stages too
4365 if(Type == WINED3DTSS_COLOROP) {
4368 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4369 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4370 * they have to be disabled
4372 * The current stage is dirtified below.
4374 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4376 TRACE("Additionally dirtifying stage %u\n", i);
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4379 This->stateBlock->state.lowest_disabled_stage = Stage;
4380 TRACE("New lowest disabled: %u\n", Stage);
4381 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4382 /* Previously disabled stage enabled. Stages above it may need enabling
4383 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4384 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4386 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4389 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4391 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4393 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4396 This->stateBlock->state.lowest_disabled_stage = i;
4397 TRACE("New lowest disabled: %u\n", i);
4401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4406 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4410 TRACE("iface %p, stage %u, state %s, value %p.\n",
4411 iface, Stage, debug_d3dtexturestate(Type), pValue);
4413 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4415 WARN("Invalid Type %d passed.\n", Type);
4419 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4420 TRACE("Returning %#x.\n", *pValue);
4428 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4429 DWORD stage, IWineD3DBaseTexture *texture)
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4433 IWineD3DBaseTexture *prev;
4435 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4437 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4438 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4440 /* Windows accepts overflowing this array... we do not. */
4441 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4443 WARN("Ignoring invalid stage %u.\n", stage);
4447 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4448 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4450 WARN("Rejecting attempt to set scratch texture.\n");
4451 return WINED3DERR_INVALIDCALL;
4454 This->updateStateBlock->changed.textures |= 1 << stage;
4456 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4457 TRACE("Previous texture %p.\n", prev);
4459 if (texture == prev)
4461 TRACE("App is setting the same texture again, nothing to do.\n");
4465 TRACE("Setting new texture to %p.\n", texture);
4466 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4468 if (This->isRecordingState)
4470 TRACE("Recording... not performing anything\n");
4472 if (texture) IWineD3DBaseTexture_AddRef(texture);
4473 if (prev) IWineD3DBaseTexture_Release(prev);
4480 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4481 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4482 GLenum dimensions = t->baseTexture.target;
4484 IWineD3DBaseTexture_AddRef(texture);
4486 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4489 if (!prev && stage < gl_info->limits.texture_stages)
4491 /* The source arguments for color and alpha ops have different
4492 * meanings when a NULL texture is bound, so the COLOROP and
4493 * ALPHAOP have to be dirtified. */
4494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4498 if (bind_count == 1) t->baseTexture.sampler = stage;
4503 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4504 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4506 IWineD3DBaseTexture_Release(prev);
4508 if (!texture && stage < gl_info->limits.texture_stages)
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4514 if (bind_count && t->baseTexture.sampler == stage)
4518 /* Search for other stages the texture is bound to. Shouldn't
4519 * happen if applications bind textures to a single stage only. */
4520 TRACE("Searching for other stages the texture is bound to.\n");
4521 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4523 if (This->updateStateBlock->state.textures[i] == t)
4525 TRACE("Texture is also bound to stage %u.\n", i);
4526 t->baseTexture.sampler = i;
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4538 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4541 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4543 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4544 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4547 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4549 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4550 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4553 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4555 IWineD3DBaseTexture_AddRef(*ppTexture);
4557 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4565 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4566 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4568 IWineD3DSwapChain *swapchain;
4571 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4572 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4574 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4577 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4581 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4582 IWineD3DSwapChain_Release(swapchain);
4585 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4592 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4594 WARN("(%p) : stub, calling idirect3d for now\n", This);
4595 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4598 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4600 IWineD3DSwapChain *swapChain;
4603 if(iSwapChain > 0) {
4604 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4605 if (hr == WINED3D_OK) {
4606 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4607 IWineD3DSwapChain_Release(swapChain);
4609 FIXME("(%p) Error getting display mode\n", This);
4612 /* Don't read the real display mode,
4613 but return the stored mode instead. X11 can't change the color
4614 depth, and some apps are pretty angry if they SetDisplayMode from
4615 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4617 Also don't relay to the swapchain because with ddraw it's possible
4618 that there isn't a swapchain at all */
4619 pMode->Width = This->ddraw_width;
4620 pMode->Height = This->ddraw_height;
4621 pMode->Format = This->ddraw_format;
4622 pMode->RefreshRate = 0;
4630 * Stateblock related functions
4633 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 IWineD3DStateBlock *stateblock;
4638 TRACE("(%p)\n", This);
4640 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4642 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4643 if (FAILED(hr)) return hr;
4645 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4646 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4647 This->isRecordingState = TRUE;
4649 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4654 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4658 if (!This->isRecordingState) {
4659 WARN("(%p) not recording! returning error\n", This);
4660 *ppStateBlock = NULL;
4661 return WINED3DERR_INVALIDCALL;
4664 stateblock_init_contained_states(object);
4666 *ppStateBlock = (IWineD3DStateBlock*) object;
4667 This->isRecordingState = FALSE;
4668 This->updateStateBlock = This->stateBlock;
4669 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4670 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4671 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4676 * Scene related functions
4678 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4679 /* At the moment we have no need for any functionality at the beginning
4681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4682 TRACE("(%p)\n", This);
4685 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4686 return WINED3DERR_INVALIDCALL;
4688 This->inScene = TRUE;
4692 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 struct wined3d_context *context;
4697 TRACE("(%p)\n", This);
4699 if(!This->inScene) {
4700 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4701 return WINED3DERR_INVALIDCALL;
4704 context = context_acquire(This, NULL);
4705 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4707 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4709 context_release(context);
4711 This->inScene = FALSE;
4715 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4716 const RECT *pSourceRect, const RECT *pDestRect,
4717 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4719 IWineD3DSwapChain *swapChain = NULL;
4721 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4723 TRACE("iface %p.\n", iface);
4725 for(i = 0 ; i < swapchains ; i ++) {
4727 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4728 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4729 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4730 IWineD3DSwapChain_Release(swapChain);
4736 /* Do not call while under the GL lock. */
4737 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4738 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4740 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4741 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4744 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4745 iface, rect_count, rects, flags, color, depth, stencil);
4747 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4749 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4750 /* TODO: What about depth stencil buffers without stencil bits? */
4751 return WINED3DERR_INVALIDCALL;
4754 device_get_draw_rect(device, &draw_rect);
4756 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4757 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4764 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4765 WINED3DPRIMITIVETYPE primitive_type)
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4769 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4771 This->updateStateBlock->changed.primitive_type = TRUE;
4772 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4775 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4776 WINED3DPRIMITIVETYPE *primitive_type)
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4782 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4784 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4787 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4791 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4793 if (!This->stateBlock->state.vertex_declaration)
4795 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4796 return WINED3DERR_INVALIDCALL;
4799 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4800 if (This->stateBlock->state.user_stream)
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4803 This->stateBlock->state.user_stream = FALSE;
4806 if (This->stateBlock->state.load_base_vertex_index)
4808 This->stateBlock->state.load_base_vertex_index = 0;
4809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4811 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4812 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4816 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4819 struct wined3d_buffer *index_buffer;
4823 index_buffer = This->stateBlock->state.index_buffer;
4826 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4827 * without an index buffer set. (The first time at least...)
4828 * D3D8 simply dies, but I doubt it can do much harm to return
4829 * D3DERR_INVALIDCALL there as well. */
4830 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4831 return WINED3DERR_INVALIDCALL;
4834 if (!This->stateBlock->state.vertex_declaration)
4836 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4837 return WINED3DERR_INVALIDCALL;
4840 if (This->stateBlock->state.user_stream)
4842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4843 This->stateBlock->state.user_stream = FALSE;
4845 vbo = index_buffer->buffer_object;
4847 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4849 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4854 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4856 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4860 drawPrimitive(This, index_count, startIndex, idxStride,
4861 vbo ? NULL : index_buffer->resource.allocatedMemory);
4866 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4867 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4870 struct wined3d_stream_state *stream;
4873 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4874 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4876 if (!This->stateBlock->state.vertex_declaration)
4878 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4879 return WINED3DERR_INVALIDCALL;
4882 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4883 stream = &This->stateBlock->state.streams[0];
4884 vb = (IWineD3DBuffer *)stream->buffer;
4885 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4886 if (vb) IWineD3DBuffer_Release(vb);
4888 stream->stride = VertexStreamZeroStride;
4889 This->stateBlock->state.user_stream = TRUE;
4890 This->stateBlock->state.load_base_vertex_index = 0;
4892 /* TODO: Only mark dirty if drawing from a different UP address */
4893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4895 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4897 /* MSDN specifies stream zero settings must be set to NULL */
4898 stream->buffer = NULL;
4901 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4902 * the new stream sources or use UP drawing again
4907 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4908 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4909 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 struct wined3d_stream_state *stream;
4917 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4918 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4920 if (!This->stateBlock->state.vertex_declaration)
4922 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4923 return WINED3DERR_INVALIDCALL;
4926 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4932 stream = &This->stateBlock->state.streams[0];
4933 vb = (IWineD3DBuffer *)stream->buffer;
4934 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4935 if (vb) IWineD3DBuffer_Release(vb);
4937 stream->stride = VertexStreamZeroStride;
4938 This->stateBlock->state.user_stream = TRUE;
4940 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4941 This->stateBlock->state.base_vertex_index = 0;
4942 This->stateBlock->state.load_base_vertex_index = 0;
4943 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4947 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4949 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4950 stream->buffer = NULL;
4952 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4955 IWineD3DBuffer_Release(ib);
4956 This->stateBlock->state.index_buffer = NULL;
4958 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4959 * SetStreamSource to specify a vertex buffer
4965 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4966 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4970 /* Mark the state dirty until we have nicer tracking
4971 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4976 This->stateBlock->state.base_vertex_index = 0;
4977 This->up_strided = DrawPrimStrideData;
4978 drawPrimitive(This, vertex_count, 0, 0, NULL);
4979 This->up_strided = NULL;
4983 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4984 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4985 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4988 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4990 /* Mark the state dirty until we have nicer tracking
4991 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4996 This->stateBlock->state.user_stream = TRUE;
4997 This->stateBlock->state.base_vertex_index = 0;
4998 This->up_strided = DrawPrimStrideData;
4999 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5000 This->up_strided = NULL;
5004 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5005 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5006 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5008 WINED3DLOCKED_BOX src;
5009 WINED3DLOCKED_BOX dst;
5012 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5013 iface, pSourceVolume, pDestinationVolume);
5015 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5016 * dirtification to improve loading performance.
5018 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5019 if (FAILED(hr)) return hr;
5020 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5023 IWineD3DVolume_Unmap(pSourceVolume);
5027 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5029 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5031 IWineD3DVolume_Unmap(pSourceVolume);
5033 hr = IWineD3DVolume_Unmap(pSourceVolume);
5038 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5039 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5041 unsigned int level_count, i;
5042 WINED3DRESOURCETYPE type;
5045 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5047 /* Verify that the source and destination textures are non-NULL. */
5048 if (!src_texture || !dst_texture)
5050 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5051 return WINED3DERR_INVALIDCALL;
5054 if (src_texture == dst_texture)
5056 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5057 return WINED3DERR_INVALIDCALL;
5060 /* Verify that the source and destination textures are the same type. */
5061 type = IWineD3DBaseTexture_GetType(src_texture);
5062 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5064 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5065 return WINED3DERR_INVALIDCALL;
5068 /* Check that both textures have the identical numbers of levels. */
5069 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5070 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5072 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5073 return WINED3DERR_INVALIDCALL;
5076 /* Make sure that the destination texture is loaded. */
5077 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5078 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5080 /* Update every surface level of the texture. */
5083 case WINED3DRTYPE_TEXTURE:
5085 IWineD3DSurface *src_surface;
5086 IWineD3DSurface *dst_surface;
5088 for (i = 0; i < level_count; ++i)
5090 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5091 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5092 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5093 IWineD3DSurface_Release(dst_surface);
5094 IWineD3DSurface_Release(src_surface);
5097 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5104 case WINED3DRTYPE_CUBETEXTURE:
5106 IWineD3DSurface *src_surface;
5107 IWineD3DSurface *dst_surface;
5109 for (i = 0; i < level_count * 6; ++i)
5111 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5112 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5113 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5114 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5115 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5116 IWineD3DSurface_Release(dst_surface);
5117 IWineD3DSurface_Release(src_surface);
5120 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5127 case WINED3DRTYPE_VOLUMETEXTURE:
5129 IWineD3DVolume *src_volume;
5130 IWineD3DVolume *dst_volume;
5132 for (i = 0; i < level_count; ++i)
5134 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5135 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5136 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5137 IWineD3DVolume_Release(dst_volume);
5138 IWineD3DVolume_Release(src_volume);
5141 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5149 FIXME("Unsupported texture type %#x.\n", type);
5150 return WINED3DERR_INVALIDCALL;
5156 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5157 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5159 IWineD3DSwapChain *swapchain;
5162 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5164 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5165 if (FAILED(hr)) return hr;
5167 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5168 IWineD3DSwapChain_Release(swapchain);
5173 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5175 IWineD3DBaseTextureImpl *texture;
5178 TRACE("(%p) : %p\n", This, pNumPasses);
5180 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5182 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5184 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5185 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5187 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5189 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5190 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5193 texture = This->stateBlock->state.textures[i];
5194 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5196 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5198 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5201 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5203 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5206 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5207 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5209 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5214 /* return a sensible default */
5217 TRACE("returning D3D_OK\n");
5221 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5225 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5227 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5228 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5229 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5231 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5236 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240 PALETTEENTRY **palettes;
5242 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5244 if (PaletteNumber >= MAX_PALETTES) {
5245 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5246 return WINED3DERR_INVALIDCALL;
5249 if (PaletteNumber >= This->NumberOfPalettes) {
5250 NewSize = This->NumberOfPalettes;
5253 } while(PaletteNumber >= NewSize);
5254 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5256 ERR("Out of memory!\n");
5257 return E_OUTOFMEMORY;
5259 This->palettes = palettes;
5260 This->NumberOfPalettes = NewSize;
5263 if (!This->palettes[PaletteNumber]) {
5264 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5265 if (!This->palettes[PaletteNumber]) {
5266 ERR("Out of memory!\n");
5267 return E_OUTOFMEMORY;
5271 for (j = 0; j < 256; ++j) {
5272 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5273 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5274 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5275 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5277 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5278 TRACE("(%p) : returning\n", This);
5282 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5285 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5286 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5287 /* What happens in such situation isn't documented; Native seems to silently abort
5288 on such conditions. Return Invalid Call. */
5289 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5290 return WINED3DERR_INVALIDCALL;
5292 for (j = 0; j < 256; ++j) {
5293 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5294 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5295 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5296 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5298 TRACE("(%p) : returning\n", This);
5302 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5304 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5305 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5306 (tested with reference rasterizer). Return Invalid Call. */
5307 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5308 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5309 return WINED3DERR_INVALIDCALL;
5311 /*TODO: stateblocks */
5312 if (This->currentPalette != PaletteNumber) {
5313 This->currentPalette = PaletteNumber;
5314 dirtify_p8_texture_samplers(This);
5316 TRACE("(%p) : returning\n", This);
5320 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5325 WARN("(%p) : returning Invalid Call\n", This);
5326 return WINED3DERR_INVALIDCALL;
5328 /*TODO: stateblocks */
5329 *PaletteNumber = This->currentPalette;
5330 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5334 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 FIXME("(%p) : stub\n", This);
5343 This->softwareVertexProcessing = bSoftware;
5348 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 FIXME("(%p) : stub\n", This);
5356 return This->softwareVertexProcessing;
5359 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5360 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5362 IWineD3DSwapChain *swapchain;
5365 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5366 iface, swapchain_idx, raster_status);
5368 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5371 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5375 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5376 IWineD3DSwapChain_Release(swapchain);
5379 WARN("Failed to get raster status, hr %#x.\n", hr);
5386 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5389 if(nSegments != 0.0f) {
5392 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5399 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5404 FIXME("iface %p stub!\n", iface);
5410 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5411 IWineD3DSurface *src_surface, const RECT *src_rect,
5412 IWineD3DSurface *dst_surface, const POINT *dst_point)
5414 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5415 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5417 const struct wined3d_format *src_format;
5418 const struct wined3d_format *dst_format;
5419 const struct wined3d_gl_info *gl_info;
5420 struct wined3d_context *context;
5421 const unsigned char *data;
5422 UINT update_w, update_h;
5423 CONVERT_TYPES convert;
5427 struct wined3d_format format;
5429 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5430 iface, src_surface, wine_dbgstr_rect(src_rect),
5431 dst_surface, wine_dbgstr_point(dst_point));
5433 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5435 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5436 src_surface, dst_surface);
5437 return WINED3DERR_INVALIDCALL;
5440 src_format = src_impl->resource.format;
5441 dst_format = dst_impl->resource.format;
5443 if (src_format->id != dst_format->id)
5445 WARN("Source and destination surfaces should have the same format.\n");
5446 return WINED3DERR_INVALIDCALL;
5449 dst_x = dst_point ? dst_point->x : 0;
5450 dst_y = dst_point ? dst_point->y : 0;
5452 /* This call loads the OpenGL surface directly, instead of copying the
5453 * surface to the destination's sysmem copy. If surface conversion is
5454 * needed, use BltFast instead to copy in sysmem and use regular surface
5456 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5457 if (convert != NO_CONVERSION || format.convert)
5458 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5460 context = context_acquire(This, NULL);
5461 gl_info = context->gl_info;
5464 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5465 checkGLcall("glActiveTextureARB");
5468 /* Make sure the surface is loaded and up to date */
5469 surface_internal_preload(dst_impl, SRGB_RGB);
5470 surface_bind(dst_impl, FALSE);
5472 src_w = src_impl->currentDesc.Width;
5473 src_h = src_impl->currentDesc.Height;
5474 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5475 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5477 data = src_impl->resource.allocatedMemory;
5478 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5482 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5484 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5485 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5486 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5490 data += (src_rect->top / src_format->block_height) * src_pitch;
5491 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5494 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5495 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5496 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5498 if (row_length == src_pitch)
5500 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5501 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5507 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5508 * can't use the unpack row length like below. */
5509 for (row = 0, y = dst_y; row < row_count; ++row)
5511 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5512 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5513 y += src_format->block_height;
5517 checkGLcall("glCompressedTexSubImage2DARB");
5523 data += src_rect->top * src_w * src_format->byte_count;
5524 data += src_rect->left * src_format->byte_count;
5527 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5528 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5529 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5531 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5532 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5533 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5534 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5535 checkGLcall("glTexSubImage2D");
5539 context_release(context);
5541 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5542 sampler = This->rev_tex_unit_map[0];
5543 if (sampler != WINED3D_UNMAPPED_STAGE)
5545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5551 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5553 struct WineD3DRectPatch *patch;
5554 GLenum old_primitive_type;
5558 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5560 if(!(Handle || pRectPatchInfo)) {
5561 /* TODO: Write a test for the return value, thus the FIXME */
5562 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5563 return WINED3DERR_INVALIDCALL;
5567 i = PATCHMAP_HASHFUNC(Handle);
5569 LIST_FOR_EACH(e, &This->patches[i]) {
5570 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5571 if(patch->Handle == Handle) {
5578 TRACE("Patch does not exist. Creating a new one\n");
5579 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5580 patch->Handle = Handle;
5581 list_add_head(&This->patches[i], &patch->entry);
5583 TRACE("Found existing patch %p\n", patch);
5586 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5587 * attributes we have to tesselate, read back, and draw. This needs a patch
5588 * management structure instance. Create one.
5590 * A possible improvement is to check if a vertex shader is used, and if not directly
5593 FIXME("Drawing an uncached patch. This is slow\n");
5594 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5597 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5598 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5599 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5602 TRACE("Tesselation density or patch info changed, retesselating\n");
5604 if(pRectPatchInfo) {
5605 patch->RectPatchInfo = *pRectPatchInfo;
5607 patch->numSegs[0] = pNumSegs[0];
5608 patch->numSegs[1] = pNumSegs[1];
5609 patch->numSegs[2] = pNumSegs[2];
5610 patch->numSegs[3] = pNumSegs[3];
5612 hr = tesselate_rectpatch(This, patch);
5614 WARN("Patch tesselation failed\n");
5616 /* Do not release the handle to store the params of the patch */
5618 HeapFree(GetProcessHeap(), 0, patch);
5624 This->currentPatch = patch;
5625 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5626 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5627 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5628 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5629 This->currentPatch = NULL;
5631 /* Destroy uncached patches */
5633 HeapFree(GetProcessHeap(), 0, patch->mem);
5634 HeapFree(GetProcessHeap(), 0, patch);
5639 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5640 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5642 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5643 iface, handle, segment_count, patch_info);
5648 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5651 struct WineD3DRectPatch *patch;
5653 TRACE("(%p) Handle(%d)\n", This, Handle);
5655 i = PATCHMAP_HASHFUNC(Handle);
5656 LIST_FOR_EACH(e, &This->patches[i]) {
5657 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5658 if(patch->Handle == Handle) {
5659 TRACE("Deleting patch %p\n", patch);
5660 list_remove(&patch->entry);
5661 HeapFree(GetProcessHeap(), 0, patch->mem);
5662 HeapFree(GetProcessHeap(), 0, patch);
5667 /* TODO: Write a test for the return value */
5668 FIXME("Attempt to destroy nonexistent patch\n");
5669 return WINED3DERR_INVALIDCALL;
5672 /* Do not call while under the GL lock. */
5673 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5674 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5676 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5678 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5679 iface, surface, wine_dbgstr_rect(rect),
5680 color->r, color->g, color->b, color->a);
5682 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5684 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5685 return WINED3DERR_INVALIDCALL;
5688 return surface_color_fill(s, rect, color);
5691 /* Do not call while under the GL lock. */
5692 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5693 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5695 IWineD3DResource *resource;
5698 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5701 ERR("Failed to get resource, hr %#x\n", hr);
5705 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5707 FIXME("Only supported on surface resources\n");
5708 IWineD3DResource_Release(resource);
5712 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5713 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5715 IWineD3DResource_Release(resource);
5718 /* rendertarget and depth stencil functions */
5719 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5720 DWORD render_target_idx, IWineD3DSurface **render_target)
5722 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5724 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5725 iface, render_target_idx, render_target);
5727 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5729 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5730 return WINED3DERR_INVALIDCALL;
5733 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5734 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5736 TRACE("Returning render target %p.\n", *render_target);
5741 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5743 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5745 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5747 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5748 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5749 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5750 IWineD3DSurface_AddRef(*depth_stencil);
5755 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5756 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5758 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5759 IWineD3DSurfaceImpl *prev;
5761 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5762 iface, render_target_idx, render_target, set_viewport);
5764 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5766 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5767 return WINED3DERR_INVALIDCALL;
5770 prev = device->render_targets[render_target_idx];
5771 if (render_target == (IWineD3DSurface *)prev)
5773 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5777 /* Render target 0 can't be set to NULL. */
5778 if (!render_target && !render_target_idx)
5780 WARN("Trying to set render target 0 to NULL.\n");
5781 return WINED3DERR_INVALIDCALL;
5784 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5786 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5787 return WINED3DERR_INVALIDCALL;
5790 if (render_target) IWineD3DSurface_AddRef(render_target);
5791 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5792 /* Release after the assignment, to prevent device_resource_released()
5793 * from seeing the surface as still in use. */
5794 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5796 /* Render target 0 is special. */
5797 if (!render_target_idx && set_viewport)
5799 /* Set the viewport and scissor rectangles, if requested. Tests show
5800 * that stateblock recording is ignored, the change goes directly
5801 * into the primary stateblock. */
5802 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5803 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5804 device->stateBlock->state.viewport.X = 0;
5805 device->stateBlock->state.viewport.Y = 0;
5806 device->stateBlock->state.viewport.MaxZ = 1.0f;
5807 device->stateBlock->state.viewport.MinZ = 0.0f;
5808 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5810 device->stateBlock->state.scissor_rect.top = 0;
5811 device->stateBlock->state.scissor_rect.left = 0;
5812 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5813 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5814 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5820 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5823 IWineD3DSurfaceImpl *tmp;
5825 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5827 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5829 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5833 if (This->depth_stencil)
5835 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5836 || This->depth_stencil->flags & SFLAG_DISCARD)
5838 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5839 This->depth_stencil->currentDesc.Width,
5840 This->depth_stencil->currentDesc.Height);
5841 if (This->depth_stencil == This->onscreen_depth_stencil)
5843 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5844 This->onscreen_depth_stencil = NULL;
5849 tmp = This->depth_stencil;
5850 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5851 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5852 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5854 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5856 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5865 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5866 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5869 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5870 WINED3DLOCKED_RECT lockedRect;
5872 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5873 iface, XHotSpot, YHotSpot, cursor_image);
5875 /* some basic validation checks */
5876 if (This->cursorTexture)
5878 struct wined3d_context *context = context_acquire(This, NULL);
5880 glDeleteTextures(1, &This->cursorTexture);
5882 context_release(context);
5883 This->cursorTexture = 0;
5886 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5887 This->haveHardwareCursor = TRUE;
5889 This->haveHardwareCursor = FALSE;
5893 WINED3DLOCKED_RECT rect;
5895 /* MSDN: Cursor must be A8R8G8B8 */
5896 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5898 WARN("surface %p has an invalid format.\n", cursor_image);
5899 return WINED3DERR_INVALIDCALL;
5902 /* MSDN: Cursor must be smaller than the display mode */
5903 if (s->currentDesc.Width > This->ddraw_width
5904 || s->currentDesc.Height > This->ddraw_height)
5906 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5907 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5908 return WINED3DERR_INVALIDCALL;
5911 if (!This->haveHardwareCursor) {
5912 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5914 /* Do not store the surface's pointer because the application may
5915 * release it after setting the cursor image. Windows doesn't
5916 * addref the set surface, so we can't do this either without
5917 * creating circular refcount dependencies. Copy out the gl texture
5920 This->cursorWidth = s->currentDesc.Width;
5921 This->cursorHeight = s->currentDesc.Height;
5922 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5924 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5925 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5926 struct wined3d_context *context;
5927 char *mem, *bits = rect.pBits;
5928 GLint intfmt = format->glInternal;
5929 GLint gl_format = format->glFormat;
5930 GLint type = format->glType;
5931 INT height = This->cursorHeight;
5932 INT width = This->cursorWidth;
5933 INT bpp = format->byte_count;
5937 /* Reformat the texture memory (pitch and width can be
5939 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5940 for(i = 0; i < height; i++)
5941 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5942 IWineD3DSurface_Unmap(cursor_image);
5944 context = context_acquire(This, NULL);
5948 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5950 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5951 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5954 /* Make sure that a proper texture unit is selected */
5955 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5956 checkGLcall("glActiveTextureARB");
5957 sampler = This->rev_tex_unit_map[0];
5958 if (sampler != WINED3D_UNMAPPED_STAGE)
5960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5962 /* Create a new cursor texture */
5963 glGenTextures(1, &This->cursorTexture);
5964 checkGLcall("glGenTextures");
5965 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5966 checkGLcall("glBindTexture");
5967 /* Copy the bitmap memory into the cursor texture */
5968 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5969 checkGLcall("glTexImage2D");
5970 HeapFree(GetProcessHeap(), 0, mem);
5972 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5974 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5975 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5980 context_release(context);
5984 FIXME("A cursor texture was not returned.\n");
5985 This->cursorTexture = 0;
5990 /* Draw a hardware cursor */
5991 ICONINFO cursorInfo;
5993 /* Create and clear maskBits because it is not needed for
5994 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5996 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5997 (s->currentDesc.Width * s->currentDesc.Height / 8));
5998 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5999 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6000 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
6002 cursorInfo.fIcon = FALSE;
6003 cursorInfo.xHotspot = XHotSpot;
6004 cursorInfo.yHotspot = YHotSpot;
6005 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
6006 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
6007 IWineD3DSurface_Unmap(cursor_image);
6008 /* Create our cursor and clean up. */
6009 cursor = CreateIconIndirect(&cursorInfo);
6011 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6012 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6013 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6014 This->hardwareCursor = cursor;
6015 HeapFree(GetProcessHeap(), 0, maskBits);
6019 This->xHotSpot = XHotSpot;
6020 This->yHotSpot = YHotSpot;
6024 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6025 int XScreenSpace, int YScreenSpace, DWORD flags)
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6029 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6030 iface, XScreenSpace, YScreenSpace, flags);
6032 This->xScreenSpace = XScreenSpace;
6033 This->yScreenSpace = YScreenSpace;
6036 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6038 BOOL oldVisible = This->bCursorVisible;
6041 TRACE("(%p) : visible(%d)\n", This, bShow);
6044 * When ShowCursor is first called it should make the cursor appear at the OS's last
6045 * known cursor position. Because of this, some applications just repetitively call
6046 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6049 This->xScreenSpace = pt.x;
6050 This->yScreenSpace = pt.y;
6052 if (This->haveHardwareCursor) {
6053 This->bCursorVisible = bShow;
6055 SetCursor(This->hardwareCursor);
6061 if (This->cursorTexture)
6062 This->bCursorVisible = bShow;
6068 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6069 TRACE("checking resource %p for eviction\n", resource);
6070 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6071 TRACE("Evicting %p\n", resource);
6072 IWineD3DResource_UnLoad(resource);
6074 IWineD3DResource_Release(resource);
6078 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6080 TRACE("iface %p.\n", iface);
6082 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6083 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6084 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6089 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6091 IWineD3DDeviceImpl *device = surface->resource.device;
6092 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6094 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6095 if (surface->flags & SFLAG_DIBSECTION)
6097 /* Release the DC */
6098 SelectObject(surface->hDC, surface->dib.holdbitmap);
6099 DeleteDC(surface->hDC);
6100 /* Release the DIB section */
6101 DeleteObject(surface->dib.DIBsection);
6102 surface->dib.bitmap_data = NULL;
6103 surface->resource.allocatedMemory = NULL;
6104 surface->flags &= ~SFLAG_DIBSECTION;
6106 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6107 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6108 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6109 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6111 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6112 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6114 surface->pow2Width = surface->pow2Height = 1;
6115 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6116 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6119 if (surface->texture_name)
6121 struct wined3d_context *context = context_acquire(device, NULL);
6123 glDeleteTextures(1, &surface->texture_name);
6125 context_release(context);
6126 surface->texture_name = 0;
6127 surface->flags &= ~SFLAG_CLIENT;
6129 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6130 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6132 surface->flags |= SFLAG_NONPOW2;
6136 surface->flags &= ~SFLAG_NONPOW2;
6138 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6139 surface->resource.allocatedMemory = NULL;
6140 surface->resource.heapMemory = NULL;
6141 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6143 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6145 if (!surface_init_sysmem(surface))
6147 return E_OUTOFMEMORY;
6152 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6153 TRACE("Unloading resource %p\n", resource);
6154 IWineD3DResource_UnLoad(resource);
6155 IWineD3DResource_Release(resource);
6159 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6162 WINED3DDISPLAYMODE m;
6165 /* All Windowed modes are supported, as is leaving the current mode */
6166 if(pp->Windowed) return TRUE;
6167 if(!pp->BackBufferWidth) return TRUE;
6168 if(!pp->BackBufferHeight) return TRUE;
6170 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6171 for(i = 0; i < count; i++) {
6172 memset(&m, 0, sizeof(m));
6173 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6175 ERR("EnumAdapterModes failed\n");
6177 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6178 /* Mode found, it is supported */
6182 /* Mode not found -> not supported */
6186 /* Do not call while under the GL lock. */
6187 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6189 const struct wined3d_gl_info *gl_info;
6190 struct wined3d_context *context;
6191 IWineD3DBaseShaderImpl *shader;
6193 context = context_acquire(device, NULL);
6194 gl_info = context->gl_info;
6196 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, reset_unload_resources, NULL);
6197 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6199 device->shader_backend->shader_destroy(shader);
6203 if (device->depth_blt_texture)
6205 glDeleteTextures(1, &device->depth_blt_texture);
6206 device->depth_blt_texture = 0;
6208 if (device->depth_blt_rb)
6210 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6211 device->depth_blt_rb = 0;
6212 device->depth_blt_rb_w = 0;
6213 device->depth_blt_rb_h = 0;
6217 device->blitter->free_private(device);
6218 device->frag_pipe->free_private(device);
6219 device->shader_backend->shader_free_private(device);
6220 destroy_dummy_textures(device, gl_info);
6222 context_release(context);
6224 while (device->numContexts)
6226 context_destroy(device, device->contexts[0]);
6228 HeapFree(GetProcessHeap(), 0, swapchain->context);
6229 swapchain->context = NULL;
6230 swapchain->num_contexts = 0;
6233 /* Do not call while under the GL lock. */
6234 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6236 struct wined3d_context *context;
6238 IWineD3DSurfaceImpl *target;
6240 /* Recreate the primary swapchain's context */
6241 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6242 if (!swapchain->context)
6244 ERR("Failed to allocate memory for swapchain context array.\n");
6245 return E_OUTOFMEMORY;
6248 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6249 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6251 WARN("Failed to create context.\n");
6252 HeapFree(GetProcessHeap(), 0, swapchain->context);
6256 swapchain->context[0] = context;
6257 swapchain->num_contexts = 1;
6258 create_dummy_textures(device);
6259 context_release(context);
6261 hr = device->shader_backend->shader_alloc_private(device);
6264 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6268 hr = device->frag_pipe->alloc_private(device);
6271 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6272 device->shader_backend->shader_free_private(device);
6276 hr = device->blitter->alloc_private(device);
6279 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6280 device->frag_pipe->free_private(device);
6281 device->shader_backend->shader_free_private(device);
6288 context_acquire(device, NULL);
6289 destroy_dummy_textures(device, context->gl_info);
6290 context_release(context);
6291 context_destroy(device, context);
6292 HeapFree(GetProcessHeap(), 0, swapchain->context);
6293 swapchain->num_contexts = 0;
6297 /* Do not call while under the GL lock. */
6298 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6299 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6302 IWineD3DSwapChainImpl *swapchain;
6304 BOOL DisplayModeChanged = FALSE;
6305 WINED3DDISPLAYMODE mode;
6306 TRACE("(%p)\n", This);
6308 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6310 ERR("Failed to get the first implicit swapchain\n");
6314 if(!is_display_mode_supported(This, pPresentationParameters)) {
6315 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6316 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6317 pPresentationParameters->BackBufferHeight);
6318 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6319 return WINED3DERR_INVALIDCALL;
6322 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6323 * on an existing gl context, so there's no real need for recreation.
6325 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6327 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6329 TRACE("New params:\n");
6330 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6331 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6332 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6333 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6334 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6335 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6336 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6337 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6338 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6339 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6340 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6341 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6342 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6344 /* No special treatment of these parameters. Just store them */
6345 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6346 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6347 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6348 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6350 /* What to do about these? */
6351 if (pPresentationParameters->BackBufferCount
6352 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6353 ERR("Cannot change the back buffer count yet\n");
6355 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6356 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6357 ERR("Cannot change the back buffer format yet\n");
6360 if (pPresentationParameters->hDeviceWindow
6361 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6362 ERR("Cannot change the device window yet\n");
6364 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6368 TRACE("Creating the depth stencil buffer\n");
6370 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6371 pPresentationParameters->BackBufferWidth,
6372 pPresentationParameters->BackBufferHeight,
6373 pPresentationParameters->AutoDepthStencilFormat,
6374 pPresentationParameters->MultiSampleType,
6375 pPresentationParameters->MultiSampleQuality,
6377 (IWineD3DSurface **)&This->auto_depth_stencil);
6380 ERR("Failed to create the depth stencil buffer\n");
6381 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6382 return WINED3DERR_INVALIDCALL;
6386 if (This->onscreen_depth_stencil)
6388 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6389 This->onscreen_depth_stencil = NULL;
6392 /* Reset the depth stencil */
6393 if (pPresentationParameters->EnableAutoDepthStencil)
6394 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6396 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6398 TRACE("Resetting stateblock\n");
6399 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6400 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6402 delete_opengl_contexts(This, swapchain);
6404 if(pPresentationParameters->Windowed) {
6405 mode.Width = swapchain->orig_width;
6406 mode.Height = swapchain->orig_height;
6407 mode.RefreshRate = 0;
6408 mode.Format = swapchain->presentParms.BackBufferFormat;
6410 mode.Width = pPresentationParameters->BackBufferWidth;
6411 mode.Height = pPresentationParameters->BackBufferHeight;
6412 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6413 mode.Format = swapchain->presentParms.BackBufferFormat;
6416 /* Should Width == 800 && Height == 0 set 800x600? */
6417 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6418 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6419 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6423 if(!pPresentationParameters->Windowed) {
6424 DisplayModeChanged = TRUE;
6426 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6427 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6429 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6432 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6436 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6438 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6441 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6445 if (This->auto_depth_stencil)
6447 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6450 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6456 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6457 || DisplayModeChanged)
6459 BOOL filter = This->filter_messages;
6460 This->filter_messages = TRUE;
6462 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6464 if (!pPresentationParameters->Windowed)
6466 if (swapchain->presentParms.Windowed)
6468 HWND focus_window = This->createParms.hFocusWindow;
6469 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6470 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6472 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6473 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6477 /* switch from windowed to fs */
6478 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6479 pPresentationParameters->BackBufferWidth,
6480 pPresentationParameters->BackBufferHeight);
6484 /* Fullscreen -> fullscreen mode change */
6485 MoveWindow(swapchain->device_window, 0, 0,
6486 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6490 else if (!swapchain->presentParms.Windowed)
6492 /* Fullscreen -> windowed switch */
6493 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6494 IWineD3DDevice_ReleaseFocusWindow(iface);
6496 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6498 This->filter_messages = filter;
6500 else if (!pPresentationParameters->Windowed)
6502 DWORD style = This->style, exStyle = This->exStyle;
6503 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6504 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6505 * Reset to clear up their mess. Guild Wars also loses the device during that.
6509 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6510 pPresentationParameters->BackBufferWidth,
6511 pPresentationParameters->BackBufferHeight);
6512 This->style = style;
6513 This->exStyle = exStyle;
6516 /* Note: No parent needed for initial internal stateblock */
6517 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6518 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6519 else TRACE("Created stateblock %p\n", This->stateBlock);
6520 This->updateStateBlock = This->stateBlock;
6521 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6523 stateblock_init_default_state(This->stateBlock);
6525 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6528 GetClientRect(swapchain->win_handle, &client_rect);
6530 if(!swapchain->presentParms.BackBufferCount)
6532 TRACE("Single buffered rendering\n");
6533 swapchain->render_to_fbo = FALSE;
6535 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6536 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6538 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6539 swapchain->presentParms.BackBufferWidth,
6540 swapchain->presentParms.BackBufferHeight,
6541 client_rect.right, client_rect.bottom);
6542 swapchain->render_to_fbo = TRUE;
6546 TRACE("Rendering directly to GL_BACK\n");
6547 swapchain->render_to_fbo = FALSE;
6551 hr = create_primary_opengl_context(This, swapchain);
6552 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6554 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6560 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6562 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6564 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6570 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6572 TRACE("(%p) : pParameters %p\n", This, pParameters);
6574 *pParameters = This->createParms;
6578 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6579 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6581 IWineD3DSwapChain *swapchain;
6583 TRACE("Relaying to swapchain\n");
6585 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6587 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6588 IWineD3DSwapChain_Release(swapchain);
6592 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6593 IWineD3DSwapChain *swapchain;
6595 TRACE("Relaying to swapchain\n");
6597 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6598 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6599 IWineD3DSwapChain_Release(swapchain);
6603 void device_resource_add(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6605 TRACE("device %p, resource %p.\n", device, resource);
6607 list_add_head(&device->resources, &resource->resource.resource_list_entry);
6610 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6612 TRACE("device %p, resource %p.\n", device, resource);
6614 list_remove(&resource->resource.resource_list_entry);
6617 void device_resource_released(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6619 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6622 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6624 context_resource_released(device, resource, type);
6628 case WINED3DRTYPE_SURFACE:
6629 if (!device->d3d_initialized) break;
6631 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6633 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6635 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6636 device->render_targets[i] = NULL;
6640 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6642 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6643 device->depth_stencil = NULL;
6647 case WINED3DRTYPE_TEXTURE:
6648 case WINED3DRTYPE_CUBETEXTURE:
6649 case WINED3DRTYPE_VOLUMETEXTURE:
6650 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6652 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6654 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6655 resource, device->stateBlock, i);
6656 device->stateBlock->state.textures[i] = NULL;
6659 if (device->updateStateBlock != device->stateBlock
6660 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6662 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6663 resource, device->updateStateBlock, i);
6664 device->updateStateBlock->state.textures[i] = NULL;
6669 case WINED3DRTYPE_BUFFER:
6670 for (i = 0; i < MAX_STREAMS; ++i)
6672 if (device->stateBlock
6673 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6675 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6676 resource, device->stateBlock, i);
6677 device->stateBlock->state.streams[i].buffer = NULL;
6680 if (device->updateStateBlock != device->stateBlock
6681 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6683 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6684 resource, device->updateStateBlock, i);
6685 device->updateStateBlock->state.streams[i].buffer = NULL;
6690 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6692 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6693 resource, device->stateBlock);
6694 device->stateBlock->state.index_buffer = NULL;
6697 if (device->updateStateBlock != device->stateBlock
6698 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6700 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6701 resource, device->updateStateBlock);
6702 device->updateStateBlock->state.index_buffer = NULL;
6710 /* Remove the resource from the resourceStore */
6711 device_resource_remove(device, resource);
6713 TRACE("Resource released.\n");
6716 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6718 IWineD3DResourceImpl *resource, *cursor;
6720 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6722 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6723 TRACE("enumerating resource %p\n", resource);
6724 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6725 ret = pCallback((IWineD3DResource *) resource, pData);
6726 if(ret == S_FALSE) {
6727 TRACE("Canceling enumeration\n");
6734 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6737 IWineD3DResourceImpl *resource;
6739 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6741 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6742 if (type == WINED3DRTYPE_SURFACE)
6744 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6746 TRACE("Found surface %p for dc %p.\n", resource, dc);
6747 *surface = (IWineD3DSurface *)resource;
6753 return WINED3DERR_INVALIDCALL;
6756 /**********************************************************
6757 * IWineD3DDevice VTbl follows
6758 **********************************************************/
6760 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6762 /*** IUnknown methods ***/
6763 IWineD3DDeviceImpl_QueryInterface,
6764 IWineD3DDeviceImpl_AddRef,
6765 IWineD3DDeviceImpl_Release,
6766 /*** IWineD3DDevice methods ***/
6767 /*** Creation methods**/
6768 IWineD3DDeviceImpl_CreateBuffer,
6769 IWineD3DDeviceImpl_CreateVertexBuffer,
6770 IWineD3DDeviceImpl_CreateIndexBuffer,
6771 IWineD3DDeviceImpl_CreateStateBlock,
6772 IWineD3DDeviceImpl_CreateSurface,
6773 IWineD3DDeviceImpl_CreateRendertargetView,
6774 IWineD3DDeviceImpl_CreateTexture,
6775 IWineD3DDeviceImpl_CreateVolumeTexture,
6776 IWineD3DDeviceImpl_CreateVolume,
6777 IWineD3DDeviceImpl_CreateCubeTexture,
6778 IWineD3DDeviceImpl_CreateQuery,
6779 IWineD3DDeviceImpl_CreateSwapChain,
6780 IWineD3DDeviceImpl_CreateVertexDeclaration,
6781 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6782 IWineD3DDeviceImpl_CreateVertexShader,
6783 IWineD3DDeviceImpl_CreateGeometryShader,
6784 IWineD3DDeviceImpl_CreatePixelShader,
6785 IWineD3DDeviceImpl_CreatePalette,
6786 /*** Odd functions **/
6787 IWineD3DDeviceImpl_Init3D,
6788 IWineD3DDeviceImpl_InitGDI,
6789 IWineD3DDeviceImpl_Uninit3D,
6790 IWineD3DDeviceImpl_UninitGDI,
6791 IWineD3DDeviceImpl_SetMultithreaded,
6792 IWineD3DDeviceImpl_EvictManagedResources,
6793 IWineD3DDeviceImpl_GetAvailableTextureMem,
6794 IWineD3DDeviceImpl_GetBackBuffer,
6795 IWineD3DDeviceImpl_GetCreationParameters,
6796 IWineD3DDeviceImpl_GetDeviceCaps,
6797 IWineD3DDeviceImpl_GetDirect3D,
6798 IWineD3DDeviceImpl_GetDisplayMode,
6799 IWineD3DDeviceImpl_SetDisplayMode,
6800 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6801 IWineD3DDeviceImpl_GetRasterStatus,
6802 IWineD3DDeviceImpl_GetSwapChain,
6803 IWineD3DDeviceImpl_Reset,
6804 IWineD3DDeviceImpl_SetDialogBoxMode,
6805 IWineD3DDeviceImpl_SetCursorProperties,
6806 IWineD3DDeviceImpl_SetCursorPosition,
6807 IWineD3DDeviceImpl_ShowCursor,
6808 /*** Getters and setters **/
6809 IWineD3DDeviceImpl_SetClipPlane,
6810 IWineD3DDeviceImpl_GetClipPlane,
6811 IWineD3DDeviceImpl_SetClipStatus,
6812 IWineD3DDeviceImpl_GetClipStatus,
6813 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6814 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6815 IWineD3DDeviceImpl_SetDepthStencilSurface,
6816 IWineD3DDeviceImpl_GetDepthStencilSurface,
6817 IWineD3DDeviceImpl_SetGammaRamp,
6818 IWineD3DDeviceImpl_GetGammaRamp,
6819 IWineD3DDeviceImpl_SetIndexBuffer,
6820 IWineD3DDeviceImpl_GetIndexBuffer,
6821 IWineD3DDeviceImpl_SetBaseVertexIndex,
6822 IWineD3DDeviceImpl_GetBaseVertexIndex,
6823 IWineD3DDeviceImpl_SetLight,
6824 IWineD3DDeviceImpl_GetLight,
6825 IWineD3DDeviceImpl_SetLightEnable,
6826 IWineD3DDeviceImpl_GetLightEnable,
6827 IWineD3DDeviceImpl_SetMaterial,
6828 IWineD3DDeviceImpl_GetMaterial,
6829 IWineD3DDeviceImpl_SetNPatchMode,
6830 IWineD3DDeviceImpl_GetNPatchMode,
6831 IWineD3DDeviceImpl_SetPaletteEntries,
6832 IWineD3DDeviceImpl_GetPaletteEntries,
6833 IWineD3DDeviceImpl_SetPixelShader,
6834 IWineD3DDeviceImpl_GetPixelShader,
6835 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6836 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6837 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6838 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6839 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6840 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6841 IWineD3DDeviceImpl_SetRenderState,
6842 IWineD3DDeviceImpl_GetRenderState,
6843 IWineD3DDeviceImpl_SetRenderTarget,
6844 IWineD3DDeviceImpl_GetRenderTarget,
6845 IWineD3DDeviceImpl_SetSamplerState,
6846 IWineD3DDeviceImpl_GetSamplerState,
6847 IWineD3DDeviceImpl_SetScissorRect,
6848 IWineD3DDeviceImpl_GetScissorRect,
6849 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6850 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6851 IWineD3DDeviceImpl_SetStreamSource,
6852 IWineD3DDeviceImpl_GetStreamSource,
6853 IWineD3DDeviceImpl_SetStreamSourceFreq,
6854 IWineD3DDeviceImpl_GetStreamSourceFreq,
6855 IWineD3DDeviceImpl_SetTexture,
6856 IWineD3DDeviceImpl_GetTexture,
6857 IWineD3DDeviceImpl_SetTextureStageState,
6858 IWineD3DDeviceImpl_GetTextureStageState,
6859 IWineD3DDeviceImpl_SetTransform,
6860 IWineD3DDeviceImpl_GetTransform,
6861 IWineD3DDeviceImpl_SetVertexDeclaration,
6862 IWineD3DDeviceImpl_GetVertexDeclaration,
6863 IWineD3DDeviceImpl_SetVertexShader,
6864 IWineD3DDeviceImpl_GetVertexShader,
6865 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6866 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6867 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6868 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6869 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6870 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6871 IWineD3DDeviceImpl_SetViewport,
6872 IWineD3DDeviceImpl_GetViewport,
6873 IWineD3DDeviceImpl_MultiplyTransform,
6874 IWineD3DDeviceImpl_ValidateDevice,
6875 IWineD3DDeviceImpl_ProcessVertices,
6876 /*** State block ***/
6877 IWineD3DDeviceImpl_BeginStateBlock,
6878 IWineD3DDeviceImpl_EndStateBlock,
6879 /*** Scene management ***/
6880 IWineD3DDeviceImpl_BeginScene,
6881 IWineD3DDeviceImpl_EndScene,
6882 IWineD3DDeviceImpl_Present,
6883 IWineD3DDeviceImpl_Clear,
6884 IWineD3DDeviceImpl_ClearRendertargetView,
6886 IWineD3DDeviceImpl_SetPrimitiveType,
6887 IWineD3DDeviceImpl_GetPrimitiveType,
6888 IWineD3DDeviceImpl_DrawPrimitive,
6889 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6890 IWineD3DDeviceImpl_DrawPrimitiveUP,
6891 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6892 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6893 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6894 IWineD3DDeviceImpl_DrawRectPatch,
6895 IWineD3DDeviceImpl_DrawTriPatch,
6896 IWineD3DDeviceImpl_DeletePatch,
6897 IWineD3DDeviceImpl_ColorFill,
6898 IWineD3DDeviceImpl_UpdateTexture,
6899 IWineD3DDeviceImpl_UpdateSurface,
6900 IWineD3DDeviceImpl_GetFrontBufferData,
6901 /*** object tracking ***/
6902 IWineD3DDeviceImpl_EnumResources,
6903 IWineD3DDeviceImpl_GetSurfaceFromDC,
6904 IWineD3DDeviceImpl_AcquireFocusWindow,
6905 IWineD3DDeviceImpl_ReleaseFocusWindow,
6906 IWineD3DDeviceImpl_SetupFullscreenWindow,
6907 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6910 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6911 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6912 IWineD3DDeviceParent *device_parent)
6914 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6915 const struct fragment_pipeline *fragment_pipeline;
6916 struct shader_caps shader_caps;
6917 struct fragment_caps ffp_caps;
6918 WINED3DDISPLAYMODE mode;
6922 device->lpVtbl = &IWineD3DDevice_Vtbl;
6924 device->wined3d = (IWineD3D *)wined3d;
6925 IWineD3D_AddRef(device->wined3d);
6926 device->adapter = wined3d->adapter_count ? adapter : NULL;
6927 device->device_parent = device_parent;
6928 list_init(&device->resources);
6929 list_init(&device->shaders);
6931 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6933 /* Get the initial screen setup for ddraw. */
6934 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6937 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6938 IWineD3D_Release(device->wined3d);
6941 device->ddraw_width = mode.Width;
6942 device->ddraw_height = mode.Height;
6943 device->ddraw_format = mode.Format;
6945 /* Save the creation parameters. */
6946 device->createParms.AdapterOrdinal = adapter_idx;
6947 device->createParms.DeviceType = device_type;
6948 device->createParms.hFocusWindow = focus_window;
6949 device->createParms.BehaviorFlags = flags;
6951 device->devType = device_type;
6952 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6954 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6955 device->shader_backend = adapter->shader_backend;
6957 if (device->shader_backend)
6959 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6960 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6961 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6962 device->vs_clipping = shader_caps.VSClipping;
6964 fragment_pipeline = adapter->fragment_pipe;
6965 device->frag_pipe = fragment_pipeline;
6966 if (fragment_pipeline)
6968 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6969 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6971 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6972 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6975 ERR("Failed to compile state table, hr %#x.\n", hr);
6976 IWineD3D_Release(device->wined3d);
6980 device->blitter = adapter->blitter;
6986 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6987 DWORD rep = This->StateTable[state].representative;
6988 struct wined3d_context *context;
6993 for(i = 0; i < This->numContexts; i++) {
6994 context = This->contexts[i];
6995 if(isStateDirty(context, rep)) continue;
6997 context->dirtyArray[context->numDirtyEntries++] = rep;
6998 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6999 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7000 context->isStateDirty[idx] |= (1 << shift);
7004 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7006 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7007 *width = context->current_rt->pow2Width;
7008 *height = context->current_rt->pow2Height;
7011 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7013 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7014 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7015 * current context's drawable, which is the size of the back buffer of the swapchain
7016 * the active context belongs to. */
7017 *width = swapchain->presentParms.BackBufferWidth;
7018 *height = swapchain->presentParms.BackBufferHeight;
7021 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7022 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7024 if (device->filter_messages)
7026 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7027 window, message, wparam, lparam);
7029 return DefWindowProcW(window, message, wparam, lparam);
7031 return DefWindowProcA(window, message, wparam, lparam);
7034 if (message == WM_DESTROY)
7036 TRACE("unregister window %p.\n", window);
7037 wined3d_unregister_window(window);
7039 if (device->focus_window == window) device->focus_window = NULL;
7040 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7044 return CallWindowProcW(proc, window, message, wparam, lparam);
7046 return CallWindowProcA(proc, window, message, wparam, lparam);