2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009-2010 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
211 data = (BYTE *)buffer;
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory(buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
436 device->useDrawStridedSlow = FALSE;
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.texture_ops->texture_preload(texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 struct wined3d_stateblock *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 if (!context_apply_clear_state(context, device, rt_count, rts, depth_stencil))
691 context_release(context);
692 WARN("Failed to apply clear state, skipping clear.\n");
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(¤t_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 IWineD3DResourceImpl *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
875 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource, debug_d3dresourcetype(type), type);
881 if(This->contexts) ERR("Context array not freed!\n");
882 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
883 This->haveHardwareCursor = FALSE;
885 IWineD3D_Release(This->wined3d);
886 This->wined3d = NULL;
887 HeapFree(GetProcessHeap(), 0, This);
888 TRACE("Freed device %p\n", This);
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
895 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 struct wined3d_buffer *object;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY;
910 FIXME("Ignoring access flags (pool)\n");
912 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
913 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
916 WARN("Failed to initialize buffer, hr %#x.\n", hr);
917 HeapFree(GetProcessHeap(), 0, object);
920 object->desc = *desc;
922 TRACE("Created buffer %p.\n", object);
924 *buffer = (IWineD3DBuffer *)object;
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
930 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
931 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 struct wined3d_buffer *object;
937 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
938 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
940 if (Pool == WINED3DPOOL_SCRATCH)
942 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
943 * anyway, SCRATCH vertex buffers aren't usable anywhere
945 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 *ppVertexBuffer = NULL;
947 return WINED3DERR_INVALIDCALL;
950 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
953 ERR("Out of memory\n");
954 *ppVertexBuffer = NULL;
955 return WINED3DERR_OUTOFVIDEOMEMORY;
958 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
959 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
962 WARN("Failed to initialize buffer, hr %#x.\n", hr);
963 HeapFree(GetProcessHeap(), 0, object);
967 TRACE("Created buffer %p.\n", object);
968 *ppVertexBuffer = (IWineD3DBuffer *)object;
973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
974 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
975 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
978 struct wined3d_buffer *object;
981 TRACE("(%p) Creating index buffer\n", This);
983 /* Allocate the storage for the device */
984 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
987 ERR("Out of memory\n");
988 *ppIndexBuffer = NULL;
989 return WINED3DERR_OUTOFVIDEOMEMORY;
992 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
993 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
997 WARN("Failed to initialize buffer, hr %#x\n", hr);
998 HeapFree(GetProcessHeap(), 0, object);
1002 TRACE("Created buffer %p.\n", object);
1004 *ppIndexBuffer = (IWineD3DBuffer *) object;
1009 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1010 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 struct wined3d_stateblock *object;
1016 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1019 ERR("Failed to allocate stateblock memory.\n");
1020 return E_OUTOFMEMORY;
1023 hr = stateblock_init(object, This, type);
1026 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1027 HeapFree(GetProcessHeap(), 0, object);
1031 TRACE("Created stateblock %p.\n", object);
1032 *stateblock = object;
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1038 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1039 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1040 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1043 IWineD3DSurfaceImpl *object;
1046 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1047 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1048 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1049 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1050 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1052 if (Impl == SURFACE_OPENGL && !This->adapter)
1054 ERR("OpenGL surfaces are not available without OpenGL.\n");
1055 return WINED3DERR_NOTAVAILABLE;
1058 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1061 ERR("Failed to allocate surface memory.\n");
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1066 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1069 WARN("Failed to initialize surface, returning %#x.\n", hr);
1070 HeapFree(GetProcessHeap(), 0, object);
1074 TRACE("(%p) : Created surface %p\n", This, object);
1076 *surface = (IWineD3DSurface *)object;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1082 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1084 struct wined3d_rendertarget_view *object;
1086 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1087 iface, resource, parent, rendertarget_view);
1089 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1092 ERR("Failed to allocate memory\n");
1093 return E_OUTOFMEMORY;
1096 wined3d_rendertarget_view_init(object, (IWineD3DResourceImpl *)resource, parent);
1098 TRACE("Created render target view %p.\n", object);
1099 *rendertarget_view = (IWineD3DRendertargetView *)object;
1104 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1105 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1106 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1112 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1113 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1114 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1116 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1119 ERR("Out of memory\n");
1121 return WINED3DERR_OUTOFVIDEOMEMORY;
1124 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1127 WARN("Failed to initialize texture, returning %#x\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1133 *ppTexture = (IWineD3DTexture *)object;
1135 TRACE("(%p) : Created texture %p\n", This, object);
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1141 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1142 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DVolumeTextureImpl *object;
1148 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1149 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1151 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1154 ERR("Out of memory\n");
1155 *ppVolumeTexture = NULL;
1156 return WINED3DERR_OUTOFVIDEOMEMORY;
1159 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1162 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1163 HeapFree(GetProcessHeap(), 0, object);
1164 *ppVolumeTexture = NULL;
1168 TRACE("(%p) : Created volume texture %p.\n", This, object);
1169 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1175 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1176 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 IWineD3DVolumeImpl *object;
1182 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1183 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1185 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1188 ERR("Out of memory\n");
1190 return WINED3DERR_OUTOFVIDEOMEMORY;
1193 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1196 WARN("Failed to initialize volume, returning %#x.\n", hr);
1197 HeapFree(GetProcessHeap(), 0, object);
1201 TRACE("(%p) : Created volume %p.\n", This, object);
1202 *ppVolume = (IWineD3DVolume *)object;
1207 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1208 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1209 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1212 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1215 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1218 ERR("Out of memory\n");
1219 *ppCubeTexture = NULL;
1220 return WINED3DERR_OUTOFVIDEOMEMORY;
1223 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1226 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1227 HeapFree(GetProcessHeap(), 0, object);
1228 *ppCubeTexture = NULL;
1232 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1233 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1239 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1242 IWineD3DQueryImpl *object;
1245 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1247 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1250 ERR("Failed to allocate query memory.\n");
1251 return E_OUTOFMEMORY;
1254 hr = query_init(object, This, type);
1257 WARN("Failed to initialize query, hr %#x.\n", hr);
1258 HeapFree(GetProcessHeap(), 0, object);
1262 TRACE("Created query %p.\n", object);
1263 *query = (IWineD3DQuery *)object;
1268 /* Do not call while under the GL lock. */
1269 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1270 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1271 void *parent, IWineD3DSwapChain **swapchain)
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DSwapChainImpl *object;
1277 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1278 iface, present_parameters, swapchain, parent, surface_type);
1280 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1283 ERR("Failed to allocate swapchain memory.\n");
1284 return E_OUTOFMEMORY;
1287 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1290 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1291 HeapFree(GetProcessHeap(), 0, object);
1295 TRACE("Created swapchain %p.\n", object);
1296 *swapchain = (IWineD3DSwapChain *)object;
1301 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1302 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 TRACE("(%p)\n", This);
1306 return This->NumberOfSwapChains;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1311 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1313 if (iSwapChain < This->NumberOfSwapChains)
1315 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1316 IWineD3DSwapChain_AddRef(*pSwapChain);
1317 TRACE("(%p) returning %p\n", This, *pSwapChain);
1320 TRACE("Swapchain out of range\n");
1322 return WINED3DERR_INVALIDCALL;
1326 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1327 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1328 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1331 IWineD3DVertexDeclarationImpl *object = NULL;
1334 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1335 iface, declaration, parent, elements, element_count);
1337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1340 ERR("Failed to allocate vertex declaration memory.\n");
1341 return E_OUTOFMEMORY;
1344 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1347 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1348 HeapFree(GetProcessHeap(), 0, object);
1352 TRACE("Created vertex declaration %p.\n", object);
1353 *declaration = (IWineD3DVertexDeclaration *)object;
1358 struct wined3d_fvf_convert_state
1360 const struct wined3d_gl_info *gl_info;
1361 WINED3DVERTEXELEMENT *elements;
1366 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1367 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1369 WINED3DVERTEXELEMENT *elements = state->elements;
1370 const struct wined3d_format *format;
1371 UINT offset = state->offset;
1372 UINT idx = state->idx;
1374 elements[idx].format = format_id;
1375 elements[idx].input_slot = 0;
1376 elements[idx].offset = offset;
1377 elements[idx].output_slot = 0;
1378 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1379 elements[idx].usage = usage;
1380 elements[idx].usage_idx = usage_idx;
1382 format = wined3d_get_format(state->gl_info, format_id);
1383 state->offset += format->component_count * format->component_size;
1387 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1388 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1390 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1391 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1392 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1393 BOOL has_blend_idx = has_blend &&
1394 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1395 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1396 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1397 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1398 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1399 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1400 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1402 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1403 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1404 struct wined3d_fvf_convert_state state;
1407 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1408 if (has_blend_idx) num_blends--;
1410 /* Compute declaration size */
1411 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1412 has_psize + has_diffuse + has_specular + num_textures;
1414 state.gl_info = gl_info;
1415 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1416 if (!state.elements) return ~0U;
1422 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1424 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1425 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1427 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1430 if (has_blend && (num_blends > 0))
1432 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1433 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1439 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1448 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1451 ERR("Unexpected amount of blend values: %u\n", num_blends);
1458 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1459 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1460 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1462 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1464 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1467 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1468 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1469 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1470 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1472 for (idx = 0; idx < num_textures; ++idx)
1474 switch ((texcoords >> (idx * 2)) & 0x03)
1476 case WINED3DFVF_TEXTUREFORMAT1:
1477 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 case WINED3DFVF_TEXTUREFORMAT2:
1480 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 case WINED3DFVF_TEXTUREFORMAT3:
1483 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 case WINED3DFVF_TEXTUREFORMAT4:
1486 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1491 *ppVertexElements = state.elements;
1495 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1496 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1497 IWineD3DVertexDeclaration **declaration)
1499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1500 WINED3DVERTEXELEMENT *elements;
1504 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1506 size = ConvertFvfToDeclaration(This, fvf, &elements);
1507 if (size == ~0U) return E_OUTOFMEMORY;
1509 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1510 HeapFree(GetProcessHeap(), 0, elements);
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1515 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1516 void *parent, const struct wined3d_parent_ops *parent_ops,
1517 IWineD3DVertexShader **ppVertexShader)
1519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1520 IWineD3DVertexShaderImpl *object;
1523 if (This->vs_selected_mode == SHADER_NONE)
1524 return WINED3DERR_INVALIDCALL;
1526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1529 ERR("Failed to allocate shader memory.\n");
1530 return E_OUTOFMEMORY;
1533 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1536 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1537 HeapFree(GetProcessHeap(), 0, object);
1541 TRACE("Created vertex shader %p.\n", object);
1542 *ppVertexShader = (IWineD3DVertexShader *)object;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1548 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1549 void *parent, const struct wined3d_parent_ops *parent_ops,
1550 IWineD3DGeometryShader **shader)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 struct wined3d_geometryshader *object;
1556 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1559 ERR("Failed to allocate shader memory.\n");
1560 return E_OUTOFMEMORY;
1563 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1566 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1567 HeapFree(GetProcessHeap(), 0, object);
1571 TRACE("Created geometry shader %p.\n", object);
1572 *shader = (IWineD3DGeometryShader *)object;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1578 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1579 void *parent, const struct wined3d_parent_ops *parent_ops,
1580 IWineD3DPixelShader **ppPixelShader)
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 IWineD3DPixelShaderImpl *object;
1586 if (This->ps_selected_mode == SHADER_NONE)
1587 return WINED3DERR_INVALIDCALL;
1589 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1592 ERR("Failed to allocate shader memory.\n");
1593 return E_OUTOFMEMORY;
1596 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1599 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1600 HeapFree(GetProcessHeap(), 0, object);
1604 TRACE("Created pixel shader %p.\n", object);
1605 *ppPixelShader = (IWineD3DPixelShader *)object;
1610 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1611 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1614 IWineD3DPaletteImpl *object;
1617 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1618 iface, flags, PalEnt, Palette, parent);
1620 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1623 ERR("Failed to allocate palette memory.\n");
1624 return E_OUTOFMEMORY;
1627 hr = wined3d_palette_init(object, This, flags, PalEnt, parent);
1630 WARN("Failed to initialize palette, hr %#x.\n", hr);
1631 HeapFree(GetProcessHeap(), 0, object);
1635 TRACE("Created palette %p.\n", object);
1636 *Palette = (IWineD3DPalette *)object;
1641 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1645 HDC dcb = NULL, dcs = NULL;
1646 WINEDDCOLORKEY colorkey;
1648 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1651 GetObjectA(hbm, sizeof(BITMAP), &bm);
1652 dcb = CreateCompatibleDC(NULL);
1654 SelectObject(dcb, hbm);
1658 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1659 * couldn't be loaded
1661 memset(&bm, 0, sizeof(bm));
1666 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1667 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1668 &wined3d_null_parent_ops, &This->logo_surface);
1671 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1676 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1677 if(FAILED(hr)) goto out;
1678 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1679 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1681 colorkey.dwColorSpaceLowValue = 0;
1682 colorkey.dwColorSpaceHighValue = 0;
1683 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1687 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1688 /* Fill the surface with a white color to show that wined3d is there */
1689 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1693 if (dcb) DeleteDC(dcb);
1694 if (hbm) DeleteObject(hbm);
1697 /* Context activation is done by the caller. */
1698 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1700 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1702 /* Under DirectX you can have texture stage operations even if no texture is
1703 bound, whereas opengl will only do texture operations when a valid texture is
1704 bound. We emulate this by creating dummy textures and binding them to each
1705 texture stage, but disable all stages by default. Hence if a stage is enabled
1706 then the default texture will kick in until replaced by a SetTexture call */
1709 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1711 /* The dummy texture does not have client storage backing */
1712 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1713 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1716 for (i = 0; i < gl_info->limits.textures; ++i)
1718 GLubyte white = 255;
1720 /* Make appropriate texture active */
1721 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1722 checkGLcall("glActiveTextureARB");
1724 /* Generate an opengl texture name */
1725 glGenTextures(1, &This->dummyTextureName[i]);
1726 checkGLcall("glGenTextures");
1727 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1729 /* Generate a dummy 2d texture (not using 1d because they cause many
1730 * DRI drivers fall back to sw) */
1731 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1732 checkGLcall("glBindTexture");
1734 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1735 checkGLcall("glTexImage2D");
1738 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1740 /* Reenable because if supported it is enabled by default */
1741 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1742 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1748 /* Context activation is done by the caller. */
1749 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1752 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1753 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1756 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1759 static LONG fullscreen_style(LONG style)
1761 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1762 style |= WS_POPUP | WS_SYSMENU;
1763 style &= ~(WS_CAPTION | WS_THICKFRAME);
1768 static LONG fullscreen_exstyle(LONG exstyle)
1770 /* Filter out window decorations. */
1771 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1776 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1778 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1779 BOOL filter_messages;
1780 LONG style, exstyle;
1782 TRACE("Setting up window %p for fullscreen mode.\n", window);
1784 if (device->style || device->exStyle)
1786 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1787 window, device->style, device->exStyle);
1790 device->style = GetWindowLongW(window, GWL_STYLE);
1791 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1793 style = fullscreen_style(device->style);
1794 exstyle = fullscreen_exstyle(device->exStyle);
1796 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1797 device->style, device->exStyle, style, exstyle);
1799 filter_messages = device->filter_messages;
1800 device->filter_messages = TRUE;
1802 SetWindowLongW(window, GWL_STYLE, style);
1803 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1804 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1806 device->filter_messages = filter_messages;
1809 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1811 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1812 BOOL filter_messages;
1813 LONG style, exstyle;
1815 if (!device->style && !device->exStyle) return;
1817 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1818 window, device->style, device->exStyle);
1820 style = GetWindowLongW(window, GWL_STYLE);
1821 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1823 filter_messages = device->filter_messages;
1824 device->filter_messages = TRUE;
1826 /* Only restore the style if the application didn't modify it during the
1827 * fullscreen phase. Some applications change it before calling Reset()
1828 * when switching between windowed and fullscreen modes (HL2), some
1829 * depend on the original style (Eve Online). */
1830 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1832 SetWindowLongW(window, GWL_STYLE, device->style);
1833 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1835 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1837 device->filter_messages = filter_messages;
1839 /* Delete the old values. */
1841 device->exStyle = 0;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1846 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1848 TRACE("iface %p, window %p.\n", iface, window);
1850 if (!wined3d_register_window(window, device))
1852 ERR("Failed to register window %p.\n", window);
1856 device->focus_window = window;
1857 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1862 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1864 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1866 TRACE("iface %p.\n", iface);
1868 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1869 device->focus_window = NULL;
1872 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1873 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1876 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1877 IWineD3DSwapChainImpl *swapchain = NULL;
1878 struct wined3d_context *context;
1883 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1885 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1886 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1888 TRACE("(%p) : Creating stateblock\n", This);
1889 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1892 WARN("Failed to create stateblock\n");
1895 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1896 This->updateStateBlock = This->stateBlock;
1897 wined3d_stateblock_incref(This->updateStateBlock);
1899 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1900 sizeof(*This->render_targets) * gl_info->limits.buffers);
1902 This->NumberOfPalettes = 1;
1903 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1904 if (!This->palettes || !This->render_targets)
1906 ERR("Out of memory!\n");
1910 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1911 if(!This->palettes[0]) {
1912 ERR("Out of memory!\n");
1916 for (i = 0; i < 256; ++i) {
1917 This->palettes[0][i].peRed = 0xFF;
1918 This->palettes[0][i].peGreen = 0xFF;
1919 This->palettes[0][i].peBlue = 0xFF;
1920 This->palettes[0][i].peFlags = 0xFF;
1922 This->currentPalette = 0;
1924 /* Initialize the texture unit mapping to a 1:1 mapping */
1925 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1927 if (state < gl_info->limits.fragment_samplers)
1929 This->texUnitMap[state] = state;
1930 This->rev_tex_unit_map[state] = state;
1932 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1933 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1937 /* Setup the implicit swapchain. This also initializes a context. */
1938 TRACE("Creating implicit swapchain\n");
1939 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1940 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1943 WARN("Failed to create implicit swapchain\n");
1947 This->NumberOfSwapChains = 1;
1948 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1949 if (!This->swapchains)
1951 ERR("Out of memory!\n");
1954 This->swapchains[0] = swapchain;
1956 if (swapchain->back_buffers && swapchain->back_buffers[0])
1958 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1959 This->render_targets[0] = swapchain->back_buffers[0];
1963 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1964 This->render_targets[0] = swapchain->front_buffer;
1966 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1968 /* Depth Stencil support */
1969 This->depth_stencil = This->auto_depth_stencil;
1970 if (This->depth_stencil)
1971 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1973 hr = This->shader_backend->shader_alloc_private(This);
1975 TRACE("Shader private data couldn't be allocated\n");
1978 hr = This->frag_pipe->alloc_private(This);
1980 TRACE("Fragment pipeline private data couldn't be allocated\n");
1983 hr = This->blitter->alloc_private(This);
1985 TRACE("Blitter private data couldn't be allocated\n");
1989 /* Set up some starting GL setup */
1991 /* Setup all the devices defaults */
1992 stateblock_init_default_state(This->stateBlock);
1994 context = context_acquire(This, swapchain->front_buffer);
1996 create_dummy_textures(This);
2000 /* Initialize the current view state */
2001 This->view_ident = 1;
2002 This->contexts[0]->last_was_rhw = 0;
2003 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2004 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2006 switch(wined3d_settings.offscreen_rendering_mode) {
2008 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2011 case ORM_BACKBUFFER:
2013 if (context_get_current()->aux_buffers > 0)
2015 TRACE("Using auxilliary buffer for offscreen rendering\n");
2016 This->offscreenBuffer = GL_AUX0;
2018 TRACE("Using back buffer for offscreen rendering\n");
2019 This->offscreenBuffer = GL_BACK;
2024 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2027 context_release(context);
2029 /* Clear the screen */
2030 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2031 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2034 This->d3d_initialized = TRUE;
2036 if(wined3d_settings.logo) {
2037 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2039 This->highest_dirty_ps_const = 0;
2040 This->highest_dirty_vs_const = 0;
2044 HeapFree(GetProcessHeap(), 0, This->render_targets);
2045 HeapFree(GetProcessHeap(), 0, This->swapchains);
2046 This->NumberOfSwapChains = 0;
2047 if(This->palettes) {
2048 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2049 HeapFree(GetProcessHeap(), 0, This->palettes);
2051 This->NumberOfPalettes = 0;
2053 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2055 if (This->stateBlock)
2057 wined3d_stateblock_decref(This->stateBlock);
2058 This->stateBlock = NULL;
2060 if (This->blit_priv) {
2061 This->blitter->free_private(This);
2063 if (This->fragment_priv) {
2064 This->frag_pipe->free_private(This);
2066 if (This->shader_priv) {
2067 This->shader_backend->shader_free_private(This);
2072 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2073 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2076 IWineD3DSwapChainImpl *swapchain = NULL;
2079 /* Setup the implicit swapchain */
2080 TRACE("Creating implicit swapchain\n");
2081 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2082 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2085 WARN("Failed to create implicit swapchain\n");
2089 This->NumberOfSwapChains = 1;
2090 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2091 if (!This->swapchains)
2093 ERR("Out of memory!\n");
2096 This->swapchains[0] = swapchain;
2100 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2104 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2106 IWineD3DResource_UnLoad(resource);
2107 IWineD3DResource_Release(resource);
2111 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2112 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2115 const struct wined3d_gl_info *gl_info;
2116 struct IWineD3DSurfaceImpl *surface;
2117 struct wined3d_context *context;
2120 TRACE("(%p)\n", This);
2122 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2124 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2125 * it was created. Thus make sure a context is active for the glDelete* calls
2127 context = context_acquire(This, NULL);
2128 gl_info = context->gl_info;
2130 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2132 /* Unload resources */
2133 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2135 TRACE("Deleting high order patches\n");
2136 for(i = 0; i < PATCHMAP_SIZE; i++) {
2137 struct list *e1, *e2;
2138 struct WineD3DRectPatch *patch;
2139 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2140 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2141 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2145 /* Delete the mouse cursor texture */
2146 if(This->cursorTexture) {
2148 glDeleteTextures(1, &This->cursorTexture);
2150 This->cursorTexture = 0;
2153 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2154 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2156 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2157 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2160 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2161 * private data, it might contain opengl pointers
2163 if(This->depth_blt_texture) {
2165 glDeleteTextures(1, &This->depth_blt_texture);
2167 This->depth_blt_texture = 0;
2169 if (This->depth_blt_rb) {
2171 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2173 This->depth_blt_rb = 0;
2174 This->depth_blt_rb_w = 0;
2175 This->depth_blt_rb_h = 0;
2178 /* Release the update stateblock */
2179 if (wined3d_stateblock_decref(This->updateStateBlock))
2181 if (This->updateStateBlock != This->stateBlock)
2182 FIXME("Something's still holding the update stateblock.\n");
2184 This->updateStateBlock = NULL;
2187 struct wined3d_stateblock *stateblock = This->stateBlock;
2188 This->stateBlock = NULL;
2190 /* Release the stateblock */
2191 if (wined3d_stateblock_decref(stateblock))
2192 FIXME("Something's still holding the stateblock.\n");
2195 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2196 This->blitter->free_private(This);
2197 This->frag_pipe->free_private(This);
2198 This->shader_backend->shader_free_private(This);
2200 /* Release the buffers (with sanity checks)*/
2201 if (This->onscreen_depth_stencil)
2203 surface = This->onscreen_depth_stencil;
2204 This->onscreen_depth_stencil = NULL;
2205 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2208 if (This->depth_stencil)
2210 surface = This->depth_stencil;
2212 TRACE("Releasing depth/stencil buffer %p.\n", surface);
2214 This->depth_stencil = NULL;
2215 if (IWineD3DSurface_Release((IWineD3DSurface *)surface)
2216 && surface != This->auto_depth_stencil)
2218 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface);
2222 if (This->auto_depth_stencil)
2224 surface = This->auto_depth_stencil;
2225 This->auto_depth_stencil = NULL;
2226 if (IWineD3DSurface_Release((IWineD3DSurface *)surface))
2228 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2232 for (i = 1; i < gl_info->limits.buffers; ++i)
2234 IWineD3DDevice_SetRenderTarget(iface, i, NULL, FALSE);
2237 surface = This->render_targets[0];
2238 TRACE("Setting rendertarget 0 to NULL\n");
2239 This->render_targets[0] = NULL;
2240 TRACE("Releasing the render target at %p\n", surface);
2241 IWineD3DSurface_Release((IWineD3DSurface *)surface);
2243 context_release(context);
2245 for (i = 0; i < This->NumberOfSwapChains; ++i)
2247 TRACE("Releasing the implicit swapchain %u.\n", i);
2248 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2250 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2254 HeapFree(GetProcessHeap(), 0, This->swapchains);
2255 This->swapchains = NULL;
2256 This->NumberOfSwapChains = 0;
2258 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2259 HeapFree(GetProcessHeap(), 0, This->palettes);
2260 This->palettes = NULL;
2261 This->NumberOfPalettes = 0;
2263 HeapFree(GetProcessHeap(), 0, This->render_targets);
2264 This->render_targets = NULL;
2266 This->d3d_initialized = FALSE;
2271 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2275 for (i = 0; i < This->NumberOfSwapChains; ++i)
2277 TRACE("Releasing the implicit swapchain %u.\n", i);
2278 if (D3DCB_DestroySwapChain((IWineD3DSwapChain *)This->swapchains[i]) > 0)
2280 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2284 HeapFree(GetProcessHeap(), 0, This->swapchains);
2285 This->swapchains = NULL;
2286 This->NumberOfSwapChains = 0;
2290 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2291 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2292 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2294 * There is no way to deactivate thread safety once it is enabled.
2296 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2299 /*For now just store the flag(needed in case of ddraw) */
2300 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2303 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2304 const WINED3DDISPLAYMODE* pMode) {
2306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2307 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2311 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2313 /* Resize the screen even without a window:
2314 * The app could have unset it with SetCooperativeLevel, but not called
2315 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2316 * but we don't have any hwnd
2319 memset(&devmode, 0, sizeof(devmode));
2320 devmode.dmSize = sizeof(devmode);
2321 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2322 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2323 devmode.dmPelsWidth = pMode->Width;
2324 devmode.dmPelsHeight = pMode->Height;
2326 devmode.dmDisplayFrequency = pMode->RefreshRate;
2327 if (pMode->RefreshRate)
2328 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2330 /* Only change the mode if necessary */
2331 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2332 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2335 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2336 if (ret != DISP_CHANGE_SUCCESSFUL)
2338 if (devmode.dmDisplayFrequency)
2340 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2341 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2342 devmode.dmDisplayFrequency = 0;
2343 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2345 if(ret != DISP_CHANGE_SUCCESSFUL) {
2346 return WINED3DERR_NOTAVAILABLE;
2350 /* Store the new values */
2351 This->ddraw_width = pMode->Width;
2352 This->ddraw_height = pMode->Height;
2353 This->ddraw_format = pMode->Format;
2355 /* And finally clip mouse to our screen */
2356 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2357 ClipCursor(&clip_rc);
2362 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 *ppD3D = This->wined3d;
2365 TRACE("Returning %p.\n", *ppD3D);
2366 IWineD3D_AddRef(*ppD3D);
2370 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2373 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2374 (This->adapter->TextureRam/(1024*1024)),
2375 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2376 /* return simulated texture memory left */
2377 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2381 * Get / Set Stream Source
2383 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2384 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2387 struct wined3d_stream_state *stream;
2388 IWineD3DBuffer *oldSrc;
2390 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2391 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2393 if (StreamNumber >= MAX_STREAMS) {
2394 WARN("Stream out of range %d\n", StreamNumber);
2395 return WINED3DERR_INVALIDCALL;
2396 } else if(OffsetInBytes & 0x3) {
2397 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2398 return WINED3DERR_INVALIDCALL;
2401 stream = &This->updateStateBlock->state.streams[StreamNumber];
2402 oldSrc = (IWineD3DBuffer *)stream->buffer;
2404 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2406 if (oldSrc == pStreamData
2407 && stream->stride == Stride
2408 && stream->offset == OffsetInBytes)
2410 TRACE("Application is setting the old values over, nothing to do\n");
2414 stream->buffer = (struct wined3d_buffer *)pStreamData;
2417 stream->stride = Stride;
2418 stream->offset = OffsetInBytes;
2421 /* Handle recording of state blocks */
2422 if (This->isRecordingState) {
2423 TRACE("Recording... not performing anything\n");
2424 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2425 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2431 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2432 IWineD3DBuffer_AddRef(pStreamData);
2436 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2437 IWineD3DBuffer_Release(oldSrc);
2440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2445 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2446 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2449 struct wined3d_stream_state *stream;
2451 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2452 iface, StreamNumber, pStream, pOffset, pStride);
2454 if (StreamNumber >= MAX_STREAMS)
2456 WARN("Stream out of range %d\n", StreamNumber);
2457 return WINED3DERR_INVALIDCALL;
2460 stream = &This->stateBlock->state.streams[StreamNumber];
2461 *pStream = (IWineD3DBuffer *)stream->buffer;
2462 *pStride = stream->stride;
2463 if (pOffset) *pOffset = stream->offset;
2465 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2470 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 struct wined3d_stream_state *stream;
2473 UINT old_flags, oldFreq;
2475 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2477 /* Verify input at least in d3d9 this is invalid. */
2478 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2480 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2481 return WINED3DERR_INVALIDCALL;
2483 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2485 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2486 return WINED3DERR_INVALIDCALL;
2490 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2491 return WINED3DERR_INVALIDCALL;
2494 stream = &This->updateStateBlock->state.streams[StreamNumber];
2495 old_flags = stream->flags;
2496 oldFreq = stream->frequency;
2498 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2499 stream->frequency = Divider & 0x7FFFFF;
2501 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2503 if (stream->frequency != oldFreq || stream->flags != old_flags)
2504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2509 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 struct wined3d_stream_state *stream;
2513 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2515 stream = &This->updateStateBlock->state.streams[StreamNumber];
2516 *Divider = stream->flags | stream->frequency;
2518 TRACE("Returning %#x.\n", *Divider);
2524 * Get / Set & Multiply Transform
2526 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 /* Most of this routine, comments included copied from ddraw tree initially: */
2530 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2532 /* Handle recording of state blocks */
2533 if (This->isRecordingState) {
2534 TRACE("Recording... not performing anything\n");
2535 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2536 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2541 * If the new matrix is the same as the current one,
2542 * we cut off any further processing. this seems to be a reasonable
2543 * optimization because as was noticed, some apps (warcraft3 for example)
2544 * tend towards setting the same matrix repeatedly for some reason.
2546 * From here on we assume that the new matrix is different, wherever it matters.
2548 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2550 TRACE("The app is setting the same matrix over again\n");
2555 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2559 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2560 where ViewMat = Camera space, WorldMat = world space.
2562 In OpenGL, camera and world space is combined into GL_MODELVIEW
2563 matrix. The Projection matrix stay projection matrix.
2566 /* Capture the times we can just ignore the change for now */
2567 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2568 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2569 /* Handled by the state manager */
2572 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2579 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2580 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2582 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2584 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2586 *matrix = device->stateBlock->state.transforms[state];
2591 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2592 const WINED3DMATRIX *mat = NULL;
2595 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2596 * below means it will be recorded in a state block change, but it
2597 * works regardless where it is recorded.
2598 * If this is found to be wrong, change to StateBlock.
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2603 if (State <= HIGHEST_TRANSFORMSTATE)
2605 mat = &This->updateStateBlock->state.transforms[State];
2609 FIXME("Unhandled transform state!!\n");
2612 multiply_matrix(&temp, mat, pMatrix);
2614 /* Apply change via set transform - will reapply to eg. lights this way */
2615 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2621 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2622 you can reference any indexes you want as long as that number max are enabled at any
2623 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2624 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2625 but when recording, just build a chain pretty much of commands to be replayed. */
2627 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2629 struct wined3d_light_info *object = NULL;
2630 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2634 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2636 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2640 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2641 return WINED3DERR_INVALIDCALL;
2644 switch(pLight->Type) {
2645 case WINED3DLIGHT_POINT:
2646 case WINED3DLIGHT_SPOT:
2647 case WINED3DLIGHT_PARALLELPOINT:
2648 case WINED3DLIGHT_GLSPOT:
2649 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2652 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2654 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2659 case WINED3DLIGHT_DIRECTIONAL:
2660 /* Ignores attenuation */
2664 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2665 return WINED3DERR_INVALIDCALL;
2668 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2670 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2671 if(object->OriginalIndex == Index) break;
2676 TRACE("Adding new light\n");
2677 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2679 ERR("Out of memory error when allocating a light\n");
2680 return E_OUTOFMEMORY;
2682 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2683 object->glIndex = -1;
2684 object->OriginalIndex = Index;
2687 /* Initialize the object */
2688 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,
2689 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2690 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2691 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2692 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2693 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2694 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2696 /* Save away the information */
2697 object->OriginalParms = *pLight;
2699 switch (pLight->Type) {
2700 case WINED3DLIGHT_POINT:
2702 object->lightPosn[0] = pLight->Position.x;
2703 object->lightPosn[1] = pLight->Position.y;
2704 object->lightPosn[2] = pLight->Position.z;
2705 object->lightPosn[3] = 1.0f;
2706 object->cutoff = 180.0f;
2710 case WINED3DLIGHT_DIRECTIONAL:
2712 object->lightPosn[0] = -pLight->Direction.x;
2713 object->lightPosn[1] = -pLight->Direction.y;
2714 object->lightPosn[2] = -pLight->Direction.z;
2715 object->lightPosn[3] = 0.0f;
2716 object->exponent = 0.0f;
2717 object->cutoff = 180.0f;
2720 case WINED3DLIGHT_SPOT:
2722 object->lightPosn[0] = pLight->Position.x;
2723 object->lightPosn[1] = pLight->Position.y;
2724 object->lightPosn[2] = pLight->Position.z;
2725 object->lightPosn[3] = 1.0f;
2728 object->lightDirn[0] = pLight->Direction.x;
2729 object->lightDirn[1] = pLight->Direction.y;
2730 object->lightDirn[2] = pLight->Direction.z;
2731 object->lightDirn[3] = 1.0f;
2734 * opengl-ish and d3d-ish spot lights use too different models for the
2735 * light "intensity" as a function of the angle towards the main light direction,
2736 * so we only can approximate very roughly.
2737 * however spot lights are rather rarely used in games (if ever used at all).
2738 * furthermore if still used, probably nobody pays attention to such details.
2740 if (!pLight->Falloff)
2742 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2743 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2744 * will always be 1.0 for both of them, and we don't have to care for the
2745 * rest of the rather complex calculation
2747 object->exponent = 0.0f;
2749 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2750 if (rho < 0.0001f) rho = 0.0001f;
2751 object->exponent = -0.3f/logf(cosf(rho/2));
2753 if (object->exponent > 128.0f)
2755 object->exponent = 128.0f;
2757 object->cutoff = (float) (pLight->Phi*90/M_PI);
2763 FIXME("Unrecognized light type %d\n", pLight->Type);
2766 /* Update the live definitions if the light is currently assigned a glIndex */
2767 if (object->glIndex != -1 && !This->isRecordingState) {
2768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2773 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2775 struct wined3d_light_info *lightInfo = NULL;
2776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2777 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2779 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2781 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2783 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2784 if(lightInfo->OriginalIndex == Index) break;
2790 TRACE("Light information requested but light not defined\n");
2791 return WINED3DERR_INVALIDCALL;
2794 *pLight = lightInfo->OriginalParms;
2799 * Get / Set Light Enable
2800 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2802 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2804 struct wined3d_light_info *lightInfo = NULL;
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2808 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2810 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2812 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2813 if(lightInfo->OriginalIndex == Index) break;
2816 TRACE("Found light: %p\n", lightInfo);
2818 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2821 TRACE("Light enabled requested but light not defined, so defining one!\n");
2822 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2824 /* Search for it again! Should be fairly quick as near head of list */
2825 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2827 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2828 if(lightInfo->OriginalIndex == Index) break;
2833 FIXME("Adding default lights has failed dismally\n");
2834 return WINED3DERR_INVALIDCALL;
2839 if(lightInfo->glIndex != -1) {
2840 if(!This->isRecordingState) {
2841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2844 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2845 lightInfo->glIndex = -1;
2847 TRACE("Light already disabled, nothing to do\n");
2849 lightInfo->enabled = FALSE;
2851 lightInfo->enabled = TRUE;
2852 if (lightInfo->glIndex != -1) {
2854 TRACE("Nothing to do as light was enabled\n");
2857 /* Find a free gl light */
2858 for (i = 0; i < This->maxConcurrentLights; ++i)
2860 if (!This->updateStateBlock->state.lights[i])
2862 This->updateStateBlock->state.lights[i] = lightInfo;
2863 lightInfo->glIndex = i;
2867 if(lightInfo->glIndex == -1) {
2868 /* Our tests show that Windows returns D3D_OK in this situation, even with
2869 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2870 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2871 * as well for those lights.
2873 * TODO: Test how this affects rendering
2875 WARN("Too many concurrently active lights\n");
2879 /* i == lightInfo->glIndex */
2880 if(!This->isRecordingState) {
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2889 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2891 struct wined3d_light_info *lightInfo = NULL;
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2894 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2895 TRACE("(%p) : for idx(%d)\n", This, Index);
2897 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2899 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2900 if(lightInfo->OriginalIndex == Index) break;
2906 TRACE("Light enabled state requested but light not defined\n");
2907 return WINED3DERR_INVALIDCALL;
2909 /* true is 128 according to SetLightEnable */
2910 *pEnable = lightInfo->enabled ? 128 : 0;
2915 * Get / Set Clip Planes
2917 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2921 /* Validate Index */
2922 if (Index >= This->adapter->gl_info.limits.clipplanes)
2924 TRACE("Application has requested clipplane this device doesn't support\n");
2925 return WINED3DERR_INVALIDCALL;
2928 This->updateStateBlock->changed.clipplane |= 1 << Index;
2930 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2931 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2932 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2933 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2935 TRACE("Application is setting old values over, nothing to do\n");
2939 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2940 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2941 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2942 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2944 /* Handle recording of state blocks */
2945 if (This->isRecordingState) {
2946 TRACE("Recording... not performing anything\n");
2950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 TRACE("(%p) : for idx %d\n", This, Index);
2959 /* Validate Index */
2960 if (Index >= This->adapter->gl_info.limits.clipplanes)
2962 TRACE("Application has requested clipplane this device doesn't support\n");
2963 return WINED3DERR_INVALIDCALL;
2966 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2967 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2968 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2969 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2974 * Get / Set Clip Plane Status
2975 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 FIXME("(%p) : stub\n", This);
2982 return WINED3DERR_INVALIDCALL;
2984 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2985 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 FIXME("(%p) : stub\n", This);
2994 return WINED3DERR_INVALIDCALL;
2996 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2997 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
3002 * Get / Set Material
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 This->updateStateBlock->changed.material = TRUE;
3008 This->updateStateBlock->state.material = *pMaterial;
3010 /* Handle recording of state blocks */
3011 if (This->isRecordingState) {
3012 TRACE("Recording... not performing anything\n");
3016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3020 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 *pMaterial = This->updateStateBlock->state.material;
3023 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3024 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3025 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3026 pMaterial->Ambient.b, pMaterial->Ambient.a);
3027 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3028 pMaterial->Specular.b, pMaterial->Specular.a);
3029 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3030 pMaterial->Emissive.b, pMaterial->Emissive.a);
3031 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3039 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3040 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 IWineD3DBuffer *oldIdxs;
3045 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3046 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3048 This->updateStateBlock->changed.indices = TRUE;
3049 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3050 This->updateStateBlock->state.index_format = fmt;
3052 /* Handle recording of state blocks */
3053 if (This->isRecordingState) {
3054 TRACE("Recording... not performing anything\n");
3055 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3056 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3060 if(oldIdxs != pIndexData) {
3061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3063 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3064 IWineD3DBuffer_AddRef(pIndexData);
3067 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3068 IWineD3DBuffer_Release(oldIdxs);
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3081 /* up ref count on ppindexdata */
3083 IWineD3DBuffer_AddRef(*ppIndexData);
3084 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3086 TRACE("(%p) No index data set\n", This);
3088 TRACE("Returning %p\n", *ppIndexData);
3093 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3094 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p)->(%d)\n", This, BaseIndex);
3098 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3100 TRACE("Application is setting the old value over, nothing to do\n");
3104 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3106 if (This->isRecordingState) {
3107 TRACE("Recording... not performing anything\n");
3110 /* The base vertex index affects the stream sources */
3111 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3115 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 TRACE("(%p) : base_index %p\n", This, base_index);
3119 *base_index = This->stateBlock->state.base_vertex_index;
3121 TRACE("Returning %u\n", *base_index);
3127 * Get / Set Viewports
3129 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 TRACE("(%p)\n", This);
3133 This->updateStateBlock->changed.viewport = TRUE;
3134 This->updateStateBlock->state.viewport = *pViewport;
3136 /* Handle recording of state blocks */
3137 if (This->isRecordingState) {
3138 TRACE("Recording... not performing anything\n");
3142 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3143 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3150 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 TRACE("(%p)\n", This);
3153 *pViewport = This->stateBlock->state.viewport;
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3158 WINED3DRENDERSTATETYPE State, DWORD Value)
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 DWORD oldValue = This->stateBlock->state.render_states[State];
3163 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3165 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3166 This->updateStateBlock->state.render_states[State] = Value;
3168 /* Handle recording of state blocks */
3169 if (This->isRecordingState) {
3170 TRACE("Recording... not performing anything\n");
3174 /* Compared here and not before the assignment to allow proper stateblock recording */
3175 if(Value == oldValue) {
3176 TRACE("Application is setting the old value over, nothing to do\n");
3178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3185 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3191 *pValue = This->stateBlock->state.render_states[State];
3196 * Get / Set Sampler States
3197 * TODO: Verify against dx9 definitions
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3204 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3205 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3207 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3208 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3211 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3213 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3214 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3217 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3218 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3219 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3221 /* Handle recording of state blocks */
3222 if (This->isRecordingState) {
3223 TRACE("Recording... not performing anything\n");
3227 if(oldValue == Value) {
3228 TRACE("Application is setting the old value over, nothing to do\n");
3232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3237 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3241 This, Sampler, debug_d3dsamplerstate(Type), Type);
3243 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3244 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3247 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3249 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3250 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3252 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3253 TRACE("(%p) : Returning %#x\n", This, *Value);
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 This->updateStateBlock->changed.scissorRect = TRUE;
3262 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3264 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3267 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3269 if(This->isRecordingState) {
3270 TRACE("Recording... not performing anything\n");
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 *pRect = This->updateStateBlock->state.scissor_rect;
3283 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3289 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3291 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3293 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3294 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3296 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3297 This->updateStateBlock->changed.vertexDecl = TRUE;
3299 if (This->isRecordingState) {
3300 TRACE("Recording... not performing anything\n");
3302 } else if(pDecl == oldDecl) {
3303 /* Checked after the assignment to allow proper stateblock recording */
3304 TRACE("Application is setting the old declaration over, nothing to do\n");
3308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3317 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3318 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3322 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3325 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3327 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3328 This->updateStateBlock->changed.vertexShader = TRUE;
3330 if (This->isRecordingState) {
3331 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3332 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3333 TRACE("Recording... not performing anything\n");
3335 } else if(oldShader == pShader) {
3336 /* Checked here to allow proper stateblock recording */
3337 TRACE("App is setting the old shader over, nothing to do\n");
3341 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3342 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3343 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3350 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3352 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3353 IWineD3DVertexShader *shader;
3355 TRACE("iface %p.\n", iface);
3357 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3358 if (shader) IWineD3DVertexShader_AddRef(shader);
3360 TRACE("Returning %p.\n", shader);
3364 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3365 IWineD3DDevice *iface,
3367 CONST BOOL *srcData,
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3371 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3373 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3374 iface, srcData, start, count);
3376 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3378 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3379 for (i = 0; i < cnt; i++)
3380 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3382 for (i = start; i < cnt + start; ++i) {
3383 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3386 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3391 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3392 IWineD3DDevice *iface,
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 int cnt = min(count, MAX_CONST_B - start);
3400 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3401 iface, dstData, start, count);
3403 if (!dstData || cnt < 0)
3404 return WINED3DERR_INVALIDCALL;
3406 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3410 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3411 IWineD3DDevice *iface,
3416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3419 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3420 iface, srcData, start, count);
3422 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3424 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3425 for (i = 0; i < cnt; i++)
3426 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3427 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3429 for (i = start; i < cnt + start; ++i) {
3430 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3433 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3438 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3439 IWineD3DDevice *iface,
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 int cnt = min(count, MAX_CONST_I - start);
3447 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3448 iface, dstData, start, count);
3450 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3451 return WINED3DERR_INVALIDCALL;
3453 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3457 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3458 IWineD3DDevice *iface,
3460 CONST float *srcData,
3463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3467 iface, srcData, start, count);
3469 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3470 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3471 return WINED3DERR_INVALIDCALL;
3473 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3475 for (i = 0; i < count; i++)
3476 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3477 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3480 if (!This->isRecordingState)
3482 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3486 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3487 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3492 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3493 IWineD3DDevice *iface,
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 int cnt = min(count, This->d3d_vshader_constantF - start);
3501 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3502 iface, dstData, start, count);
3504 if (!dstData || cnt < 0)
3505 return WINED3DERR_INVALIDCALL;
3507 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3511 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3513 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3519 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3521 DWORD i = This->rev_tex_unit_map[unit];
3522 DWORD j = This->texUnitMap[stage];
3524 This->texUnitMap[stage] = unit;
3525 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3527 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3530 This->rev_tex_unit_map[unit] = stage;
3531 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3533 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3537 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3540 This->fixed_function_usage_map = 0;
3541 for (i = 0; i < MAX_TEXTURES; ++i)
3543 const struct wined3d_state *state = &This->stateBlock->state;
3544 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3545 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3546 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3547 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3548 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3549 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3550 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3551 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3553 if (color_op == WINED3DTOP_DISABLE) {
3554 /* Not used, and disable higher stages */
3558 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3559 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3560 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3561 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3562 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3563 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3564 This->fixed_function_usage_map |= (1 << i);
3567 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3568 This->fixed_function_usage_map |= (1 << (i + 1));
3573 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3575 unsigned int i, tex;
3578 device_update_fixed_function_usage_map(This);
3579 ffu_map = This->fixed_function_usage_map;
3581 if (This->max_ffp_textures == gl_info->limits.texture_stages
3582 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3584 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3586 if (!(ffu_map & 1)) continue;
3588 if (This->texUnitMap[i] != i) {
3589 device_map_stage(This, i, i);
3590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3591 markTextureStagesDirty(This, i);
3597 /* Now work out the mapping */
3599 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3601 if (!(ffu_map & 1)) continue;
3603 if (This->texUnitMap[i] != tex) {
3604 device_map_stage(This, i, tex);
3605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3606 markTextureStagesDirty(This, i);
3613 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3615 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3616 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3619 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3620 if (sampler_type[i] && This->texUnitMap[i] != i)
3622 device_map_stage(This, i, i);
3623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3624 if (i < gl_info->limits.texture_stages)
3626 markTextureStagesDirty(This, i);
3632 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3633 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3635 DWORD current_mapping = This->rev_tex_unit_map[unit];
3637 /* Not currently used */
3638 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3640 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3641 /* Used by a fragment sampler */
3643 if (!pshader_sampler_tokens) {
3644 /* No pixel shader, check fixed function */
3645 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3648 /* Pixel shader, check the shader's sampler map */
3649 return !pshader_sampler_tokens[current_mapping];
3652 /* Used by a vertex sampler */
3653 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3656 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3658 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3659 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3660 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3661 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3666 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3668 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3669 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3670 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3673 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3674 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3675 if (vshader_sampler_type[i])
3677 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3679 /* Already mapped somewhere */
3683 while (start >= 0) {
3684 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3686 device_map_stage(This, vsampler_idx, start);
3687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3699 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3701 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3702 const struct wined3d_state *state = &This->stateBlock->state;
3703 BOOL vs = use_vs(state);
3704 BOOL ps = use_ps(state);
3707 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3708 * that would be really messy and require shader recompilation
3709 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3710 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3712 if (ps) device_map_psamplers(This, gl_info);
3713 else device_map_fixed_function_samplers(This, gl_info);
3715 if (vs) device_map_vsamplers(This, ps, gl_info);
3718 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3721 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3722 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3723 This->updateStateBlock->changed.pixelShader = TRUE;
3725 /* Handle recording of state blocks */
3726 if (This->isRecordingState) {
3727 TRACE("Recording... not performing anything\n");
3730 if (This->isRecordingState) {
3731 TRACE("Recording... not performing anything\n");
3732 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3733 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3737 if(pShader == oldShader) {
3738 TRACE("App is setting the old pixel shader over, nothing to do\n");
3742 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3743 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3745 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3751 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3753 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3754 IWineD3DPixelShader *shader;
3756 TRACE("iface %p.\n", iface);
3758 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3759 if (shader) IWineD3DPixelShader_AddRef(shader);
3761 TRACE("Returning %p.\n", shader);
3765 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3766 IWineD3DDevice *iface,
3768 CONST BOOL *srcData,
3771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3772 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3774 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3775 iface, srcData, start, count);
3777 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3779 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3780 for (i = 0; i < cnt; i++)
3781 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3783 for (i = start; i < cnt + start; ++i) {
3784 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3787 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3792 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3793 IWineD3DDevice *iface,
3798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3799 int cnt = min(count, MAX_CONST_B - start);
3801 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3802 iface, dstData, start, count);
3804 if (!dstData || cnt < 0)
3805 return WINED3DERR_INVALIDCALL;
3807 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3811 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3812 IWineD3DDevice *iface,
3817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3818 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3820 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3821 iface, srcData, start, count);
3823 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3825 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3826 for (i = 0; i < cnt; i++)
3827 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3828 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3830 for (i = start; i < cnt + start; ++i) {
3831 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3834 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3839 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3840 IWineD3DDevice *iface,
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 int cnt = min(count, MAX_CONST_I - start);
3848 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3849 iface, dstData, start, count);
3851 if (!dstData || cnt < 0)
3852 return WINED3DERR_INVALIDCALL;
3854 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3858 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3859 IWineD3DDevice *iface,
3861 CONST float *srcData,
3864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3867 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3868 iface, srcData, start, count);
3870 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3871 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3876 for (i = 0; i < count; i++)
3877 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3878 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3881 if (!This->isRecordingState)
3883 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3887 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3888 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3893 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3894 IWineD3DDevice *iface,
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3900 int cnt = min(count, This->d3d_pshader_constantF - start);
3902 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3903 iface, dstData, start, count);
3905 if (!dstData || cnt < 0)
3906 return WINED3DERR_INVALIDCALL;
3908 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3912 /* Context activation is done by the caller. */
3913 /* Do not call while under the GL lock. */
3914 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3915 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3916 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3919 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3920 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3923 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3927 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3929 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3932 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3934 ERR("Source has no position mask\n");
3935 return WINED3DERR_INVALIDCALL;
3938 if (!dest->resource.allocatedMemory)
3939 buffer_get_sysmem(dest, gl_info);
3941 /* Get a pointer into the destination vbo(create one if none exists) and
3942 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3944 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3946 dest->flags |= WINED3D_BUFFER_CREATEBO;
3947 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3950 if (dest->buffer_object)
3952 unsigned char extrabytes = 0;
3953 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3954 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3955 * this may write 4 extra bytes beyond the area that should be written
3957 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3958 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3959 if(!dest_conv_addr) {
3960 ERR("Out of memory\n");
3961 /* Continue without storing converted vertices */
3963 dest_conv = dest_conv_addr;
3966 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3968 static BOOL warned = FALSE;
3970 * The clipping code is not quite correct. Some things need
3971 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3972 * so disable clipping for now.
3973 * (The graphics in Half-Life are broken, and my processvertices
3974 * test crashes with IDirect3DDevice3)
3980 FIXME("Clipping is broken and disabled for now\n");
3982 } else doClip = FALSE;
3983 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3985 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3988 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3989 WINED3DTS_PROJECTION,
3991 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3992 WINED3DTS_WORLDMATRIX(0),
3995 TRACE("View mat:\n");
3996 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);
3997 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);
3998 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);
3999 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);
4001 TRACE("Proj mat:\n");
4002 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);
4003 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);
4004 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);
4005 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);
4007 TRACE("World mat:\n");
4008 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);
4009 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);
4010 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);
4011 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);
4013 /* Get the viewport */
4014 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4015 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4016 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4018 multiply_matrix(&mat,&view_mat,&world_mat);
4019 multiply_matrix(&mat,&proj_mat,&mat);
4021 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4023 for (i = 0; i < dwCount; i+= 1) {
4024 unsigned int tex_index;
4026 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4027 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4028 /* The position first */
4029 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4030 const float *p = (const float *)(element->data + i * element->stride);
4032 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4034 /* Multiplication with world, view and projection matrix */
4035 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);
4036 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);
4037 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);
4038 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);
4040 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4042 /* WARNING: The following things are taken from d3d7 and were not yet checked
4043 * against d3d8 or d3d9!
4046 /* Clipping conditions: From msdn
4048 * A vertex is clipped if it does not match the following requirements
4052 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4054 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4055 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4060 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4061 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4064 /* "Normal" viewport transformation (not clipped)
4065 * 1) The values are divided by rhw
4066 * 2) The y axis is negative, so multiply it with -1
4067 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4068 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4069 * 4) Multiply x with Width/2 and add Width/2
4070 * 5) The same for the height
4071 * 6) Add the viewpoint X and Y to the 2D coordinates and
4072 * The minimum Z value to z
4073 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4075 * Well, basically it's simply a linear transformation into viewport
4087 z *= vp.MaxZ - vp.MinZ;
4089 x += vp.Width / 2 + vp.X;
4090 y += vp.Height / 2 + vp.Y;
4095 /* That vertex got clipped
4096 * Contrary to OpenGL it is not dropped completely, it just
4097 * undergoes a different calculation.
4099 TRACE("Vertex got clipped\n");
4106 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4107 * outside of the main vertex buffer memory. That needs some more
4112 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4115 ( (float *) dest_ptr)[0] = x;
4116 ( (float *) dest_ptr)[1] = y;
4117 ( (float *) dest_ptr)[2] = z;
4118 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4120 dest_ptr += 3 * sizeof(float);
4122 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4123 dest_ptr += sizeof(float);
4128 ( (float *) dest_conv)[0] = x * w;
4129 ( (float *) dest_conv)[1] = y * w;
4130 ( (float *) dest_conv)[2] = z * w;
4131 ( (float *) dest_conv)[3] = w;
4133 dest_conv += 3 * sizeof(float);
4135 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4136 dest_conv += sizeof(float);
4140 if (DestFVF & WINED3DFVF_PSIZE) {
4141 dest_ptr += sizeof(DWORD);
4142 if(dest_conv) dest_conv += sizeof(DWORD);
4144 if (DestFVF & WINED3DFVF_NORMAL) {
4145 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4146 const float *normal = (const float *)(element->data + i * element->stride);
4147 /* AFAIK this should go into the lighting information */
4148 FIXME("Didn't expect the destination to have a normal\n");
4149 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4151 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4155 if (DestFVF & WINED3DFVF_DIFFUSE) {
4156 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4157 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4158 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4160 static BOOL warned = FALSE;
4163 ERR("No diffuse color in source, but destination has one\n");
4167 *( (DWORD *) dest_ptr) = 0xffffffff;
4168 dest_ptr += sizeof(DWORD);
4171 *( (DWORD *) dest_conv) = 0xffffffff;
4172 dest_conv += sizeof(DWORD);
4176 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4178 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4179 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4180 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4181 dest_conv += sizeof(DWORD);
4186 if (DestFVF & WINED3DFVF_SPECULAR)
4188 /* What's the color value in the feedback buffer? */
4189 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4190 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4191 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4193 static BOOL warned = FALSE;
4196 ERR("No specular color in source, but destination has one\n");
4200 *( (DWORD *) dest_ptr) = 0xFF000000;
4201 dest_ptr += sizeof(DWORD);
4204 *( (DWORD *) dest_conv) = 0xFF000000;
4205 dest_conv += sizeof(DWORD);
4209 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4211 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4212 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4213 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4214 dest_conv += sizeof(DWORD);
4219 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4220 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4221 const float *tex_coord = (const float *)(element->data + i * element->stride);
4222 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4224 ERR("No source texture, but destination requests one\n");
4225 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4226 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4229 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4231 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4241 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4242 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4243 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4244 dwCount * get_flexible_vertex_size(DestFVF),
4246 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4250 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4255 #undef copy_and_next
4257 /* Do not call while under the GL lock. */
4258 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4259 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD flags,
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4263 struct wined3d_stream_info stream_info;
4264 const struct wined3d_gl_info *gl_info;
4265 struct wined3d_context *context;
4266 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4269 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4272 ERR("Output vertex declaration not implemented yet\n");
4275 /* Need any context to write to the vbo. */
4276 context = context_acquire(This, NULL);
4277 gl_info = context->gl_info;
4279 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4280 * control the streamIsUP flag, thus restore it afterwards.
4282 This->stateBlock->state.user_stream = FALSE;
4283 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4284 This->stateBlock->state.user_stream = streamWasUP;
4286 if(vbo || SrcStartIndex) {
4288 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4289 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4291 * Also get the start index in, but only loop over all elements if there's something to add at all.
4293 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4295 struct wined3d_stream_info_element *e;
4297 if (!(stream_info.use_map & (1 << i))) continue;
4299 e = &stream_info.elements[i];
4300 if (e->buffer_object)
4302 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4303 e->buffer_object = 0;
4304 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4306 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4307 vb->buffer_object = 0;
4310 if (e->data) e->data += e->stride * SrcStartIndex;
4314 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4315 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4317 context_release(context);
4323 * Get / Set Texture Stage States
4324 * TODO: Verify against dx9 definitions
4326 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4329 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4332 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4334 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4336 WARN("Invalid Type %d passed.\n", Type);
4340 if (Stage >= gl_info->limits.texture_stages)
4342 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4343 Stage, gl_info->limits.texture_stages - 1);
4347 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4348 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4349 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4351 if (This->isRecordingState) {
4352 TRACE("Recording... not performing anything\n");
4356 /* Checked after the assignments to allow proper stateblock recording */
4357 if(oldValue == Value) {
4358 TRACE("App is setting the old value over, nothing to do\n");
4362 if (Stage > This->stateBlock->state.lowest_disabled_stage
4363 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4364 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4366 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4367 * Changes in other states are important on disabled stages too
4372 if(Type == WINED3DTSS_COLOROP) {
4375 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4376 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4377 * they have to be disabled
4379 * The current stage is dirtified below.
4381 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4383 TRACE("Additionally dirtifying stage %u\n", i);
4384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4386 This->stateBlock->state.lowest_disabled_stage = Stage;
4387 TRACE("New lowest disabled: %u\n", Stage);
4388 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4389 /* Previously disabled stage enabled. Stages above it may need enabling
4390 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4391 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4393 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4396 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4398 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4400 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4403 This->stateBlock->state.lowest_disabled_stage = i;
4404 TRACE("New lowest disabled: %u\n", i);
4408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4413 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4417 TRACE("iface %p, stage %u, state %s, value %p.\n",
4418 iface, Stage, debug_d3dtexturestate(Type), pValue);
4420 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4422 WARN("Invalid Type %d passed.\n", Type);
4426 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4427 TRACE("Returning %#x.\n", *pValue);
4435 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4436 DWORD stage, IWineD3DBaseTexture *texture)
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4440 IWineD3DBaseTexture *prev;
4442 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4444 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4445 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4447 /* Windows accepts overflowing this array... we do not. */
4448 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4450 WARN("Ignoring invalid stage %u.\n", stage);
4454 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4455 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4457 WARN("Rejecting attempt to set scratch texture.\n");
4458 return WINED3DERR_INVALIDCALL;
4461 This->updateStateBlock->changed.textures |= 1 << stage;
4463 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4464 TRACE("Previous texture %p.\n", prev);
4466 if (texture == prev)
4468 TRACE("App is setting the same texture again, nothing to do.\n");
4472 TRACE("Setting new texture to %p.\n", texture);
4473 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4475 if (This->isRecordingState)
4477 TRACE("Recording... not performing anything\n");
4479 if (texture) IWineD3DBaseTexture_AddRef(texture);
4480 if (prev) IWineD3DBaseTexture_Release(prev);
4487 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4488 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4489 GLenum dimensions = t->baseTexture.target;
4491 IWineD3DBaseTexture_AddRef(texture);
4493 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4496 if (!prev && stage < gl_info->limits.texture_stages)
4498 /* The source arguments for color and alpha ops have different
4499 * meanings when a NULL texture is bound, so the COLOROP and
4500 * ALPHAOP have to be dirtified. */
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4505 if (bind_count == 1) t->baseTexture.sampler = stage;
4510 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4511 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4513 IWineD3DBaseTexture_Release(prev);
4515 if (!texture && stage < gl_info->limits.texture_stages)
4517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4521 if (bind_count && t->baseTexture.sampler == stage)
4525 /* Search for other stages the texture is bound to. Shouldn't
4526 * happen if applications bind textures to a single stage only. */
4527 TRACE("Searching for other stages the texture is bound to.\n");
4528 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4530 if (This->updateStateBlock->state.textures[i] == t)
4532 TRACE("Texture is also bound to stage %u.\n", i);
4533 t->baseTexture.sampler = i;
4540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4545 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4550 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4551 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4554 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4556 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4557 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4560 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4562 IWineD3DBaseTexture_AddRef(*ppTexture);
4564 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4572 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4573 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4575 IWineD3DSwapChain *swapchain;
4578 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4579 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4581 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4584 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4588 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4589 IWineD3DSwapChain_Release(swapchain);
4592 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4599 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4601 WARN("(%p) : stub, calling idirect3d for now\n", This);
4602 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4605 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 IWineD3DSwapChain *swapChain;
4610 if(iSwapChain > 0) {
4611 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4612 if (hr == WINED3D_OK) {
4613 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4614 IWineD3DSwapChain_Release(swapChain);
4616 FIXME("(%p) Error getting display mode\n", This);
4619 /* Don't read the real display mode,
4620 but return the stored mode instead. X11 can't change the color
4621 depth, and some apps are pretty angry if they SetDisplayMode from
4622 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4624 Also don't relay to the swapchain because with ddraw it's possible
4625 that there isn't a swapchain at all */
4626 pMode->Width = This->ddraw_width;
4627 pMode->Height = This->ddraw_height;
4628 pMode->Format = This->ddraw_format;
4629 pMode->RefreshRate = 0;
4637 * Stateblock related functions
4640 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4643 struct wined3d_stateblock *stateblock;
4646 TRACE("(%p)\n", This);
4648 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4650 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4651 if (FAILED(hr)) return hr;
4653 wined3d_stateblock_decref(This->updateStateBlock);
4654 This->updateStateBlock = stateblock;
4655 This->isRecordingState = TRUE;
4657 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4662 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4663 struct wined3d_stateblock **stateblock)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 struct wined3d_stateblock *object = This->updateStateBlock;
4668 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4670 if (!This->isRecordingState) {
4671 WARN("(%p) not recording! returning error\n", This);
4673 return WINED3DERR_INVALIDCALL;
4676 stateblock_init_contained_states(object);
4678 *stateblock = object;
4679 This->isRecordingState = FALSE;
4680 This->updateStateBlock = This->stateBlock;
4681 wined3d_stateblock_incref(This->updateStateBlock);
4683 TRACE("Returning stateblock %p.\n", *stateblock);
4689 * Scene related functions
4691 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4692 /* At the moment we have no need for any functionality at the beginning
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 TRACE("(%p)\n", This);
4698 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4699 return WINED3DERR_INVALIDCALL;
4701 This->inScene = TRUE;
4705 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 struct wined3d_context *context;
4710 TRACE("(%p)\n", This);
4712 if(!This->inScene) {
4713 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4714 return WINED3DERR_INVALIDCALL;
4717 context = context_acquire(This, NULL);
4718 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4720 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4722 context_release(context);
4724 This->inScene = FALSE;
4728 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4729 const RECT *pSourceRect, const RECT *pDestRect,
4730 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4732 IWineD3DSwapChain *swapChain = NULL;
4734 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4736 TRACE("iface %p.\n", iface);
4738 for(i = 0 ; i < swapchains ; i ++) {
4740 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4741 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4742 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4743 IWineD3DSwapChain_Release(swapChain);
4749 /* Do not call while under the GL lock. */
4750 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4751 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4753 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4754 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4757 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4758 iface, rect_count, rects, flags, color, depth, stencil);
4760 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4762 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4763 /* TODO: What about depth stencil buffers without stencil bits? */
4764 return WINED3DERR_INVALIDCALL;
4767 device_get_draw_rect(device, &draw_rect);
4769 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4770 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4777 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4778 WINED3DPRIMITIVETYPE primitive_type)
4780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4784 This->updateStateBlock->changed.primitive_type = TRUE;
4785 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4788 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4789 WINED3DPRIMITIVETYPE *primitive_type)
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4793 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4795 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4797 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4800 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4804 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4806 if (!This->stateBlock->state.vertex_declaration)
4808 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4809 return WINED3DERR_INVALIDCALL;
4812 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4813 if (This->stateBlock->state.user_stream)
4815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4816 This->stateBlock->state.user_stream = FALSE;
4819 if (This->stateBlock->state.load_base_vertex_index)
4821 This->stateBlock->state.load_base_vertex_index = 0;
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4824 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4825 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4829 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4832 struct wined3d_buffer *index_buffer;
4836 index_buffer = This->stateBlock->state.index_buffer;
4839 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4840 * without an index buffer set. (The first time at least...)
4841 * D3D8 simply dies, but I doubt it can do much harm to return
4842 * D3DERR_INVALIDCALL there as well. */
4843 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4844 return WINED3DERR_INVALIDCALL;
4847 if (!This->stateBlock->state.vertex_declaration)
4849 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4850 return WINED3DERR_INVALIDCALL;
4853 if (This->stateBlock->state.user_stream)
4855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4856 This->stateBlock->state.user_stream = FALSE;
4858 vbo = index_buffer->buffer_object;
4860 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4862 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4867 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4869 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4873 drawPrimitive(This, index_count, startIndex, idxStride,
4874 vbo ? NULL : index_buffer->resource.allocatedMemory);
4879 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4880 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4883 struct wined3d_stream_state *stream;
4886 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4887 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4889 if (!This->stateBlock->state.vertex_declaration)
4891 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4892 return WINED3DERR_INVALIDCALL;
4895 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4896 stream = &This->stateBlock->state.streams[0];
4897 vb = (IWineD3DBuffer *)stream->buffer;
4898 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4899 if (vb) IWineD3DBuffer_Release(vb);
4901 stream->stride = VertexStreamZeroStride;
4902 This->stateBlock->state.user_stream = TRUE;
4903 This->stateBlock->state.load_base_vertex_index = 0;
4905 /* TODO: Only mark dirty if drawing from a different UP address */
4906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4908 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4910 /* MSDN specifies stream zero settings must be set to NULL */
4911 stream->buffer = NULL;
4914 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4915 * the new stream sources or use UP drawing again
4920 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4921 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4922 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4926 struct wined3d_stream_state *stream;
4930 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4931 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4933 if (!This->stateBlock->state.vertex_declaration)
4935 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4936 return WINED3DERR_INVALIDCALL;
4939 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4945 stream = &This->stateBlock->state.streams[0];
4946 vb = (IWineD3DBuffer *)stream->buffer;
4947 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4948 if (vb) IWineD3DBuffer_Release(vb);
4950 stream->stride = VertexStreamZeroStride;
4951 This->stateBlock->state.user_stream = TRUE;
4953 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4954 This->stateBlock->state.base_vertex_index = 0;
4955 This->stateBlock->state.load_base_vertex_index = 0;
4956 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4960 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4962 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4963 stream->buffer = NULL;
4965 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4968 IWineD3DBuffer_Release(ib);
4969 This->stateBlock->state.index_buffer = NULL;
4971 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4972 * SetStreamSource to specify a vertex buffer
4978 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4979 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4983 /* Mark the state dirty until we have nicer tracking
4984 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4989 This->stateBlock->state.base_vertex_index = 0;
4990 This->up_strided = DrawPrimStrideData;
4991 drawPrimitive(This, vertex_count, 0, 0, NULL);
4992 This->up_strided = NULL;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4997 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4998 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5001 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5003 /* Mark the state dirty until we have nicer tracking
5004 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5009 This->stateBlock->state.user_stream = TRUE;
5010 This->stateBlock->state.base_vertex_index = 0;
5011 This->up_strided = DrawPrimStrideData;
5012 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5013 This->up_strided = NULL;
5017 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5018 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5019 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5021 WINED3DLOCKED_BOX src;
5022 WINED3DLOCKED_BOX dst;
5025 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5026 iface, pSourceVolume, pDestinationVolume);
5028 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5029 * dirtification to improve loading performance.
5031 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5032 if (FAILED(hr)) return hr;
5033 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5036 IWineD3DVolume_Unmap(pSourceVolume);
5040 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5042 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5044 IWineD3DVolume_Unmap(pSourceVolume);
5046 hr = IWineD3DVolume_Unmap(pSourceVolume);
5051 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5052 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5054 unsigned int level_count, i;
5055 WINED3DRESOURCETYPE type;
5058 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5060 /* Verify that the source and destination textures are non-NULL. */
5061 if (!src_texture || !dst_texture)
5063 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5064 return WINED3DERR_INVALIDCALL;
5067 if (src_texture == dst_texture)
5069 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5070 return WINED3DERR_INVALIDCALL;
5073 /* Verify that the source and destination textures are the same type. */
5074 type = IWineD3DBaseTexture_GetType(src_texture);
5075 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5077 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5078 return WINED3DERR_INVALIDCALL;
5081 /* Check that both textures have the identical numbers of levels. */
5082 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5083 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5085 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5086 return WINED3DERR_INVALIDCALL;
5089 /* Make sure that the destination texture is loaded. */
5090 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5091 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5093 /* Update every surface level of the texture. */
5096 case WINED3DRTYPE_TEXTURE:
5098 IWineD3DSurface *src_surface;
5099 IWineD3DSurface *dst_surface;
5101 for (i = 0; i < level_count; ++i)
5103 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5104 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5105 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5106 IWineD3DSurface_Release(dst_surface);
5107 IWineD3DSurface_Release(src_surface);
5110 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5117 case WINED3DRTYPE_CUBETEXTURE:
5119 IWineD3DSurface *src_surface;
5120 IWineD3DSurface *dst_surface;
5122 for (i = 0; i < level_count * 6; ++i)
5124 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5125 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5126 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5127 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5128 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5129 IWineD3DSurface_Release(dst_surface);
5130 IWineD3DSurface_Release(src_surface);
5133 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5140 case WINED3DRTYPE_VOLUMETEXTURE:
5142 IWineD3DVolume *src_volume;
5143 IWineD3DVolume *dst_volume;
5145 for (i = 0; i < level_count; ++i)
5147 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5148 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5149 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5150 IWineD3DVolume_Release(dst_volume);
5151 IWineD3DVolume_Release(src_volume);
5154 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5162 FIXME("Unsupported texture type %#x.\n", type);
5163 return WINED3DERR_INVALIDCALL;
5169 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5170 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5172 IWineD3DSwapChain *swapchain;
5175 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5177 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5178 if (FAILED(hr)) return hr;
5180 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5181 IWineD3DSwapChain_Release(swapchain);
5186 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5188 IWineD3DBaseTextureImpl *texture;
5191 TRACE("(%p) : %p\n", This, pNumPasses);
5193 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5195 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5197 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5198 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5200 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5202 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5203 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5206 texture = This->stateBlock->state.textures[i];
5207 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5209 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5211 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5214 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5216 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5219 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5220 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5222 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5227 /* return a sensible default */
5230 TRACE("returning D3D_OK\n");
5234 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5238 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5240 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5241 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5242 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5244 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5249 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 PALETTEENTRY **palettes;
5255 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5257 if (PaletteNumber >= MAX_PALETTES) {
5258 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5259 return WINED3DERR_INVALIDCALL;
5262 if (PaletteNumber >= This->NumberOfPalettes) {
5263 NewSize = This->NumberOfPalettes;
5266 } while(PaletteNumber >= NewSize);
5267 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5269 ERR("Out of memory!\n");
5270 return E_OUTOFMEMORY;
5272 This->palettes = palettes;
5273 This->NumberOfPalettes = NewSize;
5276 if (!This->palettes[PaletteNumber]) {
5277 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5278 if (!This->palettes[PaletteNumber]) {
5279 ERR("Out of memory!\n");
5280 return E_OUTOFMEMORY;
5284 for (j = 0; j < 256; ++j) {
5285 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5286 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5287 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5288 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5290 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5291 TRACE("(%p) : returning\n", This);
5295 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5298 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5299 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5300 /* What happens in such situation isn't documented; Native seems to silently abort
5301 on such conditions. Return Invalid Call. */
5302 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5303 return WINED3DERR_INVALIDCALL;
5305 for (j = 0; j < 256; ++j) {
5306 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5307 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5308 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5309 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5311 TRACE("(%p) : returning\n", This);
5315 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5318 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5319 (tested with reference rasterizer). Return Invalid Call. */
5320 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5321 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5322 return WINED3DERR_INVALIDCALL;
5324 /*TODO: stateblocks */
5325 if (This->currentPalette != PaletteNumber) {
5326 This->currentPalette = PaletteNumber;
5327 dirtify_p8_texture_samplers(This);
5329 TRACE("(%p) : returning\n", This);
5333 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 WARN("(%p) : returning Invalid Call\n", This);
5339 return WINED3DERR_INVALIDCALL;
5341 /*TODO: stateblocks */
5342 *PaletteNumber = This->currentPalette;
5343 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5347 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5352 FIXME("(%p) : stub\n", This);
5356 This->softwareVertexProcessing = bSoftware;
5361 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5366 FIXME("(%p) : stub\n", This);
5369 return This->softwareVertexProcessing;
5372 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5373 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5375 IWineD3DSwapChain *swapchain;
5378 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5379 iface, swapchain_idx, raster_status);
5381 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5384 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5388 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5389 IWineD3DSwapChain_Release(swapchain);
5392 WARN("Failed to get raster status, hr %#x.\n", hr);
5399 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5402 if(nSegments != 0.0f) {
5405 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5412 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5417 FIXME("iface %p stub!\n", iface);
5423 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5424 IWineD3DSurface *src_surface, const RECT *src_rect,
5425 IWineD3DSurface *dst_surface, const POINT *dst_point)
5427 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5428 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 const struct wined3d_format *src_format;
5431 const struct wined3d_format *dst_format;
5432 const struct wined3d_gl_info *gl_info;
5433 struct wined3d_context *context;
5434 const unsigned char *data;
5435 UINT update_w, update_h;
5436 CONVERT_TYPES convert;
5440 struct wined3d_format format;
5442 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5443 iface, src_surface, wine_dbgstr_rect(src_rect),
5444 dst_surface, wine_dbgstr_point(dst_point));
5446 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5448 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5449 src_surface, dst_surface);
5450 return WINED3DERR_INVALIDCALL;
5453 src_format = src_impl->resource.format;
5454 dst_format = dst_impl->resource.format;
5456 if (src_format->id != dst_format->id)
5458 WARN("Source and destination surfaces should have the same format.\n");
5459 return WINED3DERR_INVALIDCALL;
5462 dst_x = dst_point ? dst_point->x : 0;
5463 dst_y = dst_point ? dst_point->y : 0;
5465 /* This call loads the OpenGL surface directly, instead of copying the
5466 * surface to the destination's sysmem copy. If surface conversion is
5467 * needed, use BltFast instead to copy in sysmem and use regular surface
5469 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5470 if (convert != NO_CONVERSION || format.convert)
5471 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5473 context = context_acquire(This, NULL);
5474 gl_info = context->gl_info;
5477 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5478 checkGLcall("glActiveTextureARB");
5481 /* Make sure the surface is loaded and up to date */
5482 surface_internal_preload(dst_impl, SRGB_RGB);
5483 surface_bind(dst_impl, FALSE);
5485 src_w = src_impl->currentDesc.Width;
5486 src_h = src_impl->currentDesc.Height;
5487 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5488 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5490 data = src_impl->resource.allocatedMemory;
5491 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5495 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5497 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5498 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5499 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5503 data += (src_rect->top / src_format->block_height) * src_pitch;
5504 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5507 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5508 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5509 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5511 if (row_length == src_pitch)
5513 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5514 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5520 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5521 * can't use the unpack row length like below. */
5522 for (row = 0, y = dst_y; row < row_count; ++row)
5524 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5525 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5526 y += src_format->block_height;
5530 checkGLcall("glCompressedTexSubImage2DARB");
5536 data += src_rect->top * src_w * src_format->byte_count;
5537 data += src_rect->left * src_format->byte_count;
5540 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5541 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5542 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5544 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5545 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5546 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5547 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5548 checkGLcall("glTexSubImage2D");
5552 context_release(context);
5554 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5555 sampler = This->rev_tex_unit_map[0];
5556 if (sampler != WINED3D_UNMAPPED_STAGE)
5558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5564 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5566 struct WineD3DRectPatch *patch;
5567 GLenum old_primitive_type;
5571 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5573 if(!(Handle || pRectPatchInfo)) {
5574 /* TODO: Write a test for the return value, thus the FIXME */
5575 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5576 return WINED3DERR_INVALIDCALL;
5580 i = PATCHMAP_HASHFUNC(Handle);
5582 LIST_FOR_EACH(e, &This->patches[i]) {
5583 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5584 if(patch->Handle == Handle) {
5591 TRACE("Patch does not exist. Creating a new one\n");
5592 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5593 patch->Handle = Handle;
5594 list_add_head(&This->patches[i], &patch->entry);
5596 TRACE("Found existing patch %p\n", patch);
5599 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5600 * attributes we have to tesselate, read back, and draw. This needs a patch
5601 * management structure instance. Create one.
5603 * A possible improvement is to check if a vertex shader is used, and if not directly
5606 FIXME("Drawing an uncached patch. This is slow\n");
5607 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5610 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5611 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5612 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5615 TRACE("Tesselation density or patch info changed, retesselating\n");
5617 if(pRectPatchInfo) {
5618 patch->RectPatchInfo = *pRectPatchInfo;
5620 patch->numSegs[0] = pNumSegs[0];
5621 patch->numSegs[1] = pNumSegs[1];
5622 patch->numSegs[2] = pNumSegs[2];
5623 patch->numSegs[3] = pNumSegs[3];
5625 hr = tesselate_rectpatch(This, patch);
5627 WARN("Patch tesselation failed\n");
5629 /* Do not release the handle to store the params of the patch */
5631 HeapFree(GetProcessHeap(), 0, patch);
5637 This->currentPatch = patch;
5638 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5639 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5640 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5641 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5642 This->currentPatch = NULL;
5644 /* Destroy uncached patches */
5646 HeapFree(GetProcessHeap(), 0, patch->mem);
5647 HeapFree(GetProcessHeap(), 0, patch);
5652 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5653 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5655 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5656 iface, handle, segment_count, patch_info);
5661 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5664 struct WineD3DRectPatch *patch;
5666 TRACE("(%p) Handle(%d)\n", This, Handle);
5668 i = PATCHMAP_HASHFUNC(Handle);
5669 LIST_FOR_EACH(e, &This->patches[i]) {
5670 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5671 if(patch->Handle == Handle) {
5672 TRACE("Deleting patch %p\n", patch);
5673 list_remove(&patch->entry);
5674 HeapFree(GetProcessHeap(), 0, patch->mem);
5675 HeapFree(GetProcessHeap(), 0, patch);
5680 /* TODO: Write a test for the return value */
5681 FIXME("Attempt to destroy nonexistent patch\n");
5682 return WINED3DERR_INVALIDCALL;
5685 /* Do not call while under the GL lock. */
5686 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5687 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5689 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5691 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5692 iface, surface, wine_dbgstr_rect(rect),
5693 color->r, color->g, color->b, color->a);
5695 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5697 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5698 return WINED3DERR_INVALIDCALL;
5701 return surface_color_fill(s, rect, color);
5704 /* Do not call while under the GL lock. */
5705 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5706 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5708 IWineD3DResource *resource;
5711 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5714 ERR("Failed to get resource, hr %#x\n", hr);
5718 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5720 FIXME("Only supported on surface resources\n");
5721 IWineD3DResource_Release(resource);
5725 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5726 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5728 IWineD3DResource_Release(resource);
5731 /* rendertarget and depth stencil functions */
5732 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5733 DWORD render_target_idx, IWineD3DSurface **render_target)
5735 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5737 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5738 iface, render_target_idx, render_target);
5740 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5742 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5743 return WINED3DERR_INVALIDCALL;
5746 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5747 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5749 TRACE("Returning render target %p.\n", *render_target);
5754 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5756 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5758 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5760 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5761 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5762 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5763 IWineD3DSurface_AddRef(*depth_stencil);
5768 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5769 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5771 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5772 IWineD3DSurfaceImpl *prev;
5774 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5775 iface, render_target_idx, render_target, set_viewport);
5777 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5779 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5780 return WINED3DERR_INVALIDCALL;
5783 prev = device->render_targets[render_target_idx];
5784 if (render_target == (IWineD3DSurface *)prev)
5786 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5790 /* Render target 0 can't be set to NULL. */
5791 if (!render_target && !render_target_idx)
5793 WARN("Trying to set render target 0 to NULL.\n");
5794 return WINED3DERR_INVALIDCALL;
5797 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5799 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5800 return WINED3DERR_INVALIDCALL;
5803 if (render_target) IWineD3DSurface_AddRef(render_target);
5804 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5805 /* Release after the assignment, to prevent device_resource_released()
5806 * from seeing the surface as still in use. */
5807 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5809 /* Render target 0 is special. */
5810 if (!render_target_idx && set_viewport)
5812 /* Set the viewport and scissor rectangles, if requested. Tests show
5813 * that stateblock recording is ignored, the change goes directly
5814 * into the primary stateblock. */
5815 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5816 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5817 device->stateBlock->state.viewport.X = 0;
5818 device->stateBlock->state.viewport.Y = 0;
5819 device->stateBlock->state.viewport.MaxZ = 1.0f;
5820 device->stateBlock->state.viewport.MinZ = 0.0f;
5821 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5823 device->stateBlock->state.scissor_rect.top = 0;
5824 device->stateBlock->state.scissor_rect.left = 0;
5825 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5826 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5827 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5833 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5836 IWineD3DSurfaceImpl *tmp;
5838 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5840 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5842 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5846 if (This->depth_stencil)
5848 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5849 || This->depth_stencil->flags & SFLAG_DISCARD)
5851 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5852 This->depth_stencil->currentDesc.Width,
5853 This->depth_stencil->currentDesc.Height);
5854 if (This->depth_stencil == This->onscreen_depth_stencil)
5856 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5857 This->onscreen_depth_stencil = NULL;
5862 tmp = This->depth_stencil;
5863 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5864 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5865 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5867 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5869 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5878 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5879 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5882 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5883 WINED3DLOCKED_RECT lockedRect;
5885 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5886 iface, XHotSpot, YHotSpot, cursor_image);
5888 /* some basic validation checks */
5889 if (This->cursorTexture)
5891 struct wined3d_context *context = context_acquire(This, NULL);
5893 glDeleteTextures(1, &This->cursorTexture);
5895 context_release(context);
5896 This->cursorTexture = 0;
5899 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5900 This->haveHardwareCursor = TRUE;
5902 This->haveHardwareCursor = FALSE;
5906 WINED3DLOCKED_RECT rect;
5908 /* MSDN: Cursor must be A8R8G8B8 */
5909 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5911 WARN("surface %p has an invalid format.\n", cursor_image);
5912 return WINED3DERR_INVALIDCALL;
5915 /* MSDN: Cursor must be smaller than the display mode */
5916 if (s->currentDesc.Width > This->ddraw_width
5917 || s->currentDesc.Height > This->ddraw_height)
5919 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5920 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5921 return WINED3DERR_INVALIDCALL;
5924 if (!This->haveHardwareCursor) {
5925 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5927 /* Do not store the surface's pointer because the application may
5928 * release it after setting the cursor image. Windows doesn't
5929 * addref the set surface, so we can't do this either without
5930 * creating circular refcount dependencies. Copy out the gl texture
5933 This->cursorWidth = s->currentDesc.Width;
5934 This->cursorHeight = s->currentDesc.Height;
5935 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5937 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5938 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5939 struct wined3d_context *context;
5940 char *mem, *bits = rect.pBits;
5941 GLint intfmt = format->glInternal;
5942 GLint gl_format = format->glFormat;
5943 GLint type = format->glType;
5944 INT height = This->cursorHeight;
5945 INT width = This->cursorWidth;
5946 INT bpp = format->byte_count;
5950 /* Reformat the texture memory (pitch and width can be
5952 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5953 for(i = 0; i < height; i++)
5954 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5955 IWineD3DSurface_Unmap(cursor_image);
5957 context = context_acquire(This, NULL);
5961 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5963 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5964 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5967 /* Make sure that a proper texture unit is selected */
5968 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5969 checkGLcall("glActiveTextureARB");
5970 sampler = This->rev_tex_unit_map[0];
5971 if (sampler != WINED3D_UNMAPPED_STAGE)
5973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5975 /* Create a new cursor texture */
5976 glGenTextures(1, &This->cursorTexture);
5977 checkGLcall("glGenTextures");
5978 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5979 checkGLcall("glBindTexture");
5980 /* Copy the bitmap memory into the cursor texture */
5981 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5982 checkGLcall("glTexImage2D");
5983 HeapFree(GetProcessHeap(), 0, mem);
5985 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5987 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5988 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5993 context_release(context);
5997 FIXME("A cursor texture was not returned.\n");
5998 This->cursorTexture = 0;
6003 /* Draw a hardware cursor */
6004 ICONINFO cursorInfo;
6006 /* Create and clear maskBits because it is not needed for
6007 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6009 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6010 (s->currentDesc.Width * s->currentDesc.Height / 8));
6011 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6012 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6013 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
6015 cursorInfo.fIcon = FALSE;
6016 cursorInfo.xHotspot = XHotSpot;
6017 cursorInfo.yHotspot = YHotSpot;
6018 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
6019 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
6020 IWineD3DSurface_Unmap(cursor_image);
6021 /* Create our cursor and clean up. */
6022 cursor = CreateIconIndirect(&cursorInfo);
6024 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6025 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6026 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6027 This->hardwareCursor = cursor;
6028 HeapFree(GetProcessHeap(), 0, maskBits);
6032 This->xHotSpot = XHotSpot;
6033 This->yHotSpot = YHotSpot;
6037 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6038 int XScreenSpace, int YScreenSpace, DWORD flags)
6040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6042 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6043 iface, XScreenSpace, YScreenSpace, flags);
6045 This->xScreenSpace = XScreenSpace;
6046 This->yScreenSpace = YScreenSpace;
6049 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6051 BOOL oldVisible = This->bCursorVisible;
6054 TRACE("(%p) : visible(%d)\n", This, bShow);
6057 * When ShowCursor is first called it should make the cursor appear at the OS's last
6058 * known cursor position. Because of this, some applications just repetitively call
6059 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6062 This->xScreenSpace = pt.x;
6063 This->yScreenSpace = pt.y;
6065 if (This->haveHardwareCursor) {
6066 This->bCursorVisible = bShow;
6068 SetCursor(This->hardwareCursor);
6074 if (This->cursorTexture)
6075 This->bCursorVisible = bShow;
6081 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6082 TRACE("checking resource %p for eviction\n", resource);
6083 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6084 TRACE("Evicting %p\n", resource);
6085 IWineD3DResource_UnLoad(resource);
6087 IWineD3DResource_Release(resource);
6091 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6093 TRACE("iface %p.\n", iface);
6095 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6096 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6097 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6102 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6104 IWineD3DDeviceImpl *device = surface->resource.device;
6105 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6107 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6108 if (surface->flags & SFLAG_DIBSECTION)
6110 /* Release the DC */
6111 SelectObject(surface->hDC, surface->dib.holdbitmap);
6112 DeleteDC(surface->hDC);
6113 /* Release the DIB section */
6114 DeleteObject(surface->dib.DIBsection);
6115 surface->dib.bitmap_data = NULL;
6116 surface->resource.allocatedMemory = NULL;
6117 surface->flags &= ~SFLAG_DIBSECTION;
6119 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6120 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6121 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6122 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6124 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6125 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6127 surface->pow2Width = surface->pow2Height = 1;
6128 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6129 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6132 if (surface->texture_name)
6134 struct wined3d_context *context = context_acquire(device, NULL);
6136 glDeleteTextures(1, &surface->texture_name);
6138 context_release(context);
6139 surface->texture_name = 0;
6140 surface->flags &= ~SFLAG_CLIENT;
6142 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6143 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6145 surface->flags |= SFLAG_NONPOW2;
6149 surface->flags &= ~SFLAG_NONPOW2;
6151 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6152 surface->resource.allocatedMemory = NULL;
6153 surface->resource.heapMemory = NULL;
6154 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6156 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6158 if (!surface_init_sysmem(surface))
6160 return E_OUTOFMEMORY;
6165 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6166 TRACE("Unloading resource %p\n", resource);
6167 IWineD3DResource_UnLoad(resource);
6168 IWineD3DResource_Release(resource);
6172 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6175 WINED3DDISPLAYMODE m;
6178 /* All Windowed modes are supported, as is leaving the current mode */
6179 if(pp->Windowed) return TRUE;
6180 if(!pp->BackBufferWidth) return TRUE;
6181 if(!pp->BackBufferHeight) return TRUE;
6183 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6184 for(i = 0; i < count; i++) {
6185 memset(&m, 0, sizeof(m));
6186 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6188 ERR("EnumAdapterModes failed\n");
6190 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6191 /* Mode found, it is supported */
6195 /* Mode not found -> not supported */
6199 /* Do not call while under the GL lock. */
6200 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6202 const struct wined3d_gl_info *gl_info;
6203 struct wined3d_context *context;
6204 IWineD3DBaseShaderImpl *shader;
6206 context = context_acquire(device, NULL);
6207 gl_info = context->gl_info;
6209 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, reset_unload_resources, NULL);
6210 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6212 device->shader_backend->shader_destroy(shader);
6216 if (device->depth_blt_texture)
6218 glDeleteTextures(1, &device->depth_blt_texture);
6219 device->depth_blt_texture = 0;
6221 if (device->depth_blt_rb)
6223 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6224 device->depth_blt_rb = 0;
6225 device->depth_blt_rb_w = 0;
6226 device->depth_blt_rb_h = 0;
6230 device->blitter->free_private(device);
6231 device->frag_pipe->free_private(device);
6232 device->shader_backend->shader_free_private(device);
6233 destroy_dummy_textures(device, gl_info);
6235 context_release(context);
6237 while (device->numContexts)
6239 context_destroy(device, device->contexts[0]);
6241 HeapFree(GetProcessHeap(), 0, swapchain->context);
6242 swapchain->context = NULL;
6243 swapchain->num_contexts = 0;
6246 /* Do not call while under the GL lock. */
6247 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6249 struct wined3d_context *context;
6251 IWineD3DSurfaceImpl *target;
6253 /* Recreate the primary swapchain's context */
6254 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6255 if (!swapchain->context)
6257 ERR("Failed to allocate memory for swapchain context array.\n");
6258 return E_OUTOFMEMORY;
6261 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6262 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6264 WARN("Failed to create context.\n");
6265 HeapFree(GetProcessHeap(), 0, swapchain->context);
6269 swapchain->context[0] = context;
6270 swapchain->num_contexts = 1;
6271 create_dummy_textures(device);
6272 context_release(context);
6274 hr = device->shader_backend->shader_alloc_private(device);
6277 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6281 hr = device->frag_pipe->alloc_private(device);
6284 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6285 device->shader_backend->shader_free_private(device);
6289 hr = device->blitter->alloc_private(device);
6292 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6293 device->frag_pipe->free_private(device);
6294 device->shader_backend->shader_free_private(device);
6301 context_acquire(device, NULL);
6302 destroy_dummy_textures(device, context->gl_info);
6303 context_release(context);
6304 context_destroy(device, context);
6305 HeapFree(GetProcessHeap(), 0, swapchain->context);
6306 swapchain->num_contexts = 0;
6310 /* Do not call while under the GL lock. */
6311 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6312 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6315 IWineD3DSwapChainImpl *swapchain;
6317 BOOL DisplayModeChanged = FALSE;
6318 WINED3DDISPLAYMODE mode;
6319 TRACE("(%p)\n", This);
6321 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6323 ERR("Failed to get the first implicit swapchain\n");
6327 if(!is_display_mode_supported(This, pPresentationParameters)) {
6328 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6329 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6330 pPresentationParameters->BackBufferHeight);
6331 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6332 return WINED3DERR_INVALIDCALL;
6335 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6336 * on an existing gl context, so there's no real need for recreation.
6338 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6340 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6342 TRACE("New params:\n");
6343 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6344 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6345 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6346 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6347 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6348 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6349 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6350 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6351 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6352 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6353 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6354 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6355 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6357 /* No special treatment of these parameters. Just store them */
6358 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6359 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6360 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6361 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6363 /* What to do about these? */
6364 if (pPresentationParameters->BackBufferCount
6365 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6366 ERR("Cannot change the back buffer count yet\n");
6368 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6369 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6370 ERR("Cannot change the back buffer format yet\n");
6373 if (pPresentationParameters->hDeviceWindow
6374 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6375 ERR("Cannot change the device window yet\n");
6377 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6381 TRACE("Creating the depth stencil buffer\n");
6383 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6384 pPresentationParameters->BackBufferWidth,
6385 pPresentationParameters->BackBufferHeight,
6386 pPresentationParameters->AutoDepthStencilFormat,
6387 pPresentationParameters->MultiSampleType,
6388 pPresentationParameters->MultiSampleQuality,
6390 (IWineD3DSurface **)&This->auto_depth_stencil);
6393 ERR("Failed to create the depth stencil buffer\n");
6394 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6395 return WINED3DERR_INVALIDCALL;
6399 if (This->onscreen_depth_stencil)
6401 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6402 This->onscreen_depth_stencil = NULL;
6405 /* Reset the depth stencil */
6406 if (pPresentationParameters->EnableAutoDepthStencil)
6407 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6409 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6411 TRACE("Resetting stateblock\n");
6412 wined3d_stateblock_decref(This->updateStateBlock);
6413 wined3d_stateblock_decref(This->stateBlock);
6415 delete_opengl_contexts(This, swapchain);
6417 if(pPresentationParameters->Windowed) {
6418 mode.Width = swapchain->orig_width;
6419 mode.Height = swapchain->orig_height;
6420 mode.RefreshRate = 0;
6421 mode.Format = swapchain->presentParms.BackBufferFormat;
6423 mode.Width = pPresentationParameters->BackBufferWidth;
6424 mode.Height = pPresentationParameters->BackBufferHeight;
6425 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6426 mode.Format = swapchain->presentParms.BackBufferFormat;
6429 /* Should Width == 800 && Height == 0 set 800x600? */
6430 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6431 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6432 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6436 if(!pPresentationParameters->Windowed) {
6437 DisplayModeChanged = TRUE;
6439 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6440 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6442 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6445 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6449 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6451 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6454 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6458 if (This->auto_depth_stencil)
6460 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6463 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6469 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6470 || DisplayModeChanged)
6472 BOOL filter = This->filter_messages;
6473 This->filter_messages = TRUE;
6475 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6477 if (!pPresentationParameters->Windowed)
6479 if (swapchain->presentParms.Windowed)
6481 HWND focus_window = This->createParms.hFocusWindow;
6482 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6483 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6485 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6486 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6490 /* switch from windowed to fs */
6491 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6492 pPresentationParameters->BackBufferWidth,
6493 pPresentationParameters->BackBufferHeight);
6497 /* Fullscreen -> fullscreen mode change */
6498 MoveWindow(swapchain->device_window, 0, 0,
6499 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6503 else if (!swapchain->presentParms.Windowed)
6505 /* Fullscreen -> windowed switch */
6506 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6507 IWineD3DDevice_ReleaseFocusWindow(iface);
6509 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6511 This->filter_messages = filter;
6513 else if (!pPresentationParameters->Windowed)
6515 DWORD style = This->style, exStyle = This->exStyle;
6516 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6517 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6518 * Reset to clear up their mess. Guild Wars also loses the device during that.
6522 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6523 pPresentationParameters->BackBufferWidth,
6524 pPresentationParameters->BackBufferHeight);
6525 This->style = style;
6526 This->exStyle = exStyle;
6529 /* Note: No parent needed for initial internal stateblock */
6530 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6531 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6532 else TRACE("Created stateblock %p\n", This->stateBlock);
6533 This->updateStateBlock = This->stateBlock;
6534 wined3d_stateblock_incref(This->updateStateBlock);
6536 stateblock_init_default_state(This->stateBlock);
6538 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6541 GetClientRect(swapchain->win_handle, &client_rect);
6543 if(!swapchain->presentParms.BackBufferCount)
6545 TRACE("Single buffered rendering\n");
6546 swapchain->render_to_fbo = FALSE;
6548 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6549 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6551 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6552 swapchain->presentParms.BackBufferWidth,
6553 swapchain->presentParms.BackBufferHeight,
6554 client_rect.right, client_rect.bottom);
6555 swapchain->render_to_fbo = TRUE;
6559 TRACE("Rendering directly to GL_BACK\n");
6560 swapchain->render_to_fbo = FALSE;
6564 hr = create_primary_opengl_context(This, swapchain);
6565 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6567 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6573 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6575 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6577 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6583 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6585 TRACE("(%p) : pParameters %p\n", This, pParameters);
6587 *pParameters = This->createParms;
6591 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6592 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6594 IWineD3DSwapChain *swapchain;
6596 TRACE("Relaying to swapchain\n");
6598 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6600 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6601 IWineD3DSwapChain_Release(swapchain);
6605 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6606 IWineD3DSwapChain *swapchain;
6608 TRACE("Relaying to swapchain\n");
6610 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6611 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6612 IWineD3DSwapChain_Release(swapchain);
6616 void device_resource_add(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6618 TRACE("device %p, resource %p.\n", device, resource);
6620 list_add_head(&device->resources, &resource->resource.resource_list_entry);
6623 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6625 TRACE("device %p, resource %p.\n", device, resource);
6627 list_remove(&resource->resource.resource_list_entry);
6630 void device_resource_released(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6632 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6635 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6637 context_resource_released(device, resource, type);
6641 case WINED3DRTYPE_SURFACE:
6642 if (!device->d3d_initialized) break;
6644 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6646 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6648 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6649 device->render_targets[i] = NULL;
6653 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6655 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6656 device->depth_stencil = NULL;
6660 case WINED3DRTYPE_TEXTURE:
6661 case WINED3DRTYPE_CUBETEXTURE:
6662 case WINED3DRTYPE_VOLUMETEXTURE:
6663 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6665 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6667 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6668 resource, device->stateBlock, i);
6669 device->stateBlock->state.textures[i] = NULL;
6672 if (device->updateStateBlock != device->stateBlock
6673 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6675 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6676 resource, device->updateStateBlock, i);
6677 device->updateStateBlock->state.textures[i] = NULL;
6682 case WINED3DRTYPE_BUFFER:
6683 for (i = 0; i < MAX_STREAMS; ++i)
6685 if (device->stateBlock
6686 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6688 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6689 resource, device->stateBlock, i);
6690 device->stateBlock->state.streams[i].buffer = NULL;
6693 if (device->updateStateBlock != device->stateBlock
6694 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6696 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6697 resource, device->updateStateBlock, i);
6698 device->updateStateBlock->state.streams[i].buffer = NULL;
6703 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6705 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6706 resource, device->stateBlock);
6707 device->stateBlock->state.index_buffer = NULL;
6710 if (device->updateStateBlock != device->stateBlock
6711 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6713 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6714 resource, device->updateStateBlock);
6715 device->updateStateBlock->state.index_buffer = NULL;
6723 /* Remove the resource from the resourceStore */
6724 device_resource_remove(device, resource);
6726 TRACE("Resource released.\n");
6729 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6731 IWineD3DResourceImpl *resource, *cursor;
6733 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6735 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6736 TRACE("enumerating resource %p\n", resource);
6737 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6738 ret = pCallback((IWineD3DResource *) resource, pData);
6739 if(ret == S_FALSE) {
6740 TRACE("Canceling enumeration\n");
6747 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6750 IWineD3DResourceImpl *resource;
6752 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6754 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6755 if (type == WINED3DRTYPE_SURFACE)
6757 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6759 TRACE("Found surface %p for dc %p.\n", resource, dc);
6760 *surface = (IWineD3DSurface *)resource;
6766 return WINED3DERR_INVALIDCALL;
6769 /**********************************************************
6770 * IWineD3DDevice VTbl follows
6771 **********************************************************/
6773 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6775 /*** IUnknown methods ***/
6776 IWineD3DDeviceImpl_QueryInterface,
6777 IWineD3DDeviceImpl_AddRef,
6778 IWineD3DDeviceImpl_Release,
6779 /*** IWineD3DDevice methods ***/
6780 /*** Creation methods**/
6781 IWineD3DDeviceImpl_CreateBuffer,
6782 IWineD3DDeviceImpl_CreateVertexBuffer,
6783 IWineD3DDeviceImpl_CreateIndexBuffer,
6784 IWineD3DDeviceImpl_CreateStateBlock,
6785 IWineD3DDeviceImpl_CreateSurface,
6786 IWineD3DDeviceImpl_CreateRendertargetView,
6787 IWineD3DDeviceImpl_CreateTexture,
6788 IWineD3DDeviceImpl_CreateVolumeTexture,
6789 IWineD3DDeviceImpl_CreateVolume,
6790 IWineD3DDeviceImpl_CreateCubeTexture,
6791 IWineD3DDeviceImpl_CreateQuery,
6792 IWineD3DDeviceImpl_CreateSwapChain,
6793 IWineD3DDeviceImpl_CreateVertexDeclaration,
6794 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6795 IWineD3DDeviceImpl_CreateVertexShader,
6796 IWineD3DDeviceImpl_CreateGeometryShader,
6797 IWineD3DDeviceImpl_CreatePixelShader,
6798 IWineD3DDeviceImpl_CreatePalette,
6799 /*** Odd functions **/
6800 IWineD3DDeviceImpl_Init3D,
6801 IWineD3DDeviceImpl_InitGDI,
6802 IWineD3DDeviceImpl_Uninit3D,
6803 IWineD3DDeviceImpl_UninitGDI,
6804 IWineD3DDeviceImpl_SetMultithreaded,
6805 IWineD3DDeviceImpl_EvictManagedResources,
6806 IWineD3DDeviceImpl_GetAvailableTextureMem,
6807 IWineD3DDeviceImpl_GetBackBuffer,
6808 IWineD3DDeviceImpl_GetCreationParameters,
6809 IWineD3DDeviceImpl_GetDeviceCaps,
6810 IWineD3DDeviceImpl_GetDirect3D,
6811 IWineD3DDeviceImpl_GetDisplayMode,
6812 IWineD3DDeviceImpl_SetDisplayMode,
6813 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6814 IWineD3DDeviceImpl_GetRasterStatus,
6815 IWineD3DDeviceImpl_GetSwapChain,
6816 IWineD3DDeviceImpl_Reset,
6817 IWineD3DDeviceImpl_SetDialogBoxMode,
6818 IWineD3DDeviceImpl_SetCursorProperties,
6819 IWineD3DDeviceImpl_SetCursorPosition,
6820 IWineD3DDeviceImpl_ShowCursor,
6821 /*** Getters and setters **/
6822 IWineD3DDeviceImpl_SetClipPlane,
6823 IWineD3DDeviceImpl_GetClipPlane,
6824 IWineD3DDeviceImpl_SetClipStatus,
6825 IWineD3DDeviceImpl_GetClipStatus,
6826 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6827 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6828 IWineD3DDeviceImpl_SetDepthStencilSurface,
6829 IWineD3DDeviceImpl_GetDepthStencilSurface,
6830 IWineD3DDeviceImpl_SetGammaRamp,
6831 IWineD3DDeviceImpl_GetGammaRamp,
6832 IWineD3DDeviceImpl_SetIndexBuffer,
6833 IWineD3DDeviceImpl_GetIndexBuffer,
6834 IWineD3DDeviceImpl_SetBaseVertexIndex,
6835 IWineD3DDeviceImpl_GetBaseVertexIndex,
6836 IWineD3DDeviceImpl_SetLight,
6837 IWineD3DDeviceImpl_GetLight,
6838 IWineD3DDeviceImpl_SetLightEnable,
6839 IWineD3DDeviceImpl_GetLightEnable,
6840 IWineD3DDeviceImpl_SetMaterial,
6841 IWineD3DDeviceImpl_GetMaterial,
6842 IWineD3DDeviceImpl_SetNPatchMode,
6843 IWineD3DDeviceImpl_GetNPatchMode,
6844 IWineD3DDeviceImpl_SetPaletteEntries,
6845 IWineD3DDeviceImpl_GetPaletteEntries,
6846 IWineD3DDeviceImpl_SetPixelShader,
6847 IWineD3DDeviceImpl_GetPixelShader,
6848 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6849 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6850 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6851 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6852 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6853 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6854 IWineD3DDeviceImpl_SetRenderState,
6855 IWineD3DDeviceImpl_GetRenderState,
6856 IWineD3DDeviceImpl_SetRenderTarget,
6857 IWineD3DDeviceImpl_GetRenderTarget,
6858 IWineD3DDeviceImpl_SetSamplerState,
6859 IWineD3DDeviceImpl_GetSamplerState,
6860 IWineD3DDeviceImpl_SetScissorRect,
6861 IWineD3DDeviceImpl_GetScissorRect,
6862 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6863 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6864 IWineD3DDeviceImpl_SetStreamSource,
6865 IWineD3DDeviceImpl_GetStreamSource,
6866 IWineD3DDeviceImpl_SetStreamSourceFreq,
6867 IWineD3DDeviceImpl_GetStreamSourceFreq,
6868 IWineD3DDeviceImpl_SetTexture,
6869 IWineD3DDeviceImpl_GetTexture,
6870 IWineD3DDeviceImpl_SetTextureStageState,
6871 IWineD3DDeviceImpl_GetTextureStageState,
6872 IWineD3DDeviceImpl_SetTransform,
6873 IWineD3DDeviceImpl_GetTransform,
6874 IWineD3DDeviceImpl_SetVertexDeclaration,
6875 IWineD3DDeviceImpl_GetVertexDeclaration,
6876 IWineD3DDeviceImpl_SetVertexShader,
6877 IWineD3DDeviceImpl_GetVertexShader,
6878 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6879 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6880 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6881 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6882 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6883 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6884 IWineD3DDeviceImpl_SetViewport,
6885 IWineD3DDeviceImpl_GetViewport,
6886 IWineD3DDeviceImpl_MultiplyTransform,
6887 IWineD3DDeviceImpl_ValidateDevice,
6888 IWineD3DDeviceImpl_ProcessVertices,
6889 /*** State block ***/
6890 IWineD3DDeviceImpl_BeginStateBlock,
6891 IWineD3DDeviceImpl_EndStateBlock,
6892 /*** Scene management ***/
6893 IWineD3DDeviceImpl_BeginScene,
6894 IWineD3DDeviceImpl_EndScene,
6895 IWineD3DDeviceImpl_Present,
6896 IWineD3DDeviceImpl_Clear,
6897 IWineD3DDeviceImpl_ClearRendertargetView,
6899 IWineD3DDeviceImpl_SetPrimitiveType,
6900 IWineD3DDeviceImpl_GetPrimitiveType,
6901 IWineD3DDeviceImpl_DrawPrimitive,
6902 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6903 IWineD3DDeviceImpl_DrawPrimitiveUP,
6904 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6905 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6906 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6907 IWineD3DDeviceImpl_DrawRectPatch,
6908 IWineD3DDeviceImpl_DrawTriPatch,
6909 IWineD3DDeviceImpl_DeletePatch,
6910 IWineD3DDeviceImpl_ColorFill,
6911 IWineD3DDeviceImpl_UpdateTexture,
6912 IWineD3DDeviceImpl_UpdateSurface,
6913 IWineD3DDeviceImpl_GetFrontBufferData,
6914 /*** object tracking ***/
6915 IWineD3DDeviceImpl_EnumResources,
6916 IWineD3DDeviceImpl_GetSurfaceFromDC,
6917 IWineD3DDeviceImpl_AcquireFocusWindow,
6918 IWineD3DDeviceImpl_ReleaseFocusWindow,
6919 IWineD3DDeviceImpl_SetupFullscreenWindow,
6920 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6923 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6924 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6925 IWineD3DDeviceParent *device_parent)
6927 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6928 const struct fragment_pipeline *fragment_pipeline;
6929 struct shader_caps shader_caps;
6930 struct fragment_caps ffp_caps;
6931 WINED3DDISPLAYMODE mode;
6935 device->lpVtbl = &IWineD3DDevice_Vtbl;
6937 device->wined3d = (IWineD3D *)wined3d;
6938 IWineD3D_AddRef(device->wined3d);
6939 device->adapter = wined3d->adapter_count ? adapter : NULL;
6940 device->device_parent = device_parent;
6941 list_init(&device->resources);
6942 list_init(&device->shaders);
6944 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6946 /* Get the initial screen setup for ddraw. */
6947 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6950 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6951 IWineD3D_Release(device->wined3d);
6954 device->ddraw_width = mode.Width;
6955 device->ddraw_height = mode.Height;
6956 device->ddraw_format = mode.Format;
6958 /* Save the creation parameters. */
6959 device->createParms.AdapterOrdinal = adapter_idx;
6960 device->createParms.DeviceType = device_type;
6961 device->createParms.hFocusWindow = focus_window;
6962 device->createParms.BehaviorFlags = flags;
6964 device->devType = device_type;
6965 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6967 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6968 device->shader_backend = adapter->shader_backend;
6970 if (device->shader_backend)
6972 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6973 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6974 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6975 device->vs_clipping = shader_caps.VSClipping;
6977 fragment_pipeline = adapter->fragment_pipe;
6978 device->frag_pipe = fragment_pipeline;
6979 if (fragment_pipeline)
6981 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6982 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6984 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6985 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6988 ERR("Failed to compile state table, hr %#x.\n", hr);
6989 IWineD3D_Release(device->wined3d);
6993 device->blitter = adapter->blitter;
6999 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7000 DWORD rep = This->StateTable[state].representative;
7001 struct wined3d_context *context;
7006 for(i = 0; i < This->numContexts; i++) {
7007 context = This->contexts[i];
7008 if(isStateDirty(context, rep)) continue;
7010 context->dirtyArray[context->numDirtyEntries++] = rep;
7011 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7012 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7013 context->isStateDirty[idx] |= (1 << shift);
7017 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7019 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7020 *width = context->current_rt->pow2Width;
7021 *height = context->current_rt->pow2Height;
7024 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7026 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7027 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7028 * current context's drawable, which is the size of the back buffer of the swapchain
7029 * the active context belongs to. */
7030 *width = swapchain->presentParms.BackBufferWidth;
7031 *height = swapchain->presentParms.BackBufferHeight;
7034 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7035 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7037 if (device->filter_messages)
7039 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7040 window, message, wparam, lparam);
7042 return DefWindowProcW(window, message, wparam, lparam);
7044 return DefWindowProcA(window, message, wparam, lparam);
7047 if (message == WM_DESTROY)
7049 TRACE("unregister window %p.\n", window);
7050 wined3d_unregister_window(window);
7052 if (device->focus_window == window) device->focus_window = NULL;
7053 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7057 return CallWindowProcW(proc, window, message, wparam, lparam);
7059 return CallWindowProcA(proc, window, message, wparam, lparam);