2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
211 data = (BYTE *)buffer;
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((IWineD3DBuffer *)buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
436 device->useDrawStridedSlow = FALSE;
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1114 ERR("Out of memory\n");
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1183 ERR("Out of memory\n");
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1314 TRACE("Swapchain out of range\n");
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 *ppVertexElements = state.elements;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1517 if (This->vs_selected_mode == SHADER_NONE)
1518 return WINED3DERR_INVALIDCALL;
1520 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1523 ERR("Failed to allocate shader memory.\n");
1524 return E_OUTOFMEMORY;
1527 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1530 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1531 HeapFree(GetProcessHeap(), 0, object);
1535 TRACE("Created vertex shader %p.\n", object);
1536 *ppVertexShader = (IWineD3DVertexShader *)object;
1541 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1542 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1543 void *parent, const struct wined3d_parent_ops *parent_ops,
1544 IWineD3DGeometryShader **shader)
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 struct wined3d_geometryshader *object;
1550 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1553 ERR("Failed to allocate shader memory.\n");
1554 return E_OUTOFMEMORY;
1557 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1560 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1561 HeapFree(GetProcessHeap(), 0, object);
1565 TRACE("Created geometry shader %p.\n", object);
1566 *shader = (IWineD3DGeometryShader *)object;
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1572 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1573 void *parent, const struct wined3d_parent_ops *parent_ops,
1574 IWineD3DPixelShader **ppPixelShader)
1576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1577 IWineD3DPixelShaderImpl *object;
1580 if (This->ps_selected_mode == SHADER_NONE)
1581 return WINED3DERR_INVALIDCALL;
1583 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1586 ERR("Failed to allocate shader memory.\n");
1587 return E_OUTOFMEMORY;
1590 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1593 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1594 HeapFree(GetProcessHeap(), 0, object);
1598 TRACE("Created pixel shader %p.\n", object);
1599 *ppPixelShader = (IWineD3DPixelShader *)object;
1604 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1605 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1608 IWineD3DPaletteImpl *object;
1611 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1612 iface, Flags, PalEnt, Palette, parent);
1614 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1617 ERR("Failed to allocate palette memory.\n");
1618 return E_OUTOFMEMORY;
1621 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1624 WARN("Failed to initialize palette, hr %#x.\n", hr);
1625 HeapFree(GetProcessHeap(), 0, object);
1629 TRACE("Created palette %p.\n", object);
1630 *Palette = (IWineD3DPalette *)object;
1635 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1639 HDC dcb = NULL, dcs = NULL;
1640 WINEDDCOLORKEY colorkey;
1642 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1645 GetObjectA(hbm, sizeof(BITMAP), &bm);
1646 dcb = CreateCompatibleDC(NULL);
1648 SelectObject(dcb, hbm);
1652 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1653 * couldn't be loaded
1655 memset(&bm, 0, sizeof(bm));
1660 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1661 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1662 &wined3d_null_parent_ops, &This->logo_surface);
1665 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1681 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static LONG fullscreen_style(LONG style)
1755 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1756 style |= WS_POPUP | WS_SYSMENU;
1757 style &= ~(WS_CAPTION | WS_THICKFRAME);
1762 static LONG fullscreen_exstyle(LONG exstyle)
1764 /* Filter out window decorations. */
1765 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1770 void device_setup_fullscreen_window(IWineD3DDeviceImpl *device, HWND window, UINT w, UINT h)
1772 BOOL filter_messages;
1773 LONG style, exstyle;
1775 TRACE("Setting up window %p for fullscreen mode.\n", window);
1777 if (device->style || device->exStyle)
1779 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1780 window, device->style, device->exStyle);
1783 device->style = GetWindowLongW(window, GWL_STYLE);
1784 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1786 style = fullscreen_style(device->style);
1787 exstyle = fullscreen_exstyle(device->exStyle);
1789 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1790 device->style, device->exStyle, style, exstyle);
1792 filter_messages = device->filter_messages;
1793 device->filter_messages = TRUE;
1795 SetWindowLongW(window, GWL_STYLE, style);
1796 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1797 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1799 device->filter_messages = filter_messages;
1802 void device_restore_fullscreen_window(IWineD3DDeviceImpl *device, HWND window)
1804 BOOL filter_messages;
1805 LONG style, exstyle;
1807 if (!device->style && !device->exStyle) return;
1809 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1810 window, device->style, device->exStyle);
1812 style = GetWindowLongW(window, GWL_STYLE);
1813 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1815 filter_messages = device->filter_messages;
1816 device->filter_messages = TRUE;
1818 /* Only restore the style if the application didn't modify it during the
1819 * fullscreen phase. Some applications change it before calling Reset()
1820 * when switching between windowed and fullscreen modes (HL2), some
1821 * depend on the original style (Eve Online). */
1822 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1824 SetWindowLongW(window, GWL_STYLE, device->style);
1825 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1827 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1829 device->filter_messages = filter_messages;
1831 /* Delete the old values. */
1833 device->exStyle = 0;
1836 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1838 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1840 TRACE("iface %p, window %p.\n", iface, window);
1842 if (!wined3d_register_window(window, device))
1844 ERR("Failed to register window %p.\n", window);
1848 device->focus_window = window;
1849 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1854 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1856 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1858 TRACE("iface %p.\n", iface);
1860 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1861 device->focus_window = NULL;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1865 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1868 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1869 IWineD3DSwapChainImpl *swapchain = NULL;
1870 struct wined3d_context *context;
1875 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1877 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1878 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1880 TRACE("(%p) : Creating stateblock\n", This);
1881 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1884 WARN("Failed to create stateblock\n");
1887 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1888 This->updateStateBlock = This->stateBlock;
1889 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1891 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1892 sizeof(*This->render_targets) * gl_info->limits.buffers);
1894 This->NumberOfPalettes = 1;
1895 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1896 if (!This->palettes || !This->render_targets)
1898 ERR("Out of memory!\n");
1902 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1903 if(!This->palettes[0]) {
1904 ERR("Out of memory!\n");
1908 for (i = 0; i < 256; ++i) {
1909 This->palettes[0][i].peRed = 0xFF;
1910 This->palettes[0][i].peGreen = 0xFF;
1911 This->palettes[0][i].peBlue = 0xFF;
1912 This->palettes[0][i].peFlags = 0xFF;
1914 This->currentPalette = 0;
1916 /* Initialize the texture unit mapping to a 1:1 mapping */
1917 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1919 if (state < gl_info->limits.fragment_samplers)
1921 This->texUnitMap[state] = state;
1922 This->rev_tex_unit_map[state] = state;
1924 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1925 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1929 /* Setup the implicit swapchain. This also initializes a context. */
1930 TRACE("Creating implicit swapchain\n");
1931 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1932 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1935 WARN("Failed to create implicit swapchain\n");
1939 This->NumberOfSwapChains = 1;
1940 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1941 if(!This->swapchains) {
1942 ERR("Out of memory!\n");
1945 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1947 if (swapchain->back_buffers && swapchain->back_buffers[0])
1949 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1950 This->render_targets[0] = swapchain->back_buffers[0];
1954 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1955 This->render_targets[0] = swapchain->front_buffer;
1957 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1959 /* Depth Stencil support */
1960 This->depth_stencil = This->auto_depth_stencil;
1961 if (This->depth_stencil)
1962 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1964 hr = This->shader_backend->shader_alloc_private(iface);
1966 TRACE("Shader private data couldn't be allocated\n");
1969 hr = This->frag_pipe->alloc_private(iface);
1971 TRACE("Fragment pipeline private data couldn't be allocated\n");
1974 hr = This->blitter->alloc_private(iface);
1976 TRACE("Blitter private data couldn't be allocated\n");
1980 /* Set up some starting GL setup */
1982 /* Setup all the devices defaults */
1983 stateblock_init_default_state(This->stateBlock);
1985 context = context_acquire(This, swapchain->front_buffer);
1987 create_dummy_textures(This);
1991 /* Initialize the current view state */
1992 This->view_ident = 1;
1993 This->contexts[0]->last_was_rhw = 0;
1994 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1995 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1997 switch(wined3d_settings.offscreen_rendering_mode) {
1999 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2002 case ORM_BACKBUFFER:
2004 if (context_get_current()->aux_buffers > 0)
2006 TRACE("Using auxilliary buffer for offscreen rendering\n");
2007 This->offscreenBuffer = GL_AUX0;
2009 TRACE("Using back buffer for offscreen rendering\n");
2010 This->offscreenBuffer = GL_BACK;
2015 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2018 context_release(context);
2020 /* Clear the screen */
2021 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2022 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2025 This->d3d_initialized = TRUE;
2027 if(wined3d_settings.logo) {
2028 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2030 This->highest_dirty_ps_const = 0;
2031 This->highest_dirty_vs_const = 0;
2035 HeapFree(GetProcessHeap(), 0, This->render_targets);
2036 HeapFree(GetProcessHeap(), 0, This->swapchains);
2037 This->NumberOfSwapChains = 0;
2038 if(This->palettes) {
2039 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2040 HeapFree(GetProcessHeap(), 0, This->palettes);
2042 This->NumberOfPalettes = 0;
2044 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2046 if(This->stateBlock) {
2047 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2048 This->stateBlock = NULL;
2050 if (This->blit_priv) {
2051 This->blitter->free_private(iface);
2053 if (This->fragment_priv) {
2054 This->frag_pipe->free_private(iface);
2056 if (This->shader_priv) {
2057 This->shader_backend->shader_free_private(iface);
2062 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2063 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2066 IWineD3DSwapChainImpl *swapchain = NULL;
2069 /* Setup the implicit swapchain */
2070 TRACE("Creating implicit swapchain\n");
2071 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2072 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2075 WARN("Failed to create implicit swapchain\n");
2079 This->NumberOfSwapChains = 1;
2080 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2081 if(!This->swapchains) {
2082 ERR("Out of memory!\n");
2085 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2089 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2093 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2095 IWineD3DResource_UnLoad(resource);
2096 IWineD3DResource_Release(resource);
2100 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2101 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2104 const struct wined3d_gl_info *gl_info;
2105 struct wined3d_context *context;
2108 TRACE("(%p)\n", This);
2110 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2112 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2113 * it was created. Thus make sure a context is active for the glDelete* calls
2115 context = context_acquire(This, NULL);
2116 gl_info = context->gl_info;
2118 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2120 /* Unload resources */
2121 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2123 TRACE("Deleting high order patches\n");
2124 for(i = 0; i < PATCHMAP_SIZE; i++) {
2125 struct list *e1, *e2;
2126 struct WineD3DRectPatch *patch;
2127 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2128 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2129 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2133 /* Delete the mouse cursor texture */
2134 if(This->cursorTexture) {
2136 glDeleteTextures(1, &This->cursorTexture);
2138 This->cursorTexture = 0;
2141 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2142 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2144 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2145 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2148 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2149 * private data, it might contain opengl pointers
2151 if(This->depth_blt_texture) {
2153 glDeleteTextures(1, &This->depth_blt_texture);
2155 This->depth_blt_texture = 0;
2157 if (This->depth_blt_rb) {
2159 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2161 This->depth_blt_rb = 0;
2162 This->depth_blt_rb_w = 0;
2163 This->depth_blt_rb_h = 0;
2166 /* Release the update stateblock */
2167 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2168 if(This->updateStateBlock != This->stateBlock)
2169 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2171 This->updateStateBlock = NULL;
2173 { /* because were not doing proper internal refcounts releasing the primary state block
2174 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2175 to set this->stateBlock = NULL; first */
2176 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2177 This->stateBlock = NULL;
2179 /* Release the stateblock */
2180 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2181 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2185 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2186 This->blitter->free_private(iface);
2187 This->frag_pipe->free_private(iface);
2188 This->shader_backend->shader_free_private(iface);
2190 /* Release the buffers (with sanity checks)*/
2191 if (This->onscreen_depth_stencil)
2193 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2194 This->onscreen_depth_stencil = NULL;
2197 if (This->depth_stencil)
2199 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2201 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2203 This->depth_stencil = NULL;
2204 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2205 && ds != This->auto_depth_stencil)
2207 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2211 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2212 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2214 TRACE("Setting rendertarget to NULL\n");
2215 This->render_targets[0] = NULL;
2217 if (This->auto_depth_stencil)
2219 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2221 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2223 This->auto_depth_stencil = NULL;
2226 context_release(context);
2228 for(i=0; i < This->NumberOfSwapChains; i++) {
2229 TRACE("Releasing the implicit swapchain %d\n", i);
2230 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2231 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2235 HeapFree(GetProcessHeap(), 0, This->swapchains);
2236 This->swapchains = NULL;
2237 This->NumberOfSwapChains = 0;
2239 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2240 HeapFree(GetProcessHeap(), 0, This->palettes);
2241 This->palettes = NULL;
2242 This->NumberOfPalettes = 0;
2244 HeapFree(GetProcessHeap(), 0, This->render_targets);
2245 This->render_targets = NULL;
2247 This->d3d_initialized = FALSE;
2252 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2256 for(i=0; i < This->NumberOfSwapChains; i++) {
2257 TRACE("Releasing the implicit swapchain %d\n", i);
2258 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2259 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2263 HeapFree(GetProcessHeap(), 0, This->swapchains);
2264 This->swapchains = NULL;
2265 This->NumberOfSwapChains = 0;
2269 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2270 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2271 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2273 * There is no way to deactivate thread safety once it is enabled.
2275 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2278 /*For now just store the flag(needed in case of ddraw) */
2279 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2282 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2283 const WINED3DDISPLAYMODE* pMode) {
2285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2286 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2290 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2292 /* Resize the screen even without a window:
2293 * The app could have unset it with SetCooperativeLevel, but not called
2294 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2295 * but we don't have any hwnd
2298 memset(&devmode, 0, sizeof(devmode));
2299 devmode.dmSize = sizeof(devmode);
2300 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2301 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2302 devmode.dmPelsWidth = pMode->Width;
2303 devmode.dmPelsHeight = pMode->Height;
2305 devmode.dmDisplayFrequency = pMode->RefreshRate;
2306 if (pMode->RefreshRate)
2307 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2309 /* Only change the mode if necessary */
2310 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2311 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2314 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2315 if (ret != DISP_CHANGE_SUCCESSFUL)
2317 if (devmode.dmDisplayFrequency)
2319 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2320 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2321 devmode.dmDisplayFrequency = 0;
2322 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2324 if(ret != DISP_CHANGE_SUCCESSFUL) {
2325 return WINED3DERR_NOTAVAILABLE;
2329 /* Store the new values */
2330 This->ddraw_width = pMode->Width;
2331 This->ddraw_height = pMode->Height;
2332 This->ddraw_format = pMode->Format;
2334 /* And finally clip mouse to our screen */
2335 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2336 ClipCursor(&clip_rc);
2341 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2343 *ppD3D = This->wined3d;
2344 TRACE("Returning %p.\n", *ppD3D);
2345 IWineD3D_AddRef(*ppD3D);
2349 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2353 (This->adapter->TextureRam/(1024*1024)),
2354 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2355 /* return simulated texture memory left */
2356 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2360 * Get / Set Stream Source
2362 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2363 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2366 struct wined3d_stream_state *stream;
2367 IWineD3DBuffer *oldSrc;
2369 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2370 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2372 if (StreamNumber >= MAX_STREAMS) {
2373 WARN("Stream out of range %d\n", StreamNumber);
2374 return WINED3DERR_INVALIDCALL;
2375 } else if(OffsetInBytes & 0x3) {
2376 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2377 return WINED3DERR_INVALIDCALL;
2380 stream = &This->updateStateBlock->state.streams[StreamNumber];
2381 oldSrc = (IWineD3DBuffer *)stream->buffer;
2383 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2385 if (oldSrc == pStreamData
2386 && stream->stride == Stride
2387 && stream->offset == OffsetInBytes)
2389 TRACE("Application is setting the old values over, nothing to do\n");
2393 stream->buffer = (struct wined3d_buffer *)pStreamData;
2396 stream->stride = Stride;
2397 stream->offset = OffsetInBytes;
2400 /* Handle recording of state blocks */
2401 if (This->isRecordingState) {
2402 TRACE("Recording... not performing anything\n");
2403 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2404 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2410 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2411 IWineD3DBuffer_AddRef(pStreamData);
2415 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2416 IWineD3DBuffer_Release(oldSrc);
2419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2424 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2425 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2428 struct wined3d_stream_state *stream;
2430 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2431 iface, StreamNumber, pStream, pOffset, pStride);
2433 if (StreamNumber >= MAX_STREAMS)
2435 WARN("Stream out of range %d\n", StreamNumber);
2436 return WINED3DERR_INVALIDCALL;
2439 stream = &This->stateBlock->state.streams[StreamNumber];
2440 *pStream = (IWineD3DBuffer *)stream->buffer;
2441 *pStride = stream->stride;
2442 if (pOffset) *pOffset = stream->offset;
2444 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 struct wined3d_stream_state *stream;
2452 UINT oldFlags, oldFreq;
2454 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2456 /* Verify input at least in d3d9 this is invalid. */
2457 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2459 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2460 return WINED3DERR_INVALIDCALL;
2462 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2464 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2465 return WINED3DERR_INVALIDCALL;
2469 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2470 return WINED3DERR_INVALIDCALL;
2473 stream = &This->updateStateBlock->state.streams[StreamNumber];
2474 oldFlags = stream->flags;
2475 oldFreq = stream->frequency;
2477 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2478 stream->frequency = Divider & 0x7FFFFF;
2480 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2482 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2488 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 struct wined3d_stream_state *stream;
2492 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2494 stream = &This->updateStateBlock->state.streams[StreamNumber];
2495 *Divider = stream->flags | stream->frequency;
2497 TRACE("Returning %#x.\n", *Divider);
2503 * Get / Set & Multiply Transform
2505 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 /* Most of this routine, comments included copied from ddraw tree initially: */
2509 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2511 /* Handle recording of state blocks */
2512 if (This->isRecordingState) {
2513 TRACE("Recording... not performing anything\n");
2514 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2515 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2520 * If the new matrix is the same as the current one,
2521 * we cut off any further processing. this seems to be a reasonable
2522 * optimization because as was noticed, some apps (warcraft3 for example)
2523 * tend towards setting the same matrix repeatedly for some reason.
2525 * From here on we assume that the new matrix is different, wherever it matters.
2527 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2529 TRACE("The app is setting the same matrix over again\n");
2534 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2538 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2539 where ViewMat = Camera space, WorldMat = world space.
2541 In OpenGL, camera and world space is combined into GL_MODELVIEW
2542 matrix. The Projection matrix stay projection matrix.
2545 /* Capture the times we can just ignore the change for now */
2546 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2547 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2548 /* Handled by the state manager */
2551 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2558 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2559 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2561 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2563 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2565 *matrix = device->stateBlock->state.transforms[state];
2570 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2571 const WINED3DMATRIX *mat = NULL;
2574 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2575 * below means it will be recorded in a state block change, but it
2576 * works regardless where it is recorded.
2577 * If this is found to be wrong, change to StateBlock.
2579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2582 if (State <= HIGHEST_TRANSFORMSTATE)
2584 mat = &This->updateStateBlock->state.transforms[State];
2588 FIXME("Unhandled transform state!!\n");
2591 multiply_matrix(&temp, mat, pMatrix);
2593 /* Apply change via set transform - will reapply to eg. lights this way */
2594 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2600 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2601 you can reference any indexes you want as long as that number max are enabled at any
2602 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2603 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2604 but when recording, just build a chain pretty much of commands to be replayed. */
2606 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2608 struct wined3d_light_info *object = NULL;
2609 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2615 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2619 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2620 return WINED3DERR_INVALIDCALL;
2623 switch(pLight->Type) {
2624 case WINED3DLIGHT_POINT:
2625 case WINED3DLIGHT_SPOT:
2626 case WINED3DLIGHT_PARALLELPOINT:
2627 case WINED3DLIGHT_GLSPOT:
2628 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2631 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2633 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2634 return WINED3DERR_INVALIDCALL;
2638 case WINED3DLIGHT_DIRECTIONAL:
2639 /* Ignores attenuation */
2643 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2644 return WINED3DERR_INVALIDCALL;
2647 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2649 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2650 if(object->OriginalIndex == Index) break;
2655 TRACE("Adding new light\n");
2656 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2658 ERR("Out of memory error when allocating a light\n");
2659 return E_OUTOFMEMORY;
2661 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2662 object->glIndex = -1;
2663 object->OriginalIndex = Index;
2666 /* Initialize the object */
2667 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,
2668 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2669 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2670 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2671 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2672 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2673 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2675 /* Save away the information */
2676 object->OriginalParms = *pLight;
2678 switch (pLight->Type) {
2679 case WINED3DLIGHT_POINT:
2681 object->lightPosn[0] = pLight->Position.x;
2682 object->lightPosn[1] = pLight->Position.y;
2683 object->lightPosn[2] = pLight->Position.z;
2684 object->lightPosn[3] = 1.0f;
2685 object->cutoff = 180.0f;
2689 case WINED3DLIGHT_DIRECTIONAL:
2691 object->lightPosn[0] = -pLight->Direction.x;
2692 object->lightPosn[1] = -pLight->Direction.y;
2693 object->lightPosn[2] = -pLight->Direction.z;
2694 object->lightPosn[3] = 0.0f;
2695 object->exponent = 0.0f;
2696 object->cutoff = 180.0f;
2699 case WINED3DLIGHT_SPOT:
2701 object->lightPosn[0] = pLight->Position.x;
2702 object->lightPosn[1] = pLight->Position.y;
2703 object->lightPosn[2] = pLight->Position.z;
2704 object->lightPosn[3] = 1.0f;
2707 object->lightDirn[0] = pLight->Direction.x;
2708 object->lightDirn[1] = pLight->Direction.y;
2709 object->lightDirn[2] = pLight->Direction.z;
2710 object->lightDirn[3] = 1.0f;
2713 * opengl-ish and d3d-ish spot lights use too different models for the
2714 * light "intensity" as a function of the angle towards the main light direction,
2715 * so we only can approximate very roughly.
2716 * however spot lights are rather rarely used in games (if ever used at all).
2717 * furthermore if still used, probably nobody pays attention to such details.
2719 if (!pLight->Falloff)
2721 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2722 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2723 * will always be 1.0 for both of them, and we don't have to care for the
2724 * rest of the rather complex calculation
2726 object->exponent = 0.0f;
2728 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2729 if (rho < 0.0001f) rho = 0.0001f;
2730 object->exponent = -0.3f/logf(cosf(rho/2));
2732 if (object->exponent > 128.0f)
2734 object->exponent = 128.0f;
2736 object->cutoff = (float) (pLight->Phi*90/M_PI);
2742 FIXME("Unrecognized light type %d\n", pLight->Type);
2745 /* Update the live definitions if the light is currently assigned a glIndex */
2746 if (object->glIndex != -1 && !This->isRecordingState) {
2747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2752 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2754 struct wined3d_light_info *lightInfo = NULL;
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2758 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2760 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2762 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2763 if(lightInfo->OriginalIndex == Index) break;
2769 TRACE("Light information requested but light not defined\n");
2770 return WINED3DERR_INVALIDCALL;
2773 *pLight = lightInfo->OriginalParms;
2778 * Get / Set Light Enable
2779 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2781 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2783 struct wined3d_light_info *lightInfo = NULL;
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2787 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2789 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2791 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2792 if(lightInfo->OriginalIndex == Index) break;
2795 TRACE("Found light: %p\n", lightInfo);
2797 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2800 TRACE("Light enabled requested but light not defined, so defining one!\n");
2801 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2803 /* Search for it again! Should be fairly quick as near head of list */
2804 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2806 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2807 if(lightInfo->OriginalIndex == Index) break;
2812 FIXME("Adding default lights has failed dismally\n");
2813 return WINED3DERR_INVALIDCALL;
2818 if(lightInfo->glIndex != -1) {
2819 if(!This->isRecordingState) {
2820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2823 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2824 lightInfo->glIndex = -1;
2826 TRACE("Light already disabled, nothing to do\n");
2828 lightInfo->enabled = FALSE;
2830 lightInfo->enabled = TRUE;
2831 if (lightInfo->glIndex != -1) {
2833 TRACE("Nothing to do as light was enabled\n");
2836 /* Find a free gl light */
2837 for (i = 0; i < This->maxConcurrentLights; ++i)
2839 if (!This->updateStateBlock->state.lights[i])
2841 This->updateStateBlock->state.lights[i] = lightInfo;
2842 lightInfo->glIndex = i;
2846 if(lightInfo->glIndex == -1) {
2847 /* Our tests show that Windows returns D3D_OK in this situation, even with
2848 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2849 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2850 * as well for those lights.
2852 * TODO: Test how this affects rendering
2854 WARN("Too many concurrently active lights\n");
2858 /* i == lightInfo->glIndex */
2859 if(!This->isRecordingState) {
2860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2868 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2870 struct wined3d_light_info *lightInfo = NULL;
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2874 TRACE("(%p) : for idx(%d)\n", This, Index);
2876 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2878 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2879 if(lightInfo->OriginalIndex == Index) break;
2885 TRACE("Light enabled state requested but light not defined\n");
2886 return WINED3DERR_INVALIDCALL;
2888 /* true is 128 according to SetLightEnable */
2889 *pEnable = lightInfo->enabled ? 128 : 0;
2894 * Get / Set Clip Planes
2896 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2900 /* Validate Index */
2901 if (Index >= This->adapter->gl_info.limits.clipplanes)
2903 TRACE("Application has requested clipplane this device doesn't support\n");
2904 return WINED3DERR_INVALIDCALL;
2907 This->updateStateBlock->changed.clipplane |= 1 << Index;
2909 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2910 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2911 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2912 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2914 TRACE("Application is setting old values over, nothing to do\n");
2918 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2919 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2920 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2921 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2923 /* Handle recording of state blocks */
2924 if (This->isRecordingState) {
2925 TRACE("Recording... not performing anything\n");
2929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2936 TRACE("(%p) : for idx %d\n", This, Index);
2938 /* Validate Index */
2939 if (Index >= This->adapter->gl_info.limits.clipplanes)
2941 TRACE("Application has requested clipplane this device doesn't support\n");
2942 return WINED3DERR_INVALIDCALL;
2945 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2946 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2947 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2948 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2953 * Get / Set Clip Plane Status
2954 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2956 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 FIXME("(%p) : stub\n", This);
2961 return WINED3DERR_INVALIDCALL;
2963 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2964 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2968 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 FIXME("(%p) : stub\n", This);
2973 return WINED3DERR_INVALIDCALL;
2975 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2976 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2981 * Get / Set Material
2983 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 This->updateStateBlock->changed.material = TRUE;
2987 This->updateStateBlock->state.material = *pMaterial;
2989 /* Handle recording of state blocks */
2990 if (This->isRecordingState) {
2991 TRACE("Recording... not performing anything\n");
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2999 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 *pMaterial = This->updateStateBlock->state.material;
3002 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3003 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3004 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3005 pMaterial->Ambient.b, pMaterial->Ambient.a);
3006 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3007 pMaterial->Specular.b, pMaterial->Specular.a);
3008 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3009 pMaterial->Emissive.b, pMaterial->Emissive.a);
3010 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3018 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3019 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 IWineD3DBuffer *oldIdxs;
3024 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3025 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3027 This->updateStateBlock->changed.indices = TRUE;
3028 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3029 This->updateStateBlock->state.index_format = fmt;
3031 /* Handle recording of state blocks */
3032 if (This->isRecordingState) {
3033 TRACE("Recording... not performing anything\n");
3034 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3035 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3039 if(oldIdxs != pIndexData) {
3040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3042 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3043 IWineD3DBuffer_AddRef(pIndexData);
3046 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3047 IWineD3DBuffer_Release(oldIdxs);
3054 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3060 /* up ref count on ppindexdata */
3062 IWineD3DBuffer_AddRef(*ppIndexData);
3063 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3065 TRACE("(%p) No index data set\n", This);
3067 TRACE("Returning %p\n", *ppIndexData);
3072 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3075 TRACE("(%p)->(%d)\n", This, BaseIndex);
3077 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3079 TRACE("Application is setting the old value over, nothing to do\n");
3083 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3089 /* The base vertex index affects the stream sources */
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3094 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : base_index %p\n", This, base_index);
3098 *base_index = This->stateBlock->state.base_vertex_index;
3100 TRACE("Returning %u\n", *base_index);
3106 * Get / Set Viewports
3108 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3111 TRACE("(%p)\n", This);
3112 This->updateStateBlock->changed.viewport = TRUE;
3113 This->updateStateBlock->state.viewport = *pViewport;
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3121 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3122 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 TRACE("(%p)\n", This);
3132 *pViewport = This->stateBlock->state.viewport;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3137 WINED3DRENDERSTATETYPE State, DWORD Value)
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 DWORD oldValue = This->stateBlock->state.render_states[State];
3142 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3144 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3145 This->updateStateBlock->state.render_states[State] = Value;
3147 /* Handle recording of state blocks */
3148 if (This->isRecordingState) {
3149 TRACE("Recording... not performing anything\n");
3153 /* Compared here and not before the assignment to allow proper stateblock recording */
3154 if(Value == oldValue) {
3155 TRACE("Application is setting the old value over, nothing to do\n");
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3164 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3170 *pValue = This->stateBlock->state.render_states[State];
3175 * Get / Set Sampler States
3176 * TODO: Verify against dx9 definitions
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3184 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3186 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3187 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3190 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3192 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3193 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3196 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3197 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3198 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3200 /* Handle recording of state blocks */
3201 if (This->isRecordingState) {
3202 TRACE("Recording... not performing anything\n");
3206 if(oldValue == Value) {
3207 TRACE("Application is setting the old value over, nothing to do\n");
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3216 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3219 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3220 This, Sampler, debug_d3dsamplerstate(Type), Type);
3222 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3223 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3226 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3228 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3229 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3231 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3232 TRACE("(%p) : Returning %#x\n", This, *Value);
3237 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 This->updateStateBlock->changed.scissorRect = TRUE;
3241 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3243 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3246 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3248 if(This->isRecordingState) {
3249 TRACE("Recording... not performing anything\n");
3253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3258 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 *pRect = This->updateStateBlock->state.scissor_rect;
3262 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3266 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3268 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3270 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3272 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3273 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3275 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3276 This->updateStateBlock->changed.vertexDecl = TRUE;
3278 if (This->isRecordingState) {
3279 TRACE("Recording... not performing anything\n");
3281 } else if(pDecl == oldDecl) {
3282 /* Checked after the assignment to allow proper stateblock recording */
3283 TRACE("Application is setting the old declaration over, nothing to do\n");
3287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3296 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3297 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3301 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3306 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3307 This->updateStateBlock->changed.vertexShader = TRUE;
3309 if (This->isRecordingState) {
3310 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3311 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3312 TRACE("Recording... not performing anything\n");
3314 } else if(oldShader == pShader) {
3315 /* Checked here to allow proper stateblock recording */
3316 TRACE("App is setting the old shader over, nothing to do\n");
3320 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3321 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3322 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3329 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3331 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3332 IWineD3DVertexShader *shader;
3334 TRACE("iface %p.\n", iface);
3336 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3337 if (shader) IWineD3DVertexShader_AddRef(shader);
3339 TRACE("Returning %p.\n", shader);
3343 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3344 IWineD3DDevice *iface,
3346 CONST BOOL *srcData,
3349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3350 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3352 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3353 iface, srcData, start, count);
3355 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3357 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3358 for (i = 0; i < cnt; i++)
3359 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3361 for (i = start; i < cnt + start; ++i) {
3362 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3365 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3371 IWineD3DDevice *iface,
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 int cnt = min(count, MAX_CONST_B - start);
3379 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3380 iface, dstData, start, count);
3382 if (!dstData || cnt < 0)
3383 return WINED3DERR_INVALIDCALL;
3385 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3389 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3390 IWineD3DDevice *iface,
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3396 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3398 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3399 iface, srcData, start, count);
3401 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3403 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3404 for (i = 0; i < cnt; i++)
3405 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3406 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3408 for (i = start; i < cnt + start; ++i) {
3409 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3412 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3418 IWineD3DDevice *iface,
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 int cnt = min(count, MAX_CONST_I - start);
3426 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3427 iface, dstData, start, count);
3429 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3430 return WINED3DERR_INVALIDCALL;
3432 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3436 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3437 IWineD3DDevice *iface,
3439 CONST float *srcData,
3442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3446 iface, srcData, start, count);
3448 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3449 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3450 return WINED3DERR_INVALIDCALL;
3452 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3454 for (i = 0; i < count; i++)
3455 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3456 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3459 if (!This->isRecordingState)
3461 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3465 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3466 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3471 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3472 IWineD3DDevice *iface,
3477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3478 int cnt = min(count, This->d3d_vshader_constantF - start);
3480 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3481 iface, dstData, start, count);
3483 if (!dstData || cnt < 0)
3484 return WINED3DERR_INVALIDCALL;
3486 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3490 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3492 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3498 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3500 DWORD i = This->rev_tex_unit_map[unit];
3501 DWORD j = This->texUnitMap[stage];
3503 This->texUnitMap[stage] = unit;
3504 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3506 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3509 This->rev_tex_unit_map[unit] = stage;
3510 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3512 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3516 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3519 This->fixed_function_usage_map = 0;
3520 for (i = 0; i < MAX_TEXTURES; ++i)
3522 const struct wined3d_state *state = &This->stateBlock->state;
3523 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3524 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3525 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3526 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3527 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3528 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3529 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3530 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3532 if (color_op == WINED3DTOP_DISABLE) {
3533 /* Not used, and disable higher stages */
3537 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3538 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3539 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3540 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3541 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3542 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3543 This->fixed_function_usage_map |= (1 << i);
3546 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3547 This->fixed_function_usage_map |= (1 << (i + 1));
3552 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3554 unsigned int i, tex;
3557 device_update_fixed_function_usage_map(This);
3558 ffu_map = This->fixed_function_usage_map;
3560 if (This->max_ffp_textures == gl_info->limits.texture_stages
3561 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3563 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3565 if (!(ffu_map & 1)) continue;
3567 if (This->texUnitMap[i] != i) {
3568 device_map_stage(This, i, i);
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3570 markTextureStagesDirty(This, i);
3576 /* Now work out the mapping */
3578 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3580 if (!(ffu_map & 1)) continue;
3582 if (This->texUnitMap[i] != tex) {
3583 device_map_stage(This, i, tex);
3584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3585 markTextureStagesDirty(This, i);
3592 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3594 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3595 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3598 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3599 if (sampler_type[i] && This->texUnitMap[i] != i)
3601 device_map_stage(This, i, i);
3602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3603 if (i < gl_info->limits.texture_stages)
3605 markTextureStagesDirty(This, i);
3611 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3612 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3614 DWORD current_mapping = This->rev_tex_unit_map[unit];
3616 /* Not currently used */
3617 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3619 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3620 /* Used by a fragment sampler */
3622 if (!pshader_sampler_tokens) {
3623 /* No pixel shader, check fixed function */
3624 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3627 /* Pixel shader, check the shader's sampler map */
3628 return !pshader_sampler_tokens[current_mapping];
3631 /* Used by a vertex sampler */
3632 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3635 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3637 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3638 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3639 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3640 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3645 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3647 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3648 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3649 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3652 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3653 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3654 if (vshader_sampler_type[i])
3656 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3658 /* Already mapped somewhere */
3662 while (start >= 0) {
3663 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3665 device_map_stage(This, vsampler_idx, start);
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3678 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3680 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3681 const struct wined3d_state *state = &This->stateBlock->state;
3682 BOOL vs = use_vs(state);
3683 BOOL ps = use_ps(state);
3686 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3687 * that would be really messy and require shader recompilation
3688 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3689 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3691 if (ps) device_map_psamplers(This, gl_info);
3692 else device_map_fixed_function_samplers(This, gl_info);
3694 if (vs) device_map_vsamplers(This, ps, gl_info);
3697 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3700 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3701 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3702 This->updateStateBlock->changed.pixelShader = TRUE;
3704 /* Handle recording of state blocks */
3705 if (This->isRecordingState) {
3706 TRACE("Recording... not performing anything\n");
3709 if (This->isRecordingState) {
3710 TRACE("Recording... not performing anything\n");
3711 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3712 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3716 if(pShader == oldShader) {
3717 TRACE("App is setting the old pixel shader over, nothing to do\n");
3721 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3722 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3724 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3730 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3732 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3733 IWineD3DPixelShader *shader;
3735 TRACE("iface %p.\n", iface);
3737 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3738 if (shader) IWineD3DPixelShader_AddRef(shader);
3740 TRACE("Returning %p.\n", shader);
3744 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3745 IWineD3DDevice *iface,
3747 CONST BOOL *srcData,
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3753 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3754 iface, srcData, start, count);
3756 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3758 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3759 for (i = 0; i < cnt; i++)
3760 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3762 for (i = start; i < cnt + start; ++i) {
3763 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3766 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3771 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3772 IWineD3DDevice *iface,
3777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3778 int cnt = min(count, MAX_CONST_B - start);
3780 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3781 iface, dstData, start, count);
3783 if (!dstData || cnt < 0)
3784 return WINED3DERR_INVALIDCALL;
3786 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3790 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3791 IWineD3DDevice *iface,
3796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3797 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3799 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3800 iface, srcData, start, count);
3802 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3804 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3805 for (i = 0; i < cnt; i++)
3806 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3807 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3809 for (i = start; i < cnt + start; ++i) {
3810 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3813 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3818 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3819 IWineD3DDevice *iface,
3824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3825 int cnt = min(count, MAX_CONST_I - start);
3827 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3828 iface, dstData, start, count);
3830 if (!dstData || cnt < 0)
3831 return WINED3DERR_INVALIDCALL;
3833 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3837 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3838 IWineD3DDevice *iface,
3840 CONST float *srcData,
3843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3847 iface, srcData, start, count);
3849 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3850 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3851 return WINED3DERR_INVALIDCALL;
3853 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3855 for (i = 0; i < count; i++)
3856 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3857 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3860 if (!This->isRecordingState)
3862 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3866 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3867 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3872 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3873 IWineD3DDevice *iface,
3878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3879 int cnt = min(count, This->d3d_pshader_constantF - start);
3881 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3882 iface, dstData, start, count);
3884 if (!dstData || cnt < 0)
3885 return WINED3DERR_INVALIDCALL;
3887 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3891 /* Context activation is done by the caller. */
3892 /* Do not call while under the GL lock. */
3893 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3894 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3895 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3898 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3899 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3902 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3906 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3908 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3911 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3913 ERR("Source has no position mask\n");
3914 return WINED3DERR_INVALIDCALL;
3917 if (!dest->resource.allocatedMemory)
3918 buffer_get_sysmem(dest, gl_info);
3920 /* Get a pointer into the destination vbo(create one if none exists) and
3921 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3923 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3925 dest->flags |= WINED3D_BUFFER_CREATEBO;
3926 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3929 if (dest->buffer_object)
3931 unsigned char extrabytes = 0;
3932 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3933 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3934 * this may write 4 extra bytes beyond the area that should be written
3936 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3937 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3938 if(!dest_conv_addr) {
3939 ERR("Out of memory\n");
3940 /* Continue without storing converted vertices */
3942 dest_conv = dest_conv_addr;
3945 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3947 static BOOL warned = FALSE;
3949 * The clipping code is not quite correct. Some things need
3950 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3951 * so disable clipping for now.
3952 * (The graphics in Half-Life are broken, and my processvertices
3953 * test crashes with IDirect3DDevice3)
3959 FIXME("Clipping is broken and disabled for now\n");
3961 } else doClip = FALSE;
3962 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3964 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3967 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3968 WINED3DTS_PROJECTION,
3970 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3971 WINED3DTS_WORLDMATRIX(0),
3974 TRACE("View mat:\n");
3975 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);
3976 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);
3977 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);
3978 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);
3980 TRACE("Proj mat:\n");
3981 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);
3982 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);
3983 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);
3984 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);
3986 TRACE("World mat:\n");
3987 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);
3988 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);
3989 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);
3990 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);
3992 /* Get the viewport */
3993 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3994 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3995 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3997 multiply_matrix(&mat,&view_mat,&world_mat);
3998 multiply_matrix(&mat,&proj_mat,&mat);
4000 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4002 for (i = 0; i < dwCount; i+= 1) {
4003 unsigned int tex_index;
4005 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4006 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4007 /* The position first */
4008 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4009 const float *p = (const float *)(element->data + i * element->stride);
4011 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4013 /* Multiplication with world, view and projection matrix */
4014 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);
4015 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);
4016 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);
4017 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);
4019 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4021 /* WARNING: The following things are taken from d3d7 and were not yet checked
4022 * against d3d8 or d3d9!
4025 /* Clipping conditions: From msdn
4027 * A vertex is clipped if it does not match the following requirements
4031 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4033 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4034 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4039 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4040 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4043 /* "Normal" viewport transformation (not clipped)
4044 * 1) The values are divided by rhw
4045 * 2) The y axis is negative, so multiply it with -1
4046 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4047 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4048 * 4) Multiply x with Width/2 and add Width/2
4049 * 5) The same for the height
4050 * 6) Add the viewpoint X and Y to the 2D coordinates and
4051 * The minimum Z value to z
4052 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4054 * Well, basically it's simply a linear transformation into viewport
4066 z *= vp.MaxZ - vp.MinZ;
4068 x += vp.Width / 2 + vp.X;
4069 y += vp.Height / 2 + vp.Y;
4074 /* That vertex got clipped
4075 * Contrary to OpenGL it is not dropped completely, it just
4076 * undergoes a different calculation.
4078 TRACE("Vertex got clipped\n");
4085 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4086 * outside of the main vertex buffer memory. That needs some more
4091 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4094 ( (float *) dest_ptr)[0] = x;
4095 ( (float *) dest_ptr)[1] = y;
4096 ( (float *) dest_ptr)[2] = z;
4097 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4099 dest_ptr += 3 * sizeof(float);
4101 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4102 dest_ptr += sizeof(float);
4107 ( (float *) dest_conv)[0] = x * w;
4108 ( (float *) dest_conv)[1] = y * w;
4109 ( (float *) dest_conv)[2] = z * w;
4110 ( (float *) dest_conv)[3] = w;
4112 dest_conv += 3 * sizeof(float);
4114 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4115 dest_conv += sizeof(float);
4119 if (DestFVF & WINED3DFVF_PSIZE) {
4120 dest_ptr += sizeof(DWORD);
4121 if(dest_conv) dest_conv += sizeof(DWORD);
4123 if (DestFVF & WINED3DFVF_NORMAL) {
4124 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4125 const float *normal = (const float *)(element->data + i * element->stride);
4126 /* AFAIK this should go into the lighting information */
4127 FIXME("Didn't expect the destination to have a normal\n");
4128 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4130 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4134 if (DestFVF & WINED3DFVF_DIFFUSE) {
4135 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4136 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4137 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4139 static BOOL warned = FALSE;
4142 ERR("No diffuse color in source, but destination has one\n");
4146 *( (DWORD *) dest_ptr) = 0xffffffff;
4147 dest_ptr += sizeof(DWORD);
4150 *( (DWORD *) dest_conv) = 0xffffffff;
4151 dest_conv += sizeof(DWORD);
4155 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4157 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4158 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4159 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4160 dest_conv += sizeof(DWORD);
4165 if (DestFVF & WINED3DFVF_SPECULAR)
4167 /* What's the color value in the feedback buffer? */
4168 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4169 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4170 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4172 static BOOL warned = FALSE;
4175 ERR("No specular color in source, but destination has one\n");
4179 *( (DWORD *) dest_ptr) = 0xFF000000;
4180 dest_ptr += sizeof(DWORD);
4183 *( (DWORD *) dest_conv) = 0xFF000000;
4184 dest_conv += sizeof(DWORD);
4188 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4190 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4191 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4192 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4193 dest_conv += sizeof(DWORD);
4198 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4199 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4200 const float *tex_coord = (const float *)(element->data + i * element->stride);
4201 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4203 ERR("No source texture, but destination requests one\n");
4204 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4205 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4208 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4210 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4220 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4221 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4222 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4223 dwCount * get_flexible_vertex_size(DestFVF),
4225 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4229 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4234 #undef copy_and_next
4236 /* Do not call while under the GL lock. */
4237 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4238 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4242 struct wined3d_stream_info stream_info;
4243 const struct wined3d_gl_info *gl_info;
4244 struct wined3d_context *context;
4245 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4248 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4251 ERR("Output vertex declaration not implemented yet\n");
4254 /* Need any context to write to the vbo. */
4255 context = context_acquire(This, NULL);
4256 gl_info = context->gl_info;
4258 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4259 * control the streamIsUP flag, thus restore it afterwards.
4261 This->stateBlock->state.user_stream = FALSE;
4262 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4263 This->stateBlock->state.user_stream = streamWasUP;
4265 if(vbo || SrcStartIndex) {
4267 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4268 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4270 * Also get the start index in, but only loop over all elements if there's something to add at all.
4272 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4274 struct wined3d_stream_info_element *e;
4276 if (!(stream_info.use_map & (1 << i))) continue;
4278 e = &stream_info.elements[i];
4279 if (e->buffer_object)
4281 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4282 e->buffer_object = 0;
4283 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4285 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4286 vb->buffer_object = 0;
4289 if (e->data) e->data += e->stride * SrcStartIndex;
4293 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4294 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4296 context_release(context);
4302 * Get / Set Texture Stage States
4303 * TODO: Verify against dx9 definitions
4305 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4308 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4311 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4313 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4315 WARN("Invalid Type %d passed.\n", Type);
4319 if (Stage >= gl_info->limits.texture_stages)
4321 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4322 Stage, gl_info->limits.texture_stages - 1);
4326 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4327 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4328 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4330 if (This->isRecordingState) {
4331 TRACE("Recording... not performing anything\n");
4335 /* Checked after the assignments to allow proper stateblock recording */
4336 if(oldValue == Value) {
4337 TRACE("App is setting the old value over, nothing to do\n");
4341 if (Stage > This->stateBlock->state.lowest_disabled_stage
4342 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4343 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4345 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4346 * Changes in other states are important on disabled stages too
4351 if(Type == WINED3DTSS_COLOROP) {
4354 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4355 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4356 * they have to be disabled
4358 * The current stage is dirtified below.
4360 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4362 TRACE("Additionally dirtifying stage %u\n", i);
4363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4365 This->stateBlock->state.lowest_disabled_stage = Stage;
4366 TRACE("New lowest disabled: %u\n", Stage);
4367 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4368 /* Previously disabled stage enabled. Stages above it may need enabling
4369 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4370 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4372 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4375 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4377 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4379 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4382 This->stateBlock->state.lowest_disabled_stage = i;
4383 TRACE("New lowest disabled: %u\n", i);
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4392 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4396 TRACE("iface %p, stage %u, state %s, value %p.\n",
4397 iface, Stage, debug_d3dtexturestate(Type), pValue);
4399 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4401 WARN("Invalid Type %d passed.\n", Type);
4405 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4406 TRACE("Returning %#x.\n", *pValue);
4414 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4415 DWORD stage, IWineD3DBaseTexture *texture)
4417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4418 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4419 IWineD3DBaseTexture *prev;
4421 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4423 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4424 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4426 /* Windows accepts overflowing this array... we do not. */
4427 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4429 WARN("Ignoring invalid stage %u.\n", stage);
4433 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4434 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4436 WARN("Rejecting attempt to set scratch texture.\n");
4437 return WINED3DERR_INVALIDCALL;
4440 This->updateStateBlock->changed.textures |= 1 << stage;
4442 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4443 TRACE("Previous texture %p.\n", prev);
4445 if (texture == prev)
4447 TRACE("App is setting the same texture again, nothing to do.\n");
4451 TRACE("Setting new texture to %p.\n", texture);
4452 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4454 if (This->isRecordingState)
4456 TRACE("Recording... not performing anything\n");
4458 if (texture) IWineD3DBaseTexture_AddRef(texture);
4459 if (prev) IWineD3DBaseTexture_Release(prev);
4466 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4467 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4468 GLenum dimensions = t->baseTexture.target;
4470 IWineD3DBaseTexture_AddRef(texture);
4472 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4475 if (!prev && stage < gl_info->limits.texture_stages)
4477 /* The source arguments for color and alpha ops have different
4478 * meanings when a NULL texture is bound, so the COLOROP and
4479 * ALPHAOP have to be dirtified. */
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4484 if (bind_count == 1) t->baseTexture.sampler = stage;
4489 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4490 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4492 IWineD3DBaseTexture_Release(prev);
4494 if (!texture && stage < gl_info->limits.texture_stages)
4496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4500 if (bind_count && t->baseTexture.sampler == stage)
4504 /* Search for other stages the texture is bound to. Shouldn't
4505 * happen if applications bind textures to a single stage only. */
4506 TRACE("Searching for other stages the texture is bound to.\n");
4507 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4509 if (This->updateStateBlock->state.textures[i] == t)
4511 TRACE("Texture is also bound to stage %u.\n", i);
4512 t->baseTexture.sampler = i;
4519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4524 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4529 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4530 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4533 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4535 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4536 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4539 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4541 IWineD3DBaseTexture_AddRef(*ppTexture);
4543 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4551 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4552 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4554 IWineD3DSwapChain *swapchain;
4557 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4558 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4560 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4563 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4567 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4568 IWineD3DSwapChain_Release(swapchain);
4571 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4578 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 WARN("(%p) : stub, calling idirect3d for now\n", This);
4581 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4584 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 IWineD3DSwapChain *swapChain;
4589 if(iSwapChain > 0) {
4590 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4591 if (hr == WINED3D_OK) {
4592 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4593 IWineD3DSwapChain_Release(swapChain);
4595 FIXME("(%p) Error getting display mode\n", This);
4598 /* Don't read the real display mode,
4599 but return the stored mode instead. X11 can't change the color
4600 depth, and some apps are pretty angry if they SetDisplayMode from
4601 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4603 Also don't relay to the swapchain because with ddraw it's possible
4604 that there isn't a swapchain at all */
4605 pMode->Width = This->ddraw_width;
4606 pMode->Height = This->ddraw_height;
4607 pMode->Format = This->ddraw_format;
4608 pMode->RefreshRate = 0;
4616 * Stateblock related functions
4619 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 IWineD3DStateBlock *stateblock;
4624 TRACE("(%p)\n", This);
4626 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4628 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4629 if (FAILED(hr)) return hr;
4631 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4632 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4633 This->isRecordingState = TRUE;
4635 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4640 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4644 if (!This->isRecordingState) {
4645 WARN("(%p) not recording! returning error\n", This);
4646 *ppStateBlock = NULL;
4647 return WINED3DERR_INVALIDCALL;
4650 stateblock_init_contained_states(object);
4652 *ppStateBlock = (IWineD3DStateBlock*) object;
4653 This->isRecordingState = FALSE;
4654 This->updateStateBlock = This->stateBlock;
4655 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4656 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4657 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4662 * Scene related functions
4664 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4665 /* At the moment we have no need for any functionality at the beginning
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 TRACE("(%p)\n", This);
4671 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4672 return WINED3DERR_INVALIDCALL;
4674 This->inScene = TRUE;
4678 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 struct wined3d_context *context;
4683 TRACE("(%p)\n", This);
4685 if(!This->inScene) {
4686 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4687 return WINED3DERR_INVALIDCALL;
4690 context = context_acquire(This, NULL);
4691 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4693 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4695 context_release(context);
4697 This->inScene = FALSE;
4701 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4702 const RECT *pSourceRect, const RECT *pDestRect,
4703 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4705 IWineD3DSwapChain *swapChain = NULL;
4707 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4709 TRACE("iface %p.\n", iface);
4711 for(i = 0 ; i < swapchains ; i ++) {
4713 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4714 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4715 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4716 IWineD3DSwapChain_Release(swapChain);
4722 /* Do not call while under the GL lock. */
4723 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4724 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4726 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4727 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4730 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4731 iface, rect_count, rects, flags, color, depth, stencil);
4733 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4735 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4736 /* TODO: What about depth stencil buffers without stencil bits? */
4737 return WINED3DERR_INVALIDCALL;
4740 device_get_draw_rect(device, &draw_rect);
4742 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4743 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4750 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4751 WINED3DPRIMITIVETYPE primitive_type)
4753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4757 This->updateStateBlock->changed.primitive_type = TRUE;
4758 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4761 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4762 WINED3DPRIMITIVETYPE *primitive_type)
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4766 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4768 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4770 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4773 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4777 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4779 if (!This->stateBlock->state.vertex_declaration)
4781 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4786 if (This->stateBlock->state.user_stream)
4788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4789 This->stateBlock->state.user_stream = FALSE;
4792 if (This->stateBlock->state.load_base_vertex_index)
4794 This->stateBlock->state.load_base_vertex_index = 0;
4795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4797 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4798 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4802 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4805 struct wined3d_buffer *index_buffer;
4809 index_buffer = This->stateBlock->state.index_buffer;
4812 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4813 * without an index buffer set. (The first time at least...)
4814 * D3D8 simply dies, but I doubt it can do much harm to return
4815 * D3DERR_INVALIDCALL there as well. */
4816 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4817 return WINED3DERR_INVALIDCALL;
4820 if (!This->stateBlock->state.vertex_declaration)
4822 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4823 return WINED3DERR_INVALIDCALL;
4826 if (This->stateBlock->state.user_stream)
4828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4829 This->stateBlock->state.user_stream = FALSE;
4831 vbo = index_buffer->buffer_object;
4833 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4835 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4840 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4842 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4846 drawPrimitive(iface, index_count, startIndex, idxStride,
4847 vbo ? NULL : index_buffer->resource.allocatedMemory);
4852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4853 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 struct wined3d_stream_state *stream;
4859 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4860 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4862 if (!This->stateBlock->state.vertex_declaration)
4864 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4865 return WINED3DERR_INVALIDCALL;
4868 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4869 stream = &This->stateBlock->state.streams[0];
4870 vb = (IWineD3DBuffer *)stream->buffer;
4871 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4872 if (vb) IWineD3DBuffer_Release(vb);
4874 stream->stride = VertexStreamZeroStride;
4875 This->stateBlock->state.user_stream = TRUE;
4876 This->stateBlock->state.load_base_vertex_index = 0;
4878 /* TODO: Only mark dirty if drawing from a different UP address */
4879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4881 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4883 /* MSDN specifies stream zero settings must be set to NULL */
4884 stream->buffer = NULL;
4887 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4888 * the new stream sources or use UP drawing again
4893 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4894 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4895 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 struct wined3d_stream_state *stream;
4903 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4904 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4906 if (!This->stateBlock->state.vertex_declaration)
4908 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4909 return WINED3DERR_INVALIDCALL;
4912 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4918 stream = &This->stateBlock->state.streams[0];
4919 vb = (IWineD3DBuffer *)stream->buffer;
4920 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4921 if (vb) IWineD3DBuffer_Release(vb);
4923 stream->stride = VertexStreamZeroStride;
4924 This->stateBlock->state.user_stream = TRUE;
4926 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4927 This->stateBlock->state.base_vertex_index = 0;
4928 This->stateBlock->state.load_base_vertex_index = 0;
4929 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4933 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4935 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4936 stream->buffer = NULL;
4938 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4941 IWineD3DBuffer_Release(ib);
4942 This->stateBlock->state.index_buffer = NULL;
4944 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4945 * SetStreamSource to specify a vertex buffer
4951 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4952 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4956 /* Mark the state dirty until we have nicer tracking
4957 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4962 This->stateBlock->state.base_vertex_index = 0;
4963 This->up_strided = DrawPrimStrideData;
4964 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4965 This->up_strided = NULL;
4969 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4970 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4971 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4974 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4976 /* Mark the state dirty until we have nicer tracking
4977 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4982 This->stateBlock->state.user_stream = TRUE;
4983 This->stateBlock->state.base_vertex_index = 0;
4984 This->up_strided = DrawPrimStrideData;
4985 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4986 This->up_strided = NULL;
4990 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4991 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4992 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4994 WINED3DLOCKED_BOX src;
4995 WINED3DLOCKED_BOX dst;
4998 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4999 iface, pSourceVolume, pDestinationVolume);
5001 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5002 * dirtification to improve loading performance.
5004 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5005 if (FAILED(hr)) return hr;
5006 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5009 IWineD3DVolume_Unmap(pSourceVolume);
5013 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5015 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5017 IWineD3DVolume_Unmap(pSourceVolume);
5019 hr = IWineD3DVolume_Unmap(pSourceVolume);
5024 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5025 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5027 unsigned int level_count, i;
5028 WINED3DRESOURCETYPE type;
5031 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5033 /* Verify that the source and destination textures are non-NULL. */
5034 if (!src_texture || !dst_texture)
5036 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5037 return WINED3DERR_INVALIDCALL;
5040 if (src_texture == dst_texture)
5042 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5043 return WINED3DERR_INVALIDCALL;
5046 /* Verify that the source and destination textures are the same type. */
5047 type = IWineD3DBaseTexture_GetType(src_texture);
5048 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5050 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5051 return WINED3DERR_INVALIDCALL;
5054 /* Check that both textures have the identical numbers of levels. */
5055 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5056 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5058 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5059 return WINED3DERR_INVALIDCALL;
5062 /* Make sure that the destination texture is loaded. */
5063 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5065 /* Update every surface level of the texture. */
5068 case WINED3DRTYPE_TEXTURE:
5070 IWineD3DSurface *src_surface;
5071 IWineD3DSurface *dst_surface;
5073 for (i = 0; i < level_count; ++i)
5075 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5076 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5077 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5078 IWineD3DSurface_Release(dst_surface);
5079 IWineD3DSurface_Release(src_surface);
5082 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5089 case WINED3DRTYPE_CUBETEXTURE:
5091 IWineD3DSurface *src_surface;
5092 IWineD3DSurface *dst_surface;
5094 for (i = 0; i < level_count * 6; ++i)
5096 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5097 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5098 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5099 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5100 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5101 IWineD3DSurface_Release(dst_surface);
5102 IWineD3DSurface_Release(src_surface);
5105 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5112 case WINED3DRTYPE_VOLUMETEXTURE:
5114 IWineD3DVolume *src_volume;
5115 IWineD3DVolume *dst_volume;
5117 for (i = 0; i < level_count; ++i)
5119 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5120 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5121 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5122 IWineD3DVolume_Release(dst_volume);
5123 IWineD3DVolume_Release(src_volume);
5126 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5134 FIXME("Unsupported texture type %#x.\n", type);
5135 return WINED3DERR_INVALIDCALL;
5141 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5142 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5144 IWineD3DSwapChain *swapchain;
5147 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5149 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5150 if (FAILED(hr)) return hr;
5152 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5153 IWineD3DSwapChain_Release(swapchain);
5158 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5160 IWineD3DBaseTextureImpl *texture;
5163 TRACE("(%p) : %p\n", This, pNumPasses);
5165 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5167 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5169 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5170 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5172 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5174 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5175 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5178 texture = This->stateBlock->state.textures[i];
5179 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5181 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5183 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5186 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5188 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5191 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5192 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5194 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5199 /* return a sensible default */
5202 TRACE("returning D3D_OK\n");
5206 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5210 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5212 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5213 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5214 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5216 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5221 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 PALETTEENTRY **palettes;
5227 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5229 if (PaletteNumber >= MAX_PALETTES) {
5230 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5231 return WINED3DERR_INVALIDCALL;
5234 if (PaletteNumber >= This->NumberOfPalettes) {
5235 NewSize = This->NumberOfPalettes;
5238 } while(PaletteNumber >= NewSize);
5239 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5241 ERR("Out of memory!\n");
5242 return E_OUTOFMEMORY;
5244 This->palettes = palettes;
5245 This->NumberOfPalettes = NewSize;
5248 if (!This->palettes[PaletteNumber]) {
5249 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5250 if (!This->palettes[PaletteNumber]) {
5251 ERR("Out of memory!\n");
5252 return E_OUTOFMEMORY;
5256 for (j = 0; j < 256; ++j) {
5257 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5258 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5259 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5260 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5262 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5263 TRACE("(%p) : returning\n", This);
5267 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5270 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5271 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5272 /* What happens in such situation isn't documented; Native seems to silently abort
5273 on such conditions. Return Invalid Call. */
5274 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5275 return WINED3DERR_INVALIDCALL;
5277 for (j = 0; j < 256; ++j) {
5278 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5279 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5280 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5281 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5283 TRACE("(%p) : returning\n", This);
5287 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5290 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5291 (tested with reference rasterizer). Return Invalid Call. */
5292 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5293 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5294 return WINED3DERR_INVALIDCALL;
5296 /*TODO: stateblocks */
5297 if (This->currentPalette != PaletteNumber) {
5298 This->currentPalette = PaletteNumber;
5299 dirtify_p8_texture_samplers(This);
5301 TRACE("(%p) : returning\n", This);
5305 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5310 WARN("(%p) : returning Invalid Call\n", This);
5311 return WINED3DERR_INVALIDCALL;
5313 /*TODO: stateblocks */
5314 *PaletteNumber = This->currentPalette;
5315 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5319 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5324 FIXME("(%p) : stub\n", This);
5328 This->softwareVertexProcessing = bSoftware;
5333 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 FIXME("(%p) : stub\n", This);
5341 return This->softwareVertexProcessing;
5344 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5345 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5347 IWineD3DSwapChain *swapchain;
5350 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5351 iface, swapchain_idx, raster_status);
5353 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5356 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5360 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5361 IWineD3DSwapChain_Release(swapchain);
5364 WARN("Failed to get raster status, hr %#x.\n", hr);
5371 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5374 if(nSegments != 0.0f) {
5377 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5384 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5389 FIXME("iface %p stub!\n", iface);
5395 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5396 IWineD3DSurface *src_surface, const RECT *src_rect,
5397 IWineD3DSurface *dst_surface, const POINT *dst_point)
5399 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5400 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5402 const struct wined3d_format *src_format;
5403 const struct wined3d_format *dst_format;
5404 const struct wined3d_gl_info *gl_info;
5405 struct wined3d_context *context;
5406 const unsigned char *data;
5407 UINT update_w, update_h;
5408 CONVERT_TYPES convert;
5412 struct wined3d_format format;
5414 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5415 iface, src_surface, wine_dbgstr_rect(src_rect),
5416 dst_surface, wine_dbgstr_point(dst_point));
5418 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5420 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5421 src_surface, dst_surface);
5422 return WINED3DERR_INVALIDCALL;
5425 src_format = src_impl->resource.format;
5426 dst_format = dst_impl->resource.format;
5428 if (src_format->id != dst_format->id)
5430 WARN("Source and destination surfaces should have the same format.\n");
5431 return WINED3DERR_INVALIDCALL;
5434 dst_x = dst_point ? dst_point->x : 0;
5435 dst_y = dst_point ? dst_point->y : 0;
5437 /* This call loads the OpenGL surface directly, instead of copying the
5438 * surface to the destination's sysmem copy. If surface conversion is
5439 * needed, use BltFast instead to copy in sysmem and use regular surface
5441 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5442 if (convert != NO_CONVERSION || format.convert)
5443 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5445 context = context_acquire(This, NULL);
5446 gl_info = context->gl_info;
5449 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5450 checkGLcall("glActiveTextureARB");
5453 /* Make sure the surface is loaded and up to date */
5454 surface_internal_preload(dst_impl, SRGB_RGB);
5455 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5457 src_w = src_impl->currentDesc.Width;
5458 src_h = src_impl->currentDesc.Height;
5459 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5460 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5462 data = IWineD3DSurface_GetData(src_surface);
5463 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5467 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5469 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5470 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5471 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5475 data += (src_rect->top / src_format->block_height) * src_pitch;
5476 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5479 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5480 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5481 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5483 if (row_length == src_pitch)
5485 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5486 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5492 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5493 * can't use the unpack row length like below. */
5494 for (row = 0, y = dst_y; row < row_count; ++row)
5496 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5497 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5498 y += src_format->block_height;
5502 checkGLcall("glCompressedTexSubImage2DARB");
5508 data += src_rect->top * src_w * src_format->byte_count;
5509 data += src_rect->left * src_format->byte_count;
5512 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5513 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5514 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5516 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5517 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5518 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5519 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5520 checkGLcall("glTexSubImage2D");
5524 context_release(context);
5526 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5527 sampler = This->rev_tex_unit_map[0];
5528 if (sampler != WINED3D_UNMAPPED_STAGE)
5530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5536 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 struct WineD3DRectPatch *patch;
5539 GLenum old_primitive_type;
5543 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5545 if(!(Handle || pRectPatchInfo)) {
5546 /* TODO: Write a test for the return value, thus the FIXME */
5547 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5548 return WINED3DERR_INVALIDCALL;
5552 i = PATCHMAP_HASHFUNC(Handle);
5554 LIST_FOR_EACH(e, &This->patches[i]) {
5555 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5556 if(patch->Handle == Handle) {
5563 TRACE("Patch does not exist. Creating a new one\n");
5564 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5565 patch->Handle = Handle;
5566 list_add_head(&This->patches[i], &patch->entry);
5568 TRACE("Found existing patch %p\n", patch);
5571 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5572 * attributes we have to tesselate, read back, and draw. This needs a patch
5573 * management structure instance. Create one.
5575 * A possible improvement is to check if a vertex shader is used, and if not directly
5578 FIXME("Drawing an uncached patch. This is slow\n");
5579 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5582 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5583 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5584 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5587 TRACE("Tesselation density or patch info changed, retesselating\n");
5589 if(pRectPatchInfo) {
5590 patch->RectPatchInfo = *pRectPatchInfo;
5592 patch->numSegs[0] = pNumSegs[0];
5593 patch->numSegs[1] = pNumSegs[1];
5594 patch->numSegs[2] = pNumSegs[2];
5595 patch->numSegs[3] = pNumSegs[3];
5597 hr = tesselate_rectpatch(This, patch);
5599 WARN("Patch tesselation failed\n");
5601 /* Do not release the handle to store the params of the patch */
5603 HeapFree(GetProcessHeap(), 0, patch);
5609 This->currentPatch = patch;
5610 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5611 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5612 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5613 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5614 This->currentPatch = NULL;
5616 /* Destroy uncached patches */
5618 HeapFree(GetProcessHeap(), 0, patch->mem);
5619 HeapFree(GetProcessHeap(), 0, patch);
5624 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5625 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5627 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5628 iface, handle, segment_count, patch_info);
5633 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5636 struct WineD3DRectPatch *patch;
5638 TRACE("(%p) Handle(%d)\n", This, Handle);
5640 i = PATCHMAP_HASHFUNC(Handle);
5641 LIST_FOR_EACH(e, &This->patches[i]) {
5642 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5643 if(patch->Handle == Handle) {
5644 TRACE("Deleting patch %p\n", patch);
5645 list_remove(&patch->entry);
5646 HeapFree(GetProcessHeap(), 0, patch->mem);
5647 HeapFree(GetProcessHeap(), 0, patch);
5652 /* TODO: Write a test for the return value */
5653 FIXME("Attempt to destroy nonexistent patch\n");
5654 return WINED3DERR_INVALIDCALL;
5657 /* Do not call while under the GL lock. */
5658 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5659 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5661 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5663 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5664 iface, surface, wine_dbgstr_rect(rect),
5665 color->r, color->g, color->b, color->a);
5667 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5669 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5670 return WINED3DERR_INVALIDCALL;
5673 return surface_color_fill(s, rect, color);
5676 /* Do not call while under the GL lock. */
5677 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5678 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5680 IWineD3DResource *resource;
5683 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5686 ERR("Failed to get resource, hr %#x\n", hr);
5690 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5692 FIXME("Only supported on surface resources\n");
5693 IWineD3DResource_Release(resource);
5697 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5698 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5700 IWineD3DResource_Release(resource);
5703 /* rendertarget and depth stencil functions */
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5705 DWORD render_target_idx, IWineD3DSurface **render_target)
5707 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5709 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5710 iface, render_target_idx, render_target);
5712 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5714 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5715 return WINED3DERR_INVALIDCALL;
5718 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5719 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5721 TRACE("Returning render target %p.\n", *render_target);
5726 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5728 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5730 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5732 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5733 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5734 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5735 IWineD3DSurface_AddRef(*depth_stencil);
5740 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5741 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5743 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5744 IWineD3DSurfaceImpl *prev;
5746 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5747 iface, render_target_idx, render_target, set_viewport);
5749 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5751 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5752 return WINED3DERR_INVALIDCALL;
5755 prev = device->render_targets[render_target_idx];
5756 if (render_target == (IWineD3DSurface *)prev)
5758 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5762 /* Render target 0 can't be set to NULL. */
5763 if (!render_target && !render_target_idx)
5765 WARN("Trying to set render target 0 to NULL.\n");
5766 return WINED3DERR_INVALIDCALL;
5769 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5771 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5772 return WINED3DERR_INVALIDCALL;
5775 if (render_target) IWineD3DSurface_AddRef(render_target);
5776 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5777 /* Release after the assignment, to prevent device_resource_released()
5778 * from seeing the surface as still in use. */
5779 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5781 /* Render target 0 is special. */
5782 if (!render_target_idx && set_viewport)
5784 /* Set the viewport and scissor rectangles, if requested. Tests show
5785 * that stateblock recording is ignored, the change goes directly
5786 * into the primary stateblock. */
5787 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5788 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5789 device->stateBlock->state.viewport.X = 0;
5790 device->stateBlock->state.viewport.Y = 0;
5791 device->stateBlock->state.viewport.MaxZ = 1.0f;
5792 device->stateBlock->state.viewport.MinZ = 0.0f;
5793 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5795 device->stateBlock->state.scissor_rect.top = 0;
5796 device->stateBlock->state.scissor_rect.left = 0;
5797 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5798 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5799 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5805 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5808 IWineD3DSurfaceImpl *tmp;
5810 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5812 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5814 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5818 if (This->depth_stencil)
5820 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5821 || This->depth_stencil->Flags & SFLAG_DISCARD)
5823 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5824 This->depth_stencil->currentDesc.Width,
5825 This->depth_stencil->currentDesc.Height);
5826 if (This->depth_stencil == This->onscreen_depth_stencil)
5828 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5829 This->onscreen_depth_stencil = NULL;
5834 tmp = This->depth_stencil;
5835 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5836 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5837 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5839 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5841 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5850 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5851 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5855 WINED3DLOCKED_RECT lockedRect;
5857 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5858 iface, XHotSpot, YHotSpot, cursor_image);
5860 /* some basic validation checks */
5861 if (This->cursorTexture)
5863 struct wined3d_context *context = context_acquire(This, NULL);
5865 glDeleteTextures(1, &This->cursorTexture);
5867 context_release(context);
5868 This->cursorTexture = 0;
5871 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5872 This->haveHardwareCursor = TRUE;
5874 This->haveHardwareCursor = FALSE;
5878 WINED3DLOCKED_RECT rect;
5880 /* MSDN: Cursor must be A8R8G8B8 */
5881 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5883 WARN("surface %p has an invalid format.\n", cursor_image);
5884 return WINED3DERR_INVALIDCALL;
5887 /* MSDN: Cursor must be smaller than the display mode */
5888 if (s->currentDesc.Width > This->ddraw_width
5889 || s->currentDesc.Height > This->ddraw_height)
5891 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5892 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5893 return WINED3DERR_INVALIDCALL;
5896 if (!This->haveHardwareCursor) {
5897 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5899 /* Do not store the surface's pointer because the application may
5900 * release it after setting the cursor image. Windows doesn't
5901 * addref the set surface, so we can't do this either without
5902 * creating circular refcount dependencies. Copy out the gl texture
5905 This->cursorWidth = s->currentDesc.Width;
5906 This->cursorHeight = s->currentDesc.Height;
5907 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5909 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5910 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5911 struct wined3d_context *context;
5912 char *mem, *bits = rect.pBits;
5913 GLint intfmt = format->glInternal;
5914 GLint gl_format = format->glFormat;
5915 GLint type = format->glType;
5916 INT height = This->cursorHeight;
5917 INT width = This->cursorWidth;
5918 INT bpp = format->byte_count;
5922 /* Reformat the texture memory (pitch and width can be
5924 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5925 for(i = 0; i < height; i++)
5926 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5927 IWineD3DSurface_Unmap(cursor_image);
5929 context = context_acquire(This, NULL);
5933 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5935 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5936 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5939 /* Make sure that a proper texture unit is selected */
5940 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5941 checkGLcall("glActiveTextureARB");
5942 sampler = This->rev_tex_unit_map[0];
5943 if (sampler != WINED3D_UNMAPPED_STAGE)
5945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5947 /* Create a new cursor texture */
5948 glGenTextures(1, &This->cursorTexture);
5949 checkGLcall("glGenTextures");
5950 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5951 checkGLcall("glBindTexture");
5952 /* Copy the bitmap memory into the cursor texture */
5953 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5954 checkGLcall("glTexImage2D");
5955 HeapFree(GetProcessHeap(), 0, mem);
5957 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5959 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5960 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5965 context_release(context);
5969 FIXME("A cursor texture was not returned.\n");
5970 This->cursorTexture = 0;
5975 /* Draw a hardware cursor */
5976 ICONINFO cursorInfo;
5978 /* Create and clear maskBits because it is not needed for
5979 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5981 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5982 (s->currentDesc.Width * s->currentDesc.Height / 8));
5983 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5984 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5985 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5987 cursorInfo.fIcon = FALSE;
5988 cursorInfo.xHotspot = XHotSpot;
5989 cursorInfo.yHotspot = YHotSpot;
5990 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5991 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5992 IWineD3DSurface_Unmap(cursor_image);
5993 /* Create our cursor and clean up. */
5994 cursor = CreateIconIndirect(&cursorInfo);
5996 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5997 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5998 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5999 This->hardwareCursor = cursor;
6000 HeapFree(GetProcessHeap(), 0, maskBits);
6004 This->xHotSpot = XHotSpot;
6005 This->yHotSpot = YHotSpot;
6009 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6011 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6013 This->xScreenSpace = XScreenSpace;
6014 This->yScreenSpace = YScreenSpace;
6020 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6022 BOOL oldVisible = This->bCursorVisible;
6025 TRACE("(%p) : visible(%d)\n", This, bShow);
6028 * When ShowCursor is first called it should make the cursor appear at the OS's last
6029 * known cursor position. Because of this, some applications just repetitively call
6030 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6033 This->xScreenSpace = pt.x;
6034 This->yScreenSpace = pt.y;
6036 if (This->haveHardwareCursor) {
6037 This->bCursorVisible = bShow;
6039 SetCursor(This->hardwareCursor);
6045 if (This->cursorTexture)
6046 This->bCursorVisible = bShow;
6052 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6053 TRACE("checking resource %p for eviction\n", resource);
6054 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6055 TRACE("Evicting %p\n", resource);
6056 IWineD3DResource_UnLoad(resource);
6058 IWineD3DResource_Release(resource);
6062 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6064 TRACE("iface %p.\n", iface);
6066 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6067 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6068 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6073 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6075 IWineD3DDeviceImpl *device = surface->resource.device;
6076 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6078 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6079 if(surface->Flags & SFLAG_DIBSECTION) {
6080 /* Release the DC */
6081 SelectObject(surface->hDC, surface->dib.holdbitmap);
6082 DeleteDC(surface->hDC);
6083 /* Release the DIB section */
6084 DeleteObject(surface->dib.DIBsection);
6085 surface->dib.bitmap_data = NULL;
6086 surface->resource.allocatedMemory = NULL;
6087 surface->Flags &= ~SFLAG_DIBSECTION;
6089 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6090 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6091 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6092 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6094 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6095 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6097 surface->pow2Width = surface->pow2Height = 1;
6098 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6099 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6102 if (surface->texture_name)
6104 struct wined3d_context *context = context_acquire(device, NULL);
6106 glDeleteTextures(1, &surface->texture_name);
6108 context_release(context);
6109 surface->texture_name = 0;
6110 surface->Flags &= ~SFLAG_CLIENT;
6112 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6113 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6114 surface->Flags |= SFLAG_NONPOW2;
6116 surface->Flags &= ~SFLAG_NONPOW2;
6118 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6119 surface->resource.allocatedMemory = NULL;
6120 surface->resource.heapMemory = NULL;
6121 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6123 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6125 if (!surface_init_sysmem(surface))
6127 return E_OUTOFMEMORY;
6132 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6133 TRACE("Unloading resource %p\n", resource);
6134 IWineD3DResource_UnLoad(resource);
6135 IWineD3DResource_Release(resource);
6139 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6142 WINED3DDISPLAYMODE m;
6145 /* All Windowed modes are supported, as is leaving the current mode */
6146 if(pp->Windowed) return TRUE;
6147 if(!pp->BackBufferWidth) return TRUE;
6148 if(!pp->BackBufferHeight) return TRUE;
6150 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6151 for(i = 0; i < count; i++) {
6152 memset(&m, 0, sizeof(m));
6153 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6155 ERR("EnumAdapterModes failed\n");
6157 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6158 /* Mode found, it is supported */
6162 /* Mode not found -> not supported */
6166 /* Do not call while under the GL lock. */
6167 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6170 const struct wined3d_gl_info *gl_info;
6171 struct wined3d_context *context;
6172 IWineD3DBaseShaderImpl *shader;
6174 context = context_acquire(This, NULL);
6175 gl_info = context->gl_info;
6177 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6178 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6179 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6183 if(This->depth_blt_texture) {
6184 glDeleteTextures(1, &This->depth_blt_texture);
6185 This->depth_blt_texture = 0;
6187 if (This->depth_blt_rb) {
6188 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6189 This->depth_blt_rb = 0;
6190 This->depth_blt_rb_w = 0;
6191 This->depth_blt_rb_h = 0;
6195 This->blitter->free_private(iface);
6196 This->frag_pipe->free_private(iface);
6197 This->shader_backend->shader_free_private(iface);
6198 destroy_dummy_textures(This, gl_info);
6200 context_release(context);
6202 while (This->numContexts)
6204 context_destroy(This, This->contexts[0]);
6206 HeapFree(GetProcessHeap(), 0, swapchain->context);
6207 swapchain->context = NULL;
6208 swapchain->num_contexts = 0;
6211 /* Do not call while under the GL lock. */
6212 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6215 struct wined3d_context *context;
6217 IWineD3DSurfaceImpl *target;
6219 /* Recreate the primary swapchain's context */
6220 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6221 if (!swapchain->context)
6223 ERR("Failed to allocate memory for swapchain context array.\n");
6224 return E_OUTOFMEMORY;
6227 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6228 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6230 WARN("Failed to create context.\n");
6231 HeapFree(GetProcessHeap(), 0, swapchain->context);
6235 swapchain->context[0] = context;
6236 swapchain->num_contexts = 1;
6237 create_dummy_textures(This);
6238 context_release(context);
6240 hr = This->shader_backend->shader_alloc_private(iface);
6243 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6247 hr = This->frag_pipe->alloc_private(iface);
6250 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6251 This->shader_backend->shader_free_private(iface);
6255 hr = This->blitter->alloc_private(iface);
6258 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6259 This->frag_pipe->free_private(iface);
6260 This->shader_backend->shader_free_private(iface);
6267 context_acquire(This, NULL);
6268 destroy_dummy_textures(This, context->gl_info);
6269 context_release(context);
6270 context_destroy(This, context);
6271 HeapFree(GetProcessHeap(), 0, swapchain->context);
6272 swapchain->num_contexts = 0;
6276 /* Do not call while under the GL lock. */
6277 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6278 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6281 IWineD3DSwapChainImpl *swapchain;
6283 BOOL DisplayModeChanged = FALSE;
6284 WINED3DDISPLAYMODE mode;
6285 TRACE("(%p)\n", This);
6287 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6289 ERR("Failed to get the first implicit swapchain\n");
6293 if(!is_display_mode_supported(This, pPresentationParameters)) {
6294 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6295 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6296 pPresentationParameters->BackBufferHeight);
6297 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6298 return WINED3DERR_INVALIDCALL;
6301 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6302 * on an existing gl context, so there's no real need for recreation.
6304 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6306 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6308 TRACE("New params:\n");
6309 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6310 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6311 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6312 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6313 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6314 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6315 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6316 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6317 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6318 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6319 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6320 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6321 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6323 /* No special treatment of these parameters. Just store them */
6324 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6325 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6326 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6327 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6329 /* What to do about these? */
6330 if (pPresentationParameters->BackBufferCount
6331 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6332 ERR("Cannot change the back buffer count yet\n");
6334 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6335 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6336 ERR("Cannot change the back buffer format yet\n");
6339 if (pPresentationParameters->hDeviceWindow
6340 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6341 ERR("Cannot change the device window yet\n");
6343 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6347 TRACE("Creating the depth stencil buffer\n");
6349 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6350 pPresentationParameters->BackBufferWidth,
6351 pPresentationParameters->BackBufferHeight,
6352 pPresentationParameters->AutoDepthStencilFormat,
6353 pPresentationParameters->MultiSampleType,
6354 pPresentationParameters->MultiSampleQuality,
6356 (IWineD3DSurface **)&This->auto_depth_stencil);
6359 ERR("Failed to create the depth stencil buffer\n");
6360 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6361 return WINED3DERR_INVALIDCALL;
6365 if (This->onscreen_depth_stencil)
6367 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6368 This->onscreen_depth_stencil = NULL;
6371 /* Reset the depth stencil */
6372 if (pPresentationParameters->EnableAutoDepthStencil)
6373 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6375 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6377 TRACE("Resetting stateblock\n");
6378 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6379 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6381 delete_opengl_contexts(iface, swapchain);
6383 if(pPresentationParameters->Windowed) {
6384 mode.Width = swapchain->orig_width;
6385 mode.Height = swapchain->orig_height;
6386 mode.RefreshRate = 0;
6387 mode.Format = swapchain->presentParms.BackBufferFormat;
6389 mode.Width = pPresentationParameters->BackBufferWidth;
6390 mode.Height = pPresentationParameters->BackBufferHeight;
6391 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6392 mode.Format = swapchain->presentParms.BackBufferFormat;
6395 /* Should Width == 800 && Height == 0 set 800x600? */
6396 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6397 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6398 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6402 if(!pPresentationParameters->Windowed) {
6403 DisplayModeChanged = TRUE;
6405 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6406 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6408 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6411 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6415 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6417 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6420 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6424 if (This->auto_depth_stencil)
6426 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6429 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6435 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6436 || DisplayModeChanged)
6438 BOOL filter = This->filter_messages;
6439 This->filter_messages = TRUE;
6441 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6443 if (!pPresentationParameters->Windowed)
6445 if (swapchain->presentParms.Windowed)
6447 HWND focus_window = This->createParms.hFocusWindow;
6448 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6449 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6451 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6452 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6456 /* switch from windowed to fs */
6457 device_setup_fullscreen_window(This, swapchain->device_window,
6458 pPresentationParameters->BackBufferWidth,
6459 pPresentationParameters->BackBufferHeight);
6463 /* Fullscreen -> fullscreen mode change */
6464 MoveWindow(swapchain->device_window, 0, 0,
6465 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6469 else if (!swapchain->presentParms.Windowed)
6471 /* Fullscreen -> windowed switch */
6472 device_restore_fullscreen_window(This, swapchain->device_window);
6473 IWineD3DDevice_ReleaseFocusWindow(iface);
6475 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6477 This->filter_messages = filter;
6479 else if (!pPresentationParameters->Windowed)
6481 DWORD style = This->style, exStyle = This->exStyle;
6482 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6483 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6484 * Reset to clear up their mess. Guild Wars also loses the device during that.
6488 device_setup_fullscreen_window(This, swapchain->device_window,
6489 pPresentationParameters->BackBufferWidth,
6490 pPresentationParameters->BackBufferHeight);
6491 This->style = style;
6492 This->exStyle = exStyle;
6495 /* Note: No parent needed for initial internal stateblock */
6496 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6497 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6498 else TRACE("Created stateblock %p\n", This->stateBlock);
6499 This->updateStateBlock = This->stateBlock;
6500 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6502 stateblock_init_default_state(This->stateBlock);
6504 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6507 GetClientRect(swapchain->win_handle, &client_rect);
6509 if(!swapchain->presentParms.BackBufferCount)
6511 TRACE("Single buffered rendering\n");
6512 swapchain->render_to_fbo = FALSE;
6514 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6515 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6517 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6518 swapchain->presentParms.BackBufferWidth,
6519 swapchain->presentParms.BackBufferHeight,
6520 client_rect.right, client_rect.bottom);
6521 swapchain->render_to_fbo = TRUE;
6525 TRACE("Rendering directly to GL_BACK\n");
6526 swapchain->render_to_fbo = FALSE;
6530 hr = create_primary_opengl_context(iface, swapchain);
6531 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6533 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6539 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6541 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6543 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6549 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6551 TRACE("(%p) : pParameters %p\n", This, pParameters);
6553 *pParameters = This->createParms;
6557 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6558 IWineD3DSwapChain *swapchain;
6560 TRACE("Relaying to swapchain\n");
6562 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6563 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6564 IWineD3DSwapChain_Release(swapchain);
6568 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6569 IWineD3DSwapChain *swapchain;
6571 TRACE("Relaying to swapchain\n");
6573 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6574 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6575 IWineD3DSwapChain_Release(swapchain);
6580 /** ********************************************************
6581 * Notification functions
6582 ** ********************************************************/
6583 /** This function must be called in the release of a resource when ref == 0,
6584 * the contents of resource must still be correct,
6585 * any handles to other resource held by the caller must be closed
6586 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6587 *****************************************************/
6588 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6590 TRACE("(%p) : Adding resource %p\n", This, resource);
6592 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6595 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6597 TRACE("(%p) : Removing resource %p\n", This, resource);
6599 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6602 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6604 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6607 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6609 context_resource_released(device, resource, type);
6613 case WINED3DRTYPE_SURFACE:
6614 if (!device->d3d_initialized) break;
6616 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6618 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6620 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6621 device->render_targets[i] = NULL;
6625 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6627 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6628 device->depth_stencil = NULL;
6632 case WINED3DRTYPE_TEXTURE:
6633 case WINED3DRTYPE_CUBETEXTURE:
6634 case WINED3DRTYPE_VOLUMETEXTURE:
6635 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6637 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6639 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6640 resource, device->stateBlock, i);
6641 device->stateBlock->state.textures[i] = NULL;
6644 if (device->updateStateBlock != device->stateBlock
6645 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6647 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6648 resource, device->updateStateBlock, i);
6649 device->updateStateBlock->state.textures[i] = NULL;
6654 case WINED3DRTYPE_BUFFER:
6655 for (i = 0; i < MAX_STREAMS; ++i)
6657 if (device->stateBlock
6658 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6660 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6661 resource, device->stateBlock, i);
6662 device->stateBlock->state.streams[i].buffer = NULL;
6665 if (device->updateStateBlock != device->stateBlock
6666 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6668 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6669 resource, device->updateStateBlock, i);
6670 device->updateStateBlock->state.streams[i].buffer = NULL;
6675 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6677 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6678 resource, device->stateBlock);
6679 device->stateBlock->state.index_buffer = NULL;
6682 if (device->updateStateBlock != device->stateBlock
6683 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6685 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6686 resource, device->updateStateBlock);
6687 device->updateStateBlock->state.index_buffer = NULL;
6695 /* Remove the resource from the resourceStore */
6696 device_resource_remove(device, resource);
6698 TRACE("Resource released.\n");
6701 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6703 IWineD3DResourceImpl *resource, *cursor;
6705 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6707 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6708 TRACE("enumerating resource %p\n", resource);
6709 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6710 ret = pCallback((IWineD3DResource *) resource, pData);
6711 if(ret == S_FALSE) {
6712 TRACE("Canceling enumeration\n");
6719 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6722 IWineD3DResourceImpl *resource;
6724 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6726 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6727 if (type == WINED3DRTYPE_SURFACE)
6729 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6731 TRACE("Found surface %p for dc %p.\n", resource, dc);
6732 *surface = (IWineD3DSurface *)resource;
6738 return WINED3DERR_INVALIDCALL;
6741 /**********************************************************
6742 * IWineD3DDevice VTbl follows
6743 **********************************************************/
6745 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6747 /*** IUnknown methods ***/
6748 IWineD3DDeviceImpl_QueryInterface,
6749 IWineD3DDeviceImpl_AddRef,
6750 IWineD3DDeviceImpl_Release,
6751 /*** IWineD3DDevice methods ***/
6752 /*** Creation methods**/
6753 IWineD3DDeviceImpl_CreateBuffer,
6754 IWineD3DDeviceImpl_CreateVertexBuffer,
6755 IWineD3DDeviceImpl_CreateIndexBuffer,
6756 IWineD3DDeviceImpl_CreateStateBlock,
6757 IWineD3DDeviceImpl_CreateSurface,
6758 IWineD3DDeviceImpl_CreateRendertargetView,
6759 IWineD3DDeviceImpl_CreateTexture,
6760 IWineD3DDeviceImpl_CreateVolumeTexture,
6761 IWineD3DDeviceImpl_CreateVolume,
6762 IWineD3DDeviceImpl_CreateCubeTexture,
6763 IWineD3DDeviceImpl_CreateQuery,
6764 IWineD3DDeviceImpl_CreateSwapChain,
6765 IWineD3DDeviceImpl_CreateVertexDeclaration,
6766 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6767 IWineD3DDeviceImpl_CreateVertexShader,
6768 IWineD3DDeviceImpl_CreateGeometryShader,
6769 IWineD3DDeviceImpl_CreatePixelShader,
6770 IWineD3DDeviceImpl_CreatePalette,
6771 /*** Odd functions **/
6772 IWineD3DDeviceImpl_Init3D,
6773 IWineD3DDeviceImpl_InitGDI,
6774 IWineD3DDeviceImpl_Uninit3D,
6775 IWineD3DDeviceImpl_UninitGDI,
6776 IWineD3DDeviceImpl_SetMultithreaded,
6777 IWineD3DDeviceImpl_EvictManagedResources,
6778 IWineD3DDeviceImpl_GetAvailableTextureMem,
6779 IWineD3DDeviceImpl_GetBackBuffer,
6780 IWineD3DDeviceImpl_GetCreationParameters,
6781 IWineD3DDeviceImpl_GetDeviceCaps,
6782 IWineD3DDeviceImpl_GetDirect3D,
6783 IWineD3DDeviceImpl_GetDisplayMode,
6784 IWineD3DDeviceImpl_SetDisplayMode,
6785 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6786 IWineD3DDeviceImpl_GetRasterStatus,
6787 IWineD3DDeviceImpl_GetSwapChain,
6788 IWineD3DDeviceImpl_Reset,
6789 IWineD3DDeviceImpl_SetDialogBoxMode,
6790 IWineD3DDeviceImpl_SetCursorProperties,
6791 IWineD3DDeviceImpl_SetCursorPosition,
6792 IWineD3DDeviceImpl_ShowCursor,
6793 /*** Getters and setters **/
6794 IWineD3DDeviceImpl_SetClipPlane,
6795 IWineD3DDeviceImpl_GetClipPlane,
6796 IWineD3DDeviceImpl_SetClipStatus,
6797 IWineD3DDeviceImpl_GetClipStatus,
6798 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6799 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6800 IWineD3DDeviceImpl_SetDepthStencilSurface,
6801 IWineD3DDeviceImpl_GetDepthStencilSurface,
6802 IWineD3DDeviceImpl_SetGammaRamp,
6803 IWineD3DDeviceImpl_GetGammaRamp,
6804 IWineD3DDeviceImpl_SetIndexBuffer,
6805 IWineD3DDeviceImpl_GetIndexBuffer,
6806 IWineD3DDeviceImpl_SetBaseVertexIndex,
6807 IWineD3DDeviceImpl_GetBaseVertexIndex,
6808 IWineD3DDeviceImpl_SetLight,
6809 IWineD3DDeviceImpl_GetLight,
6810 IWineD3DDeviceImpl_SetLightEnable,
6811 IWineD3DDeviceImpl_GetLightEnable,
6812 IWineD3DDeviceImpl_SetMaterial,
6813 IWineD3DDeviceImpl_GetMaterial,
6814 IWineD3DDeviceImpl_SetNPatchMode,
6815 IWineD3DDeviceImpl_GetNPatchMode,
6816 IWineD3DDeviceImpl_SetPaletteEntries,
6817 IWineD3DDeviceImpl_GetPaletteEntries,
6818 IWineD3DDeviceImpl_SetPixelShader,
6819 IWineD3DDeviceImpl_GetPixelShader,
6820 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6821 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6822 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6823 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6824 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6825 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6826 IWineD3DDeviceImpl_SetRenderState,
6827 IWineD3DDeviceImpl_GetRenderState,
6828 IWineD3DDeviceImpl_SetRenderTarget,
6829 IWineD3DDeviceImpl_GetRenderTarget,
6830 IWineD3DDeviceImpl_SetSamplerState,
6831 IWineD3DDeviceImpl_GetSamplerState,
6832 IWineD3DDeviceImpl_SetScissorRect,
6833 IWineD3DDeviceImpl_GetScissorRect,
6834 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6835 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6836 IWineD3DDeviceImpl_SetStreamSource,
6837 IWineD3DDeviceImpl_GetStreamSource,
6838 IWineD3DDeviceImpl_SetStreamSourceFreq,
6839 IWineD3DDeviceImpl_GetStreamSourceFreq,
6840 IWineD3DDeviceImpl_SetTexture,
6841 IWineD3DDeviceImpl_GetTexture,
6842 IWineD3DDeviceImpl_SetTextureStageState,
6843 IWineD3DDeviceImpl_GetTextureStageState,
6844 IWineD3DDeviceImpl_SetTransform,
6845 IWineD3DDeviceImpl_GetTransform,
6846 IWineD3DDeviceImpl_SetVertexDeclaration,
6847 IWineD3DDeviceImpl_GetVertexDeclaration,
6848 IWineD3DDeviceImpl_SetVertexShader,
6849 IWineD3DDeviceImpl_GetVertexShader,
6850 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6851 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6852 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6853 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6854 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6855 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6856 IWineD3DDeviceImpl_SetViewport,
6857 IWineD3DDeviceImpl_GetViewport,
6858 IWineD3DDeviceImpl_MultiplyTransform,
6859 IWineD3DDeviceImpl_ValidateDevice,
6860 IWineD3DDeviceImpl_ProcessVertices,
6861 /*** State block ***/
6862 IWineD3DDeviceImpl_BeginStateBlock,
6863 IWineD3DDeviceImpl_EndStateBlock,
6864 /*** Scene management ***/
6865 IWineD3DDeviceImpl_BeginScene,
6866 IWineD3DDeviceImpl_EndScene,
6867 IWineD3DDeviceImpl_Present,
6868 IWineD3DDeviceImpl_Clear,
6869 IWineD3DDeviceImpl_ClearRendertargetView,
6871 IWineD3DDeviceImpl_SetPrimitiveType,
6872 IWineD3DDeviceImpl_GetPrimitiveType,
6873 IWineD3DDeviceImpl_DrawPrimitive,
6874 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6875 IWineD3DDeviceImpl_DrawPrimitiveUP,
6876 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6877 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6878 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6879 IWineD3DDeviceImpl_DrawRectPatch,
6880 IWineD3DDeviceImpl_DrawTriPatch,
6881 IWineD3DDeviceImpl_DeletePatch,
6882 IWineD3DDeviceImpl_ColorFill,
6883 IWineD3DDeviceImpl_UpdateTexture,
6884 IWineD3DDeviceImpl_UpdateSurface,
6885 IWineD3DDeviceImpl_GetFrontBufferData,
6886 /*** object tracking ***/
6887 IWineD3DDeviceImpl_EnumResources,
6888 IWineD3DDeviceImpl_GetSurfaceFromDC,
6889 IWineD3DDeviceImpl_AcquireFocusWindow,
6890 IWineD3DDeviceImpl_ReleaseFocusWindow,
6893 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6894 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6895 IWineD3DDeviceParent *device_parent)
6897 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6898 const struct fragment_pipeline *fragment_pipeline;
6899 struct shader_caps shader_caps;
6900 struct fragment_caps ffp_caps;
6901 WINED3DDISPLAYMODE mode;
6905 device->lpVtbl = &IWineD3DDevice_Vtbl;
6907 device->wined3d = (IWineD3D *)wined3d;
6908 IWineD3D_AddRef(device->wined3d);
6909 device->adapter = wined3d->adapter_count ? adapter : NULL;
6910 device->device_parent = device_parent;
6911 list_init(&device->resources);
6912 list_init(&device->shaders);
6914 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6916 /* Get the initial screen setup for ddraw. */
6917 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6920 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6921 IWineD3D_Release(device->wined3d);
6924 device->ddraw_width = mode.Width;
6925 device->ddraw_height = mode.Height;
6926 device->ddraw_format = mode.Format;
6928 /* Save the creation parameters. */
6929 device->createParms.AdapterOrdinal = adapter_idx;
6930 device->createParms.DeviceType = device_type;
6931 device->createParms.hFocusWindow = focus_window;
6932 device->createParms.BehaviorFlags = flags;
6934 device->devType = device_type;
6935 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6937 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6938 device->shader_backend = adapter->shader_backend;
6940 if (device->shader_backend)
6942 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6943 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6944 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6945 device->vs_clipping = shader_caps.VSClipping;
6947 fragment_pipeline = adapter->fragment_pipe;
6948 device->frag_pipe = fragment_pipeline;
6949 if (fragment_pipeline)
6951 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6952 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6954 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6955 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6958 ERR("Failed to compile state table, hr %#x.\n", hr);
6959 IWineD3D_Release(device->wined3d);
6963 device->blitter = adapter->blitter;
6969 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6970 DWORD rep = This->StateTable[state].representative;
6971 struct wined3d_context *context;
6976 for(i = 0; i < This->numContexts; i++) {
6977 context = This->contexts[i];
6978 if(isStateDirty(context, rep)) continue;
6980 context->dirtyArray[context->numDirtyEntries++] = rep;
6981 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6982 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6983 context->isStateDirty[idx] |= (1 << shift);
6987 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6989 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6990 *width = context->current_rt->pow2Width;
6991 *height = context->current_rt->pow2Height;
6994 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6996 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6997 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6998 * current context's drawable, which is the size of the back buffer of the swapchain
6999 * the active context belongs to. */
7000 *width = swapchain->presentParms.BackBufferWidth;
7001 *height = swapchain->presentParms.BackBufferHeight;
7004 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7005 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7007 if (device->filter_messages)
7009 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7010 window, message, wparam, lparam);
7012 return DefWindowProcW(window, message, wparam, lparam);
7014 return DefWindowProcA(window, message, wparam, lparam);
7017 if (message == WM_DESTROY)
7019 TRACE("unregister window %p.\n", window);
7020 wined3d_unregister_window(window);
7022 if (device->focus_window == window) device->focus_window = NULL;
7023 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7027 return CallWindowProcW(proc, window, message, wparam, lparam);
7029 return CallWindowProcA(proc, window, message, wparam, lparam);