2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->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->streams[element->input_slot].stride;
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
211 data = (BYTE *)buffer;
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((IWineD3DBuffer *)buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
227 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
263 element->usage, element->usage_idx, &idx);
267 idx = element->output_slot;
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
293 stream_info->elements[idx].format = element->format;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
319 if (!(map & 1)) continue;
321 element = &stream_info->elements[i];
322 buffer = This->stateBlock->streams[element->stream_idx].buffer;
323 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
325 /* If PreLoad dropped the buffer object, update the stream info. */
326 if (buffer->buffer_object != element->buffer_object)
328 element->buffer_object = 0;
329 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
333 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
338 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
339 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
341 e->format = wined3d_get_format(gl_info, strided->format);
342 e->stride = strided->dwStride;
343 e->data = strided->lpData;
345 e->buffer_object = 0;
348 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
349 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
353 memset(stream_info, 0, sizeof(*stream_info));
355 if (strided->position.lpData)
356 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
357 if (strided->normal.lpData)
358 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
359 if (strided->diffuse.lpData)
360 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
361 if (strided->specular.lpData)
362 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
364 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
366 if (strided->texCoords[i].lpData)
367 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
368 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
371 stream_info->position_transformed = strided->position_transformed;
373 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
375 if (!stream_info->elements[i].format) continue;
377 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
378 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
380 stream_info->swizzle_map |= 1 << i;
382 stream_info->use_map |= 1 << i;
386 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
388 TRACE("Strided Data:\n");
389 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
406 /* Context activation is done by the caller. */
407 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
409 struct wined3d_stream_info *stream_info = &device->strided_streams;
410 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
411 BOOL vs = stateblock->state.vertex_shader && device->vs_selected_mode != SHADER_NONE;
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, vs, stream_info, &fixup);
427 if (vs && !stream_info->position_transformed)
429 if (stateblock->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(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = stateblock->state.textures[idx])) return;
462 srgb = stateblock->state.sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
471 if (use_vs(stateblock))
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (stateblock->state.vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
480 if (use_ps(stateblock))
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (stateblock->state.pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(stateblock, i);
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 device_preload_texture(stateblock, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
511 ERR("Failed to grow the context array.\n");
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
539 ERR("Context %p doesn't exist in context array.\n", context);
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(¤t_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
617 SetRectEmpty(¤t_rect);
619 IntersectRect(&r, draw_rect, ¤t_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
627 if (EqualRect(&r, ¤t_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1114 ERR("Out of memory\n");
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1183 ERR("Out of memory\n");
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1314 TRACE("Swapchain out of range\n");
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 *ppVertexElements = state.elements;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1517 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1520 ERR("Failed to allocate shader memory.\n");
1521 return E_OUTOFMEMORY;
1524 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1527 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1528 HeapFree(GetProcessHeap(), 0, object);
1532 TRACE("Created vertex shader %p.\n", object);
1533 *ppVertexShader = (IWineD3DVertexShader *)object;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1539 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1540 void *parent, const struct wined3d_parent_ops *parent_ops,
1541 IWineD3DGeometryShader **shader)
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 struct wined3d_geometryshader *object;
1547 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1550 ERR("Failed to allocate shader memory.\n");
1551 return E_OUTOFMEMORY;
1554 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1557 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1558 HeapFree(GetProcessHeap(), 0, object);
1562 TRACE("Created geometry shader %p.\n", object);
1563 *shader = (IWineD3DGeometryShader *)object;
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1569 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1570 void *parent, const struct wined3d_parent_ops *parent_ops,
1571 IWineD3DPixelShader **ppPixelShader)
1573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1574 IWineD3DPixelShaderImpl *object;
1577 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1580 ERR("Failed to allocate shader memory.\n");
1581 return E_OUTOFMEMORY;
1584 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1587 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1588 HeapFree(GetProcessHeap(), 0, object);
1592 TRACE("Created pixel shader %p.\n", object);
1593 *ppPixelShader = (IWineD3DPixelShader *)object;
1598 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1599 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1602 IWineD3DPaletteImpl *object;
1605 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1606 iface, Flags, PalEnt, Palette, parent);
1608 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1611 ERR("Failed to allocate palette memory.\n");
1612 return E_OUTOFMEMORY;
1615 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1618 WARN("Failed to initialize palette, hr %#x.\n", hr);
1619 HeapFree(GetProcessHeap(), 0, object);
1623 TRACE("Created palette %p.\n", object);
1624 *Palette = (IWineD3DPalette *)object;
1629 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1633 HDC dcb = NULL, dcs = NULL;
1634 WINEDDCOLORKEY colorkey;
1636 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1639 GetObjectA(hbm, sizeof(BITMAP), &bm);
1640 dcb = CreateCompatibleDC(NULL);
1642 SelectObject(dcb, hbm);
1646 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1647 * couldn't be loaded
1649 memset(&bm, 0, sizeof(bm));
1654 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1655 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1656 &wined3d_null_parent_ops, &This->logo_surface);
1659 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1664 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1665 if(FAILED(hr)) goto out;
1666 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1667 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1669 colorkey.dwColorSpaceLowValue = 0;
1670 colorkey.dwColorSpaceHighValue = 0;
1671 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1675 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1676 /* Fill the surface with a white color to show that wined3d is there */
1677 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1681 if (dcb) DeleteDC(dcb);
1682 if (hbm) DeleteObject(hbm);
1685 /* Context activation is done by the caller. */
1686 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1688 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1690 /* Under DirectX you can have texture stage operations even if no texture is
1691 bound, whereas opengl will only do texture operations when a valid texture is
1692 bound. We emulate this by creating dummy textures and binding them to each
1693 texture stage, but disable all stages by default. Hence if a stage is enabled
1694 then the default texture will kick in until replaced by a SetTexture call */
1697 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1699 /* The dummy texture does not have client storage backing */
1700 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1701 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1704 for (i = 0; i < gl_info->limits.textures; ++i)
1706 GLubyte white = 255;
1708 /* Make appropriate texture active */
1709 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1710 checkGLcall("glActiveTextureARB");
1712 /* Generate an opengl texture name */
1713 glGenTextures(1, &This->dummyTextureName[i]);
1714 checkGLcall("glGenTextures");
1715 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1717 /* Generate a dummy 2d texture (not using 1d because they cause many
1718 * DRI drivers fall back to sw) */
1719 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1720 checkGLcall("glBindTexture");
1722 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1723 checkGLcall("glTexImage2D");
1726 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1728 /* Reenable because if supported it is enabled by default */
1729 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1730 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1736 /* Context activation is done by the caller. */
1737 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1740 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1741 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1744 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1747 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1749 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1751 if (!wined3d_register_window(window, device))
1753 ERR("Failed to register window %p.\n", window);
1757 device->focus_window = window;
1758 SetForegroundWindow(window);
1763 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1765 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1767 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1768 device->focus_window = NULL;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1772 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1776 IWineD3DSwapChainImpl *swapchain = NULL;
1777 struct wined3d_context *context;
1782 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1784 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1785 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1787 TRACE("(%p) : Creating stateblock\n", This);
1788 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1791 WARN("Failed to create stateblock\n");
1794 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1795 This->updateStateBlock = This->stateBlock;
1796 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1798 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1799 sizeof(*This->render_targets) * gl_info->limits.buffers);
1801 This->NumberOfPalettes = 1;
1802 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1803 if (!This->palettes || !This->render_targets)
1805 ERR("Out of memory!\n");
1809 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1810 if(!This->palettes[0]) {
1811 ERR("Out of memory!\n");
1815 for (i = 0; i < 256; ++i) {
1816 This->palettes[0][i].peRed = 0xFF;
1817 This->palettes[0][i].peGreen = 0xFF;
1818 This->palettes[0][i].peBlue = 0xFF;
1819 This->palettes[0][i].peFlags = 0xFF;
1821 This->currentPalette = 0;
1823 /* Initialize the texture unit mapping to a 1:1 mapping */
1824 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1826 if (state < gl_info->limits.fragment_samplers)
1828 This->texUnitMap[state] = state;
1829 This->rev_tex_unit_map[state] = state;
1831 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1832 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1836 /* Setup the implicit swapchain. This also initializes a context. */
1837 TRACE("Creating implicit swapchain\n");
1838 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1839 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1842 WARN("Failed to create implicit swapchain\n");
1846 This->NumberOfSwapChains = 1;
1847 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1848 if(!This->swapchains) {
1849 ERR("Out of memory!\n");
1852 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1854 if (swapchain->back_buffers && swapchain->back_buffers[0])
1856 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1857 This->render_targets[0] = swapchain->back_buffers[0];
1861 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1862 This->render_targets[0] = swapchain->front_buffer;
1864 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1866 /* Depth Stencil support */
1867 This->depth_stencil = This->auto_depth_stencil;
1868 if (This->depth_stencil)
1869 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1871 hr = This->shader_backend->shader_alloc_private(iface);
1873 TRACE("Shader private data couldn't be allocated\n");
1876 hr = This->frag_pipe->alloc_private(iface);
1878 TRACE("Fragment pipeline private data couldn't be allocated\n");
1881 hr = This->blitter->alloc_private(iface);
1883 TRACE("Blitter private data couldn't be allocated\n");
1887 /* Set up some starting GL setup */
1889 /* Setup all the devices defaults */
1890 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1892 context = context_acquire(This, swapchain->front_buffer);
1894 create_dummy_textures(This);
1898 /* Initialize the current view state */
1899 This->view_ident = 1;
1900 This->contexts[0]->last_was_rhw = 0;
1901 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1902 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1904 switch(wined3d_settings.offscreen_rendering_mode) {
1906 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1909 case ORM_BACKBUFFER:
1911 if (context_get_current()->aux_buffers > 0)
1913 TRACE("Using auxilliary buffer for offscreen rendering\n");
1914 This->offscreenBuffer = GL_AUX0;
1916 TRACE("Using back buffer for offscreen rendering\n");
1917 This->offscreenBuffer = GL_BACK;
1922 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1925 context_release(context);
1927 /* Clear the screen */
1928 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1929 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1932 This->d3d_initialized = TRUE;
1934 if(wined3d_settings.logo) {
1935 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1937 This->highest_dirty_ps_const = 0;
1938 This->highest_dirty_vs_const = 0;
1942 HeapFree(GetProcessHeap(), 0, This->render_targets);
1943 HeapFree(GetProcessHeap(), 0, This->swapchains);
1944 This->NumberOfSwapChains = 0;
1945 if(This->palettes) {
1946 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1947 HeapFree(GetProcessHeap(), 0, This->palettes);
1949 This->NumberOfPalettes = 0;
1951 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1953 if(This->stateBlock) {
1954 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1955 This->stateBlock = NULL;
1957 if (This->blit_priv) {
1958 This->blitter->free_private(iface);
1960 if (This->fragment_priv) {
1961 This->frag_pipe->free_private(iface);
1963 if (This->shader_priv) {
1964 This->shader_backend->shader_free_private(iface);
1969 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1970 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1973 IWineD3DSwapChainImpl *swapchain = NULL;
1976 /* Setup the implicit swapchain */
1977 TRACE("Creating implicit swapchain\n");
1978 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1979 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1982 WARN("Failed to create implicit swapchain\n");
1986 This->NumberOfSwapChains = 1;
1987 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1988 if(!This->swapchains) {
1989 ERR("Out of memory!\n");
1992 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1996 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2000 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2002 IWineD3DResource_UnLoad(resource);
2003 IWineD3DResource_Release(resource);
2007 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2008 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2011 const struct wined3d_gl_info *gl_info;
2012 struct wined3d_context *context;
2015 TRACE("(%p)\n", This);
2017 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2019 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2020 * it was created. Thus make sure a context is active for the glDelete* calls
2022 context = context_acquire(This, NULL);
2023 gl_info = context->gl_info;
2025 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2027 /* Unload resources */
2028 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2030 TRACE("Deleting high order patches\n");
2031 for(i = 0; i < PATCHMAP_SIZE; i++) {
2032 struct list *e1, *e2;
2033 struct WineD3DRectPatch *patch;
2034 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2035 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2036 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2040 /* Delete the mouse cursor texture */
2041 if(This->cursorTexture) {
2043 glDeleteTextures(1, &This->cursorTexture);
2045 This->cursorTexture = 0;
2048 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2049 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2051 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2052 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2055 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2056 * private data, it might contain opengl pointers
2058 if(This->depth_blt_texture) {
2060 glDeleteTextures(1, &This->depth_blt_texture);
2062 This->depth_blt_texture = 0;
2064 if (This->depth_blt_rb) {
2066 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2068 This->depth_blt_rb = 0;
2069 This->depth_blt_rb_w = 0;
2070 This->depth_blt_rb_h = 0;
2073 /* Release the update stateblock */
2074 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2075 if(This->updateStateBlock != This->stateBlock)
2076 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2078 This->updateStateBlock = NULL;
2080 { /* because were not doing proper internal refcounts releasing the primary state block
2081 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2082 to set this->stateBlock = NULL; first */
2083 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2084 This->stateBlock = NULL;
2086 /* Release the stateblock */
2087 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2088 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2092 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2093 This->blitter->free_private(iface);
2094 This->frag_pipe->free_private(iface);
2095 This->shader_backend->shader_free_private(iface);
2097 /* Release the buffers (with sanity checks)*/
2098 if (This->onscreen_depth_stencil)
2100 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2101 This->onscreen_depth_stencil = NULL;
2104 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2105 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2107 if (This->auto_depth_stencil != This->depth_stencil)
2108 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2110 This->depth_stencil = NULL;
2112 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2113 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2115 TRACE("Setting rendertarget to NULL\n");
2116 This->render_targets[0] = NULL;
2118 if (This->auto_depth_stencil)
2120 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2122 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2124 This->auto_depth_stencil = NULL;
2127 context_release(context);
2129 for(i=0; i < This->NumberOfSwapChains; i++) {
2130 TRACE("Releasing the implicit swapchain %d\n", i);
2131 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2132 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2136 HeapFree(GetProcessHeap(), 0, This->swapchains);
2137 This->swapchains = NULL;
2138 This->NumberOfSwapChains = 0;
2140 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2141 HeapFree(GetProcessHeap(), 0, This->palettes);
2142 This->palettes = NULL;
2143 This->NumberOfPalettes = 0;
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 This->render_targets = NULL;
2148 This->d3d_initialized = FALSE;
2153 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2157 for(i=0; i < This->NumberOfSwapChains; i++) {
2158 TRACE("Releasing the implicit swapchain %d\n", i);
2159 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2160 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2164 HeapFree(GetProcessHeap(), 0, This->swapchains);
2165 This->swapchains = NULL;
2166 This->NumberOfSwapChains = 0;
2170 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2171 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2172 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2174 * There is no way to deactivate thread safety once it is enabled.
2176 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2179 /*For now just store the flag(needed in case of ddraw) */
2180 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2183 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2184 const WINED3DDISPLAYMODE* pMode) {
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2191 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2193 /* Resize the screen even without a window:
2194 * The app could have unset it with SetCooperativeLevel, but not called
2195 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2196 * but we don't have any hwnd
2199 memset(&devmode, 0, sizeof(devmode));
2200 devmode.dmSize = sizeof(devmode);
2201 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2202 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2203 devmode.dmPelsWidth = pMode->Width;
2204 devmode.dmPelsHeight = pMode->Height;
2206 devmode.dmDisplayFrequency = pMode->RefreshRate;
2207 if (pMode->RefreshRate)
2208 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2210 /* Only change the mode if necessary */
2211 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2212 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2215 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2216 if (ret != DISP_CHANGE_SUCCESSFUL)
2218 if (devmode.dmDisplayFrequency)
2220 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2221 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2222 devmode.dmDisplayFrequency = 0;
2223 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2225 if(ret != DISP_CHANGE_SUCCESSFUL) {
2226 return WINED3DERR_NOTAVAILABLE;
2230 /* Store the new values */
2231 This->ddraw_width = pMode->Width;
2232 This->ddraw_height = pMode->Height;
2233 This->ddraw_format = pMode->Format;
2235 /* And finally clip mouse to our screen */
2236 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2237 ClipCursor(&clip_rc);
2242 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 *ppD3D = This->wined3d;
2245 TRACE("Returning %p.\n", *ppD3D);
2246 IWineD3D_AddRef(*ppD3D);
2250 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2254 (This->adapter->TextureRam/(1024*1024)),
2255 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2256 /* return simulated texture memory left */
2257 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2261 * Get / Set Stream Source
2263 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2264 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2267 struct wined3d_stream_state *stream;
2268 IWineD3DBuffer *oldSrc;
2270 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2271 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2273 if (StreamNumber >= MAX_STREAMS) {
2274 WARN("Stream out of range %d\n", StreamNumber);
2275 return WINED3DERR_INVALIDCALL;
2276 } else if(OffsetInBytes & 0x3) {
2277 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2278 return WINED3DERR_INVALIDCALL;
2281 stream = &This->updateStateBlock->streams[StreamNumber];
2282 oldSrc = (IWineD3DBuffer *)stream->buffer;
2284 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2286 if (oldSrc == pStreamData
2287 && stream->stride == Stride
2288 && stream->offset == OffsetInBytes)
2290 TRACE("Application is setting the old values over, nothing to do\n");
2294 stream->buffer = (struct wined3d_buffer *)pStreamData;
2297 stream->stride = Stride;
2298 stream->offset = OffsetInBytes;
2301 /* Handle recording of state blocks */
2302 if (This->isRecordingState) {
2303 TRACE("Recording... not performing anything\n");
2304 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2305 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2311 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2312 IWineD3DBuffer_AddRef(pStreamData);
2316 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2317 IWineD3DBuffer_Release(oldSrc);
2320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2325 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2326 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 struct wined3d_stream_state *stream;
2331 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2332 iface, StreamNumber, pStream, pOffset, pStride);
2334 if (StreamNumber >= MAX_STREAMS)
2336 WARN("Stream out of range %d\n", StreamNumber);
2337 return WINED3DERR_INVALIDCALL;
2340 stream = &This->stateBlock->streams[StreamNumber];
2341 *pStream = (IWineD3DBuffer *)stream->buffer;
2342 *pStride = stream->stride;
2343 if (pOffset) *pOffset = stream->offset;
2345 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2350 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 struct wined3d_stream_state *stream;
2353 UINT oldFlags, oldFreq;
2355 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2357 /* Verify input at least in d3d9 this is invalid. */
2358 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2360 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2361 return WINED3DERR_INVALIDCALL;
2363 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2365 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2370 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2374 stream = &This->updateStateBlock->streams[StreamNumber];
2375 oldFlags = stream->flags;
2376 oldFreq = stream->frequency;
2378 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2379 stream->frequency = Divider & 0x7FFFFF;
2381 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2383 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2393 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2395 stream = &This->updateStateBlock->streams[StreamNumber];
2396 *Divider = stream->flags | stream->frequency;
2398 TRACE("Returning %#x.\n", *Divider);
2404 * Get / Set & Multiply Transform
2406 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 /* Most of this routine, comments included copied from ddraw tree initially: */
2410 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2412 /* Handle recording of state blocks */
2413 if (This->isRecordingState) {
2414 TRACE("Recording... not performing anything\n");
2415 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2416 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2421 * If the new matrix is the same as the current one,
2422 * we cut off any further processing. this seems to be a reasonable
2423 * optimization because as was noticed, some apps (warcraft3 for example)
2424 * tend towards setting the same matrix repeatedly for some reason.
2426 * From here on we assume that the new matrix is different, wherever it matters.
2428 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2430 TRACE("The app is setting the same matrix over again\n");
2435 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2439 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2440 where ViewMat = Camera space, WorldMat = world space.
2442 In OpenGL, camera and world space is combined into GL_MODELVIEW
2443 matrix. The Projection matrix stay projection matrix.
2446 /* Capture the times we can just ignore the change for now */
2447 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2448 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2449 /* Handled by the state manager */
2452 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2459 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2460 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2462 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2464 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2466 *matrix = device->stateBlock->state.transforms[state];
2471 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2472 const WINED3DMATRIX *mat = NULL;
2475 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2476 * below means it will be recorded in a state block change, but it
2477 * works regardless where it is recorded.
2478 * If this is found to be wrong, change to StateBlock.
2480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2483 if (State <= HIGHEST_TRANSFORMSTATE)
2485 mat = &This->updateStateBlock->state.transforms[State];
2489 FIXME("Unhandled transform state!!\n");
2492 multiply_matrix(&temp, mat, pMatrix);
2494 /* Apply change via set transform - will reapply to eg. lights this way */
2495 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2501 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2502 you can reference any indexes you want as long as that number max are enabled at any
2503 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2504 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2505 but when recording, just build a chain pretty much of commands to be replayed. */
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2509 struct wined3d_light_info *object = NULL;
2510 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2516 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2520 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2521 return WINED3DERR_INVALIDCALL;
2524 switch(pLight->Type) {
2525 case WINED3DLIGHT_POINT:
2526 case WINED3DLIGHT_SPOT:
2527 case WINED3DLIGHT_PARALLELPOINT:
2528 case WINED3DLIGHT_GLSPOT:
2529 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2532 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2534 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2535 return WINED3DERR_INVALIDCALL;
2539 case WINED3DLIGHT_DIRECTIONAL:
2540 /* Ignores attenuation */
2544 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2545 return WINED3DERR_INVALIDCALL;
2548 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2550 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2551 if(object->OriginalIndex == Index) break;
2556 TRACE("Adding new light\n");
2557 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2559 ERR("Out of memory error when allocating a light\n");
2560 return E_OUTOFMEMORY;
2562 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2563 object->glIndex = -1;
2564 object->OriginalIndex = Index;
2567 /* Initialize the object */
2568 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,
2569 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2570 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2571 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2572 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2573 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2574 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2576 /* Save away the information */
2577 object->OriginalParms = *pLight;
2579 switch (pLight->Type) {
2580 case WINED3DLIGHT_POINT:
2582 object->lightPosn[0] = pLight->Position.x;
2583 object->lightPosn[1] = pLight->Position.y;
2584 object->lightPosn[2] = pLight->Position.z;
2585 object->lightPosn[3] = 1.0f;
2586 object->cutoff = 180.0f;
2590 case WINED3DLIGHT_DIRECTIONAL:
2592 object->lightPosn[0] = -pLight->Direction.x;
2593 object->lightPosn[1] = -pLight->Direction.y;
2594 object->lightPosn[2] = -pLight->Direction.z;
2595 object->lightPosn[3] = 0.0f;
2596 object->exponent = 0.0f;
2597 object->cutoff = 180.0f;
2600 case WINED3DLIGHT_SPOT:
2602 object->lightPosn[0] = pLight->Position.x;
2603 object->lightPosn[1] = pLight->Position.y;
2604 object->lightPosn[2] = pLight->Position.z;
2605 object->lightPosn[3] = 1.0f;
2608 object->lightDirn[0] = pLight->Direction.x;
2609 object->lightDirn[1] = pLight->Direction.y;
2610 object->lightDirn[2] = pLight->Direction.z;
2611 object->lightDirn[3] = 1.0f;
2614 * opengl-ish and d3d-ish spot lights use too different models for the
2615 * light "intensity" as a function of the angle towards the main light direction,
2616 * so we only can approximate very roughly.
2617 * however spot lights are rather rarely used in games (if ever used at all).
2618 * furthermore if still used, probably nobody pays attention to such details.
2620 if (!pLight->Falloff)
2622 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2623 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2624 * will always be 1.0 for both of them, and we don't have to care for the
2625 * rest of the rather complex calculation
2627 object->exponent = 0.0f;
2629 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2630 if (rho < 0.0001f) rho = 0.0001f;
2631 object->exponent = -0.3f/logf(cosf(rho/2));
2633 if (object->exponent > 128.0f)
2635 object->exponent = 128.0f;
2637 object->cutoff = (float) (pLight->Phi*90/M_PI);
2643 FIXME("Unrecognized light type %d\n", pLight->Type);
2646 /* Update the live definitions if the light is currently assigned a glIndex */
2647 if (object->glIndex != -1 && !This->isRecordingState) {
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2655 struct wined3d_light_info *lightInfo = NULL;
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2657 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2659 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2661 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2663 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2664 if(lightInfo->OriginalIndex == Index) break;
2670 TRACE("Light information requested but light not defined\n");
2671 return WINED3DERR_INVALIDCALL;
2674 *pLight = lightInfo->OriginalParms;
2679 * Get / Set Light Enable
2680 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2682 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2684 struct wined3d_light_info *lightInfo = NULL;
2685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2688 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2690 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2692 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2693 if(lightInfo->OriginalIndex == Index) break;
2696 TRACE("Found light: %p\n", lightInfo);
2698 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2701 TRACE("Light enabled requested but light not defined, so defining one!\n");
2702 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2704 /* Search for it again! Should be fairly quick as near head of list */
2705 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2707 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2708 if(lightInfo->OriginalIndex == Index) break;
2713 FIXME("Adding default lights has failed dismally\n");
2714 return WINED3DERR_INVALIDCALL;
2719 if(lightInfo->glIndex != -1) {
2720 if(!This->isRecordingState) {
2721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2724 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2725 lightInfo->glIndex = -1;
2727 TRACE("Light already disabled, nothing to do\n");
2729 lightInfo->enabled = FALSE;
2731 lightInfo->enabled = TRUE;
2732 if (lightInfo->glIndex != -1) {
2734 TRACE("Nothing to do as light was enabled\n");
2737 /* Find a free gl light */
2738 for (i = 0; i < This->maxConcurrentLights; ++i)
2740 if (!This->updateStateBlock->activeLights[i])
2742 This->updateStateBlock->activeLights[i] = lightInfo;
2743 lightInfo->glIndex = i;
2747 if(lightInfo->glIndex == -1) {
2748 /* Our tests show that Windows returns D3D_OK in this situation, even with
2749 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2750 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2751 * as well for those lights.
2753 * TODO: Test how this affects rendering
2755 WARN("Too many concurrently active lights\n");
2759 /* i == lightInfo->glIndex */
2760 if(!This->isRecordingState) {
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2769 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2771 struct wined3d_light_info *lightInfo = NULL;
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2774 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2775 TRACE("(%p) : for idx(%d)\n", This, Index);
2777 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2779 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2780 if(lightInfo->OriginalIndex == Index) break;
2786 TRACE("Light enabled state requested but light not defined\n");
2787 return WINED3DERR_INVALIDCALL;
2789 /* true is 128 according to SetLightEnable */
2790 *pEnable = lightInfo->enabled ? 128 : 0;
2795 * Get / Set Clip Planes
2797 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2801 /* Validate Index */
2802 if (Index >= This->adapter->gl_info.limits.clipplanes)
2804 TRACE("Application has requested clipplane this device doesn't support\n");
2805 return WINED3DERR_INVALIDCALL;
2808 This->updateStateBlock->changed.clipplane |= 1 << Index;
2810 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2811 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2812 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2813 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2814 TRACE("Application is setting old values over, nothing to do\n");
2818 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2819 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2820 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2821 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2823 /* Handle recording of state blocks */
2824 if (This->isRecordingState) {
2825 TRACE("Recording... not performing anything\n");
2829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2834 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2836 TRACE("(%p) : for idx %d\n", This, Index);
2838 /* Validate Index */
2839 if (Index >= This->adapter->gl_info.limits.clipplanes)
2841 TRACE("Application has requested clipplane this device doesn't support\n");
2842 return WINED3DERR_INVALIDCALL;
2845 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2846 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2847 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2848 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2853 * Get / Set Clip Plane Status
2854 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2856 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 FIXME("(%p) : stub\n", This);
2861 return WINED3DERR_INVALIDCALL;
2863 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2864 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2868 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 FIXME("(%p) : stub\n", This);
2873 return WINED3DERR_INVALIDCALL;
2875 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2876 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2881 * Get / Set Material
2883 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 This->updateStateBlock->changed.material = TRUE;
2887 This->updateStateBlock->state.material = *pMaterial;
2889 /* Handle recording of state blocks */
2890 if (This->isRecordingState) {
2891 TRACE("Recording... not performing anything\n");
2895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2899 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 *pMaterial = This->updateStateBlock->state.material;
2902 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2903 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2904 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2905 pMaterial->Ambient.b, pMaterial->Ambient.a);
2906 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2907 pMaterial->Specular.b, pMaterial->Specular.a);
2908 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2909 pMaterial->Emissive.b, pMaterial->Emissive.a);
2910 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2918 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2919 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 IWineD3DBuffer *oldIdxs;
2924 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2925 oldIdxs = This->updateStateBlock->pIndexData;
2927 This->updateStateBlock->changed.indices = TRUE;
2928 This->updateStateBlock->pIndexData = pIndexData;
2929 This->updateStateBlock->IndexFmt = fmt;
2931 /* Handle recording of state blocks */
2932 if (This->isRecordingState) {
2933 TRACE("Recording... not performing anything\n");
2934 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2935 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2939 if(oldIdxs != pIndexData) {
2940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2942 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2943 IWineD3DBuffer_AddRef(pIndexData);
2946 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2947 IWineD3DBuffer_Release(oldIdxs);
2954 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 *ppIndexData = This->stateBlock->pIndexData;
2960 /* up ref count on ppindexdata */
2962 IWineD3DBuffer_AddRef(*ppIndexData);
2963 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2965 TRACE("(%p) No index data set\n", This);
2967 TRACE("Returning %p\n", *ppIndexData);
2972 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2973 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 TRACE("(%p)->(%d)\n", This, BaseIndex);
2977 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2978 TRACE("Application is setting the old value over, nothing to do\n");
2982 This->updateStateBlock->baseVertexIndex = BaseIndex;
2984 if (This->isRecordingState) {
2985 TRACE("Recording... not performing anything\n");
2988 /* The base vertex index affects the stream sources */
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 TRACE("(%p) : base_index %p\n", This, base_index);
2997 *base_index = This->stateBlock->baseVertexIndex;
2999 TRACE("Returning %u\n", *base_index);
3005 * Get / Set Viewports
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 TRACE("(%p)\n", This);
3011 This->updateStateBlock->changed.viewport = TRUE;
3012 This->updateStateBlock->state.viewport = *pViewport;
3014 /* Handle recording of state blocks */
3015 if (This->isRecordingState) {
3016 TRACE("Recording... not performing anything\n");
3020 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3021 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 TRACE("(%p)\n", This);
3031 *pViewport = This->stateBlock->state.viewport;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3036 WINED3DRENDERSTATETYPE State, DWORD Value)
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 DWORD oldValue = This->stateBlock->state.render_states[State];
3041 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3043 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3044 This->updateStateBlock->state.render_states[State] = Value;
3046 /* Handle recording of state blocks */
3047 if (This->isRecordingState) {
3048 TRACE("Recording... not performing anything\n");
3052 /* Compared here and not before the assignment to allow proper stateblock recording */
3053 if(Value == oldValue) {
3054 TRACE("Application is setting the old value over, nothing to do\n");
3056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3062 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3063 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3069 *pValue = This->stateBlock->state.render_states[State];
3074 * Get / Set Sampler States
3075 * TODO: Verify against dx9 definitions
3078 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3083 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3085 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3086 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3089 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3091 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3092 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3095 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3096 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3097 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3099 /* Handle recording of state blocks */
3100 if (This->isRecordingState) {
3101 TRACE("Recording... not performing anything\n");
3105 if(oldValue == Value) {
3106 TRACE("Application is setting the old value over, nothing to do\n");
3110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3115 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3119 This, Sampler, debug_d3dsamplerstate(Type), Type);
3121 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3122 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3125 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3127 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3128 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3130 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3131 TRACE("(%p) : Returning %#x\n", This, *Value);
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 This->updateStateBlock->changed.scissorRect = TRUE;
3140 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3142 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3145 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3147 if(This->isRecordingState) {
3148 TRACE("Recording... not performing anything\n");
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3157 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 *pRect = This->updateStateBlock->state.scissor_rect;
3161 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3165 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3167 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3169 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3171 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3172 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3174 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3175 This->updateStateBlock->changed.vertexDecl = TRUE;
3177 if (This->isRecordingState) {
3178 TRACE("Recording... not performing anything\n");
3180 } else if(pDecl == oldDecl) {
3181 /* Checked after the assignment to allow proper stateblock recording */
3182 TRACE("Application is setting the old declaration over, nothing to do\n");
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3195 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3196 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3205 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3206 This->updateStateBlock->changed.vertexShader = TRUE;
3208 if (This->isRecordingState) {
3209 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3210 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3211 TRACE("Recording... not performing anything\n");
3213 } else if(oldShader == pShader) {
3214 /* Checked here to allow proper stateblock recording */
3215 TRACE("App is setting the old shader over, nothing to do\n");
3219 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3220 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3221 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3228 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3230 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3231 IWineD3DVertexShader *shader;
3233 TRACE("iface %p.\n", iface);
3235 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3236 if (shader) IWineD3DVertexShader_AddRef(shader);
3238 TRACE("Returning %p.\n", shader);
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3243 IWineD3DDevice *iface,
3245 CONST BOOL *srcData,
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3251 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3252 iface, srcData, start, count);
3254 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3256 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3257 for (i = 0; i < cnt; i++)
3258 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3260 for (i = start; i < cnt + start; ++i) {
3261 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3264 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3269 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3270 IWineD3DDevice *iface,
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 int cnt = min(count, MAX_CONST_B - start);
3278 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3279 iface, dstData, start, count);
3281 if (!dstData || cnt < 0)
3282 return WINED3DERR_INVALIDCALL;
3284 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3289 IWineD3DDevice *iface,
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3297 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3298 iface, srcData, start, count);
3300 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3302 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3303 for (i = 0; i < cnt; i++)
3304 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3305 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3307 for (i = start; i < cnt + start; ++i) {
3308 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3311 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3317 IWineD3DDevice *iface,
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 int cnt = min(count, MAX_CONST_I - start);
3325 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326 iface, dstData, start, count);
3328 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3329 return WINED3DERR_INVALIDCALL;
3331 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3336 IWineD3DDevice *iface,
3338 CONST float *srcData,
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3345 iface, srcData, start, count);
3347 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3348 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3349 return WINED3DERR_INVALIDCALL;
3351 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3353 for (i = 0; i < count; i++)
3354 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3355 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3358 if (!This->isRecordingState)
3360 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3364 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3365 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3371 IWineD3DDevice *iface,
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 int cnt = min(count, This->d3d_vshader_constantF - start);
3379 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3380 iface, dstData, start, count);
3382 if (!dstData || cnt < 0)
3383 return WINED3DERR_INVALIDCALL;
3385 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3389 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3391 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3397 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3399 DWORD i = This->rev_tex_unit_map[unit];
3400 DWORD j = This->texUnitMap[stage];
3402 This->texUnitMap[stage] = unit;
3403 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3405 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3408 This->rev_tex_unit_map[unit] = stage;
3409 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3411 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3415 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3418 This->fixed_function_usage_map = 0;
3419 for (i = 0; i < MAX_TEXTURES; ++i)
3421 const struct wined3d_state *state = &This->stateBlock->state;
3422 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3423 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3424 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3425 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3426 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3427 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3428 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3429 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3431 if (color_op == WINED3DTOP_DISABLE) {
3432 /* Not used, and disable higher stages */
3436 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3437 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3438 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3439 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3440 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3441 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3442 This->fixed_function_usage_map |= (1 << i);
3445 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3446 This->fixed_function_usage_map |= (1 << (i + 1));
3451 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3453 unsigned int i, tex;
3456 device_update_fixed_function_usage_map(This);
3457 ffu_map = This->fixed_function_usage_map;
3459 if (This->max_ffp_textures == gl_info->limits.texture_stages
3460 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3462 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3464 if (!(ffu_map & 1)) continue;
3466 if (This->texUnitMap[i] != i) {
3467 device_map_stage(This, i, i);
3468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3469 markTextureStagesDirty(This, i);
3475 /* Now work out the mapping */
3477 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3479 if (!(ffu_map & 1)) continue;
3481 if (This->texUnitMap[i] != tex) {
3482 device_map_stage(This, i, tex);
3483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3484 markTextureStagesDirty(This, i);
3491 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3493 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3494 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3497 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3498 if (sampler_type[i] && This->texUnitMap[i] != i)
3500 device_map_stage(This, i, i);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 if (i < gl_info->limits.texture_stages)
3504 markTextureStagesDirty(This, i);
3510 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3511 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3513 DWORD current_mapping = This->rev_tex_unit_map[unit];
3515 /* Not currently used */
3516 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3518 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3519 /* Used by a fragment sampler */
3521 if (!pshader_sampler_tokens) {
3522 /* No pixel shader, check fixed function */
3523 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3526 /* Pixel shader, check the shader's sampler map */
3527 return !pshader_sampler_tokens[current_mapping];
3530 /* Used by a vertex sampler */
3531 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3534 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3536 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3537 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3538 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3539 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3544 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3546 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3547 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3548 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3551 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3552 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3553 if (vshader_sampler_type[i])
3555 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3557 /* Already mapped somewhere */
3561 while (start >= 0) {
3562 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3564 device_map_stage(This, vsampler_idx, start);
3565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3577 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3579 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3580 BOOL vs = use_vs(This->stateBlock);
3581 BOOL ps = use_ps(This->stateBlock);
3584 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3585 * that would be really messy and require shader recompilation
3586 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3587 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3589 if (ps) device_map_psamplers(This, gl_info);
3590 else device_map_fixed_function_samplers(This, gl_info);
3592 if (vs) device_map_vsamplers(This, ps, gl_info);
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3598 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3599 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3600 This->updateStateBlock->changed.pixelShader = TRUE;
3602 /* Handle recording of state blocks */
3603 if (This->isRecordingState) {
3604 TRACE("Recording... not performing anything\n");
3607 if (This->isRecordingState) {
3608 TRACE("Recording... not performing anything\n");
3609 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3610 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3614 if(pShader == oldShader) {
3615 TRACE("App is setting the old pixel shader over, nothing to do\n");
3619 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3620 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3622 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3628 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3630 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3631 IWineD3DPixelShader *shader;
3633 TRACE("iface %p.\n", iface);
3635 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3636 if (shader) IWineD3DPixelShader_AddRef(shader);
3638 TRACE("Returning %p.\n", shader);
3642 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3643 IWineD3DDevice *iface,
3645 CONST BOOL *srcData,
3648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3649 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3651 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3652 iface, srcData, start, count);
3654 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3656 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3657 for (i = 0; i < cnt; i++)
3658 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3660 for (i = start; i < cnt + start; ++i) {
3661 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3664 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3669 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3670 IWineD3DDevice *iface,
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 int cnt = min(count, MAX_CONST_B - start);
3678 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3679 iface, dstData, start, count);
3681 if (!dstData || cnt < 0)
3682 return WINED3DERR_INVALIDCALL;
3684 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3688 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3689 IWineD3DDevice *iface,
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3697 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3698 iface, srcData, start, count);
3700 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3702 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3703 for (i = 0; i < cnt; i++)
3704 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3705 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3707 for (i = start; i < cnt + start; ++i) {
3708 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3711 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3716 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3717 IWineD3DDevice *iface,
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3723 int cnt = min(count, MAX_CONST_I - start);
3725 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3726 iface, dstData, start, count);
3728 if (!dstData || cnt < 0)
3729 return WINED3DERR_INVALIDCALL;
3731 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3735 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3736 IWineD3DDevice *iface,
3738 CONST float *srcData,
3741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3744 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3745 iface, srcData, start, count);
3747 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3748 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3749 return WINED3DERR_INVALIDCALL;
3751 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3753 for (i = 0; i < count; i++)
3754 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3755 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3758 if (!This->isRecordingState)
3760 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3764 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3765 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3770 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3771 IWineD3DDevice *iface,
3776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3777 int cnt = min(count, This->d3d_pshader_constantF - start);
3779 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3780 iface, dstData, start, count);
3782 if (!dstData || cnt < 0)
3783 return WINED3DERR_INVALIDCALL;
3785 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3789 /* Context activation is done by the caller. */
3790 /* Do not call while under the GL lock. */
3791 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3792 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3793 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3796 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3797 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3800 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3804 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3806 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3809 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3811 ERR("Source has no position mask\n");
3812 return WINED3DERR_INVALIDCALL;
3815 if (!dest->resource.allocatedMemory)
3816 buffer_get_sysmem(dest, gl_info);
3818 /* Get a pointer into the destination vbo(create one if none exists) and
3819 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3821 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3823 dest->flags |= WINED3D_BUFFER_CREATEBO;
3824 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3827 if (dest->buffer_object)
3829 unsigned char extrabytes = 0;
3830 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3831 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3832 * this may write 4 extra bytes beyond the area that should be written
3834 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3835 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3836 if(!dest_conv_addr) {
3837 ERR("Out of memory\n");
3838 /* Continue without storing converted vertices */
3840 dest_conv = dest_conv_addr;
3843 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3845 static BOOL warned = FALSE;
3847 * The clipping code is not quite correct. Some things need
3848 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3849 * so disable clipping for now.
3850 * (The graphics in Half-Life are broken, and my processvertices
3851 * test crashes with IDirect3DDevice3)
3857 FIXME("Clipping is broken and disabled for now\n");
3859 } else doClip = FALSE;
3860 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3862 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3865 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3866 WINED3DTS_PROJECTION,
3868 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3869 WINED3DTS_WORLDMATRIX(0),
3872 TRACE("View mat:\n");
3873 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);
3874 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);
3875 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);
3876 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);
3878 TRACE("Proj mat:\n");
3879 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);
3880 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);
3881 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);
3882 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);
3884 TRACE("World mat:\n");
3885 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);
3886 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);
3887 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);
3888 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);
3890 /* Get the viewport */
3891 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3892 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3893 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3895 multiply_matrix(&mat,&view_mat,&world_mat);
3896 multiply_matrix(&mat,&proj_mat,&mat);
3898 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3900 for (i = 0; i < dwCount; i+= 1) {
3901 unsigned int tex_index;
3903 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3904 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3905 /* The position first */
3906 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3907 const float *p = (const float *)(element->data + i * element->stride);
3909 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3911 /* Multiplication with world, view and projection matrix */
3912 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);
3913 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);
3914 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);
3915 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);
3917 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3919 /* WARNING: The following things are taken from d3d7 and were not yet checked
3920 * against d3d8 or d3d9!
3923 /* Clipping conditions: From msdn
3925 * A vertex is clipped if it does not match the following requirements
3929 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3931 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3932 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3937 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3938 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3941 /* "Normal" viewport transformation (not clipped)
3942 * 1) The values are divided by rhw
3943 * 2) The y axis is negative, so multiply it with -1
3944 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3945 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3946 * 4) Multiply x with Width/2 and add Width/2
3947 * 5) The same for the height
3948 * 6) Add the viewpoint X and Y to the 2D coordinates and
3949 * The minimum Z value to z
3950 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3952 * Well, basically it's simply a linear transformation into viewport
3964 z *= vp.MaxZ - vp.MinZ;
3966 x += vp.Width / 2 + vp.X;
3967 y += vp.Height / 2 + vp.Y;
3972 /* That vertex got clipped
3973 * Contrary to OpenGL it is not dropped completely, it just
3974 * undergoes a different calculation.
3976 TRACE("Vertex got clipped\n");
3983 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3984 * outside of the main vertex buffer memory. That needs some more
3989 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3992 ( (float *) dest_ptr)[0] = x;
3993 ( (float *) dest_ptr)[1] = y;
3994 ( (float *) dest_ptr)[2] = z;
3995 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3997 dest_ptr += 3 * sizeof(float);
3999 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4000 dest_ptr += sizeof(float);
4005 ( (float *) dest_conv)[0] = x * w;
4006 ( (float *) dest_conv)[1] = y * w;
4007 ( (float *) dest_conv)[2] = z * w;
4008 ( (float *) dest_conv)[3] = w;
4010 dest_conv += 3 * sizeof(float);
4012 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4013 dest_conv += sizeof(float);
4017 if (DestFVF & WINED3DFVF_PSIZE) {
4018 dest_ptr += sizeof(DWORD);
4019 if(dest_conv) dest_conv += sizeof(DWORD);
4021 if (DestFVF & WINED3DFVF_NORMAL) {
4022 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4023 const float *normal = (const float *)(element->data + i * element->stride);
4024 /* AFAIK this should go into the lighting information */
4025 FIXME("Didn't expect the destination to have a normal\n");
4026 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4028 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4032 if (DestFVF & WINED3DFVF_DIFFUSE) {
4033 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4034 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4035 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4037 static BOOL warned = FALSE;
4040 ERR("No diffuse color in source, but destination has one\n");
4044 *( (DWORD *) dest_ptr) = 0xffffffff;
4045 dest_ptr += sizeof(DWORD);
4048 *( (DWORD *) dest_conv) = 0xffffffff;
4049 dest_conv += sizeof(DWORD);
4053 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4055 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4056 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4057 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4058 dest_conv += sizeof(DWORD);
4063 if (DestFVF & WINED3DFVF_SPECULAR)
4065 /* What's the color value in the feedback buffer? */
4066 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4067 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4068 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4070 static BOOL warned = FALSE;
4073 ERR("No specular color in source, but destination has one\n");
4077 *( (DWORD *) dest_ptr) = 0xFF000000;
4078 dest_ptr += sizeof(DWORD);
4081 *( (DWORD *) dest_conv) = 0xFF000000;
4082 dest_conv += sizeof(DWORD);
4086 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4088 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4089 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4090 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4091 dest_conv += sizeof(DWORD);
4096 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4097 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4098 const float *tex_coord = (const float *)(element->data + i * element->stride);
4099 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4101 ERR("No source texture, but destination requests one\n");
4102 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4103 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4106 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4108 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4118 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4119 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4120 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4121 dwCount * get_flexible_vertex_size(DestFVF),
4123 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4127 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4132 #undef copy_and_next
4134 /* Do not call while under the GL lock. */
4135 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4136 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4140 struct wined3d_stream_info stream_info;
4141 const struct wined3d_gl_info *gl_info;
4142 struct wined3d_context *context;
4143 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4146 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4149 ERR("Output vertex declaration not implemented yet\n");
4152 /* Need any context to write to the vbo. */
4153 context = context_acquire(This, NULL);
4154 gl_info = context->gl_info;
4156 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4157 * control the streamIsUP flag, thus restore it afterwards.
4159 This->stateBlock->streamIsUP = FALSE;
4160 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4161 This->stateBlock->streamIsUP = streamWasUP;
4163 if(vbo || SrcStartIndex) {
4165 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4166 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4168 * Also get the start index in, but only loop over all elements if there's something to add at all.
4170 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4172 struct wined3d_stream_info_element *e;
4174 if (!(stream_info.use_map & (1 << i))) continue;
4176 e = &stream_info.elements[i];
4177 if (e->buffer_object)
4179 struct wined3d_buffer *vb = This->stateBlock->streams[e->stream_idx].buffer;
4180 e->buffer_object = 0;
4181 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4183 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4184 vb->buffer_object = 0;
4187 if (e->data) e->data += e->stride * SrcStartIndex;
4191 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4192 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4194 context_release(context);
4200 * Get / Set Texture Stage States
4201 * TODO: Verify against dx9 definitions
4203 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4206 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4209 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4211 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4213 WARN("Invalid Type %d passed.\n", Type);
4217 if (Stage >= gl_info->limits.texture_stages)
4219 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4220 Stage, gl_info->limits.texture_stages - 1);
4224 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4225 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4226 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4228 if (This->isRecordingState) {
4229 TRACE("Recording... not performing anything\n");
4233 /* Checked after the assignments to allow proper stateblock recording */
4234 if(oldValue == Value) {
4235 TRACE("App is setting the old value over, nothing to do\n");
4239 if (Stage > This->stateBlock->state.lowest_disabled_stage
4240 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4241 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4243 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4244 * Changes in other states are important on disabled stages too
4249 if(Type == WINED3DTSS_COLOROP) {
4252 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4253 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4254 * they have to be disabled
4256 * The current stage is dirtified below.
4258 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4260 TRACE("Additionally dirtifying stage %u\n", i);
4261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4263 This->stateBlock->state.lowest_disabled_stage = Stage;
4264 TRACE("New lowest disabled: %u\n", Stage);
4265 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4266 /* Previously disabled stage enabled. Stages above it may need enabling
4267 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4268 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4270 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4273 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4275 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4277 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4280 This->stateBlock->state.lowest_disabled_stage = i;
4281 TRACE("New lowest disabled: %u\n", i);
4285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4290 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4294 TRACE("iface %p, stage %u, state %s, value %p.\n",
4295 iface, Stage, debug_d3dtexturestate(Type), pValue);
4297 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4299 WARN("Invalid Type %d passed.\n", Type);
4303 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4304 TRACE("Returning %#x.\n", *pValue);
4312 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4313 DWORD stage, IWineD3DBaseTexture *texture)
4315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4316 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4317 IWineD3DBaseTexture *prev;
4319 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4321 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4322 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4324 /* Windows accepts overflowing this array... we do not. */
4325 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4327 WARN("Ignoring invalid stage %u.\n", stage);
4331 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4332 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4334 WARN("Rejecting attempt to set scratch texture.\n");
4335 return WINED3DERR_INVALIDCALL;
4338 This->updateStateBlock->changed.textures |= 1 << stage;
4340 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4341 TRACE("Previous texture %p.\n", prev);
4343 if (texture == prev)
4345 TRACE("App is setting the same texture again, nothing to do.\n");
4349 TRACE("Setting new texture to %p.\n", texture);
4350 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4352 if (This->isRecordingState)
4354 TRACE("Recording... not performing anything\n");
4356 if (texture) IWineD3DBaseTexture_AddRef(texture);
4357 if (prev) IWineD3DBaseTexture_Release(prev);
4364 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4365 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4366 GLenum dimensions = t->baseTexture.target;
4368 IWineD3DBaseTexture_AddRef(texture);
4370 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4373 if (!prev && stage < gl_info->limits.texture_stages)
4375 /* The source arguments for color and alpha ops have different
4376 * meanings when a NULL texture is bound, so the COLOROP and
4377 * ALPHAOP have to be dirtified. */
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4382 if (bind_count == 1) t->baseTexture.sampler = stage;
4387 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4388 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4390 IWineD3DBaseTexture_Release(prev);
4392 if (!texture && stage < gl_info->limits.texture_stages)
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4398 if (bind_count && t->baseTexture.sampler == stage)
4402 /* Search for other stages the texture is bound to. Shouldn't
4403 * happen if applications bind textures to a single stage only. */
4404 TRACE("Searching for other stages the texture is bound to.\n");
4405 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4407 if (This->updateStateBlock->state.textures[i] == t)
4409 TRACE("Texture is also bound to stage %u.\n", i);
4410 t->baseTexture.sampler = i;
4417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4422 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4427 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4428 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4431 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4433 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4434 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4437 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4439 IWineD3DBaseTexture_AddRef(*ppTexture);
4441 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4449 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4450 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4452 IWineD3DSwapChain *swapchain;
4455 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4456 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4458 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4461 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4465 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4466 IWineD3DSwapChain_Release(swapchain);
4469 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4476 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 WARN("(%p) : stub, calling idirect3d for now\n", This);
4479 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4482 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 IWineD3DSwapChain *swapChain;
4487 if(iSwapChain > 0) {
4488 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4489 if (hr == WINED3D_OK) {
4490 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4491 IWineD3DSwapChain_Release(swapChain);
4493 FIXME("(%p) Error getting display mode\n", This);
4496 /* Don't read the real display mode,
4497 but return the stored mode instead. X11 can't change the color
4498 depth, and some apps are pretty angry if they SetDisplayMode from
4499 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4501 Also don't relay to the swapchain because with ddraw it's possible
4502 that there isn't a swapchain at all */
4503 pMode->Width = This->ddraw_width;
4504 pMode->Height = This->ddraw_height;
4505 pMode->Format = This->ddraw_format;
4506 pMode->RefreshRate = 0;
4514 * Stateblock related functions
4517 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 IWineD3DStateBlock *stateblock;
4522 TRACE("(%p)\n", This);
4524 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4526 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4527 if (FAILED(hr)) return hr;
4529 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4530 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4531 This->isRecordingState = TRUE;
4533 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4538 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4542 if (!This->isRecordingState) {
4543 WARN("(%p) not recording! returning error\n", This);
4544 *ppStateBlock = NULL;
4545 return WINED3DERR_INVALIDCALL;
4548 stateblock_init_contained_states(object);
4550 *ppStateBlock = (IWineD3DStateBlock*) object;
4551 This->isRecordingState = FALSE;
4552 This->updateStateBlock = This->stateBlock;
4553 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4554 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4555 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4560 * Scene related functions
4562 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4563 /* At the moment we have no need for any functionality at the beginning
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p)\n", This);
4569 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4570 return WINED3DERR_INVALIDCALL;
4572 This->inScene = TRUE;
4576 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 struct wined3d_context *context;
4581 TRACE("(%p)\n", This);
4583 if(!This->inScene) {
4584 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4585 return WINED3DERR_INVALIDCALL;
4588 context = context_acquire(This, NULL);
4589 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4591 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4593 context_release(context);
4595 This->inScene = FALSE;
4599 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4600 const RECT *pSourceRect, const RECT *pDestRect,
4601 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4603 IWineD3DSwapChain *swapChain = NULL;
4605 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4607 TRACE("iface %p.\n", iface);
4609 for(i = 0 ; i < swapchains ; i ++) {
4611 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4612 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4613 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4614 IWineD3DSwapChain_Release(swapChain);
4620 /* Do not call while under the GL lock. */
4621 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4622 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4624 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4625 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4628 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4629 iface, rect_count, rects, flags, color, depth, stencil);
4631 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4633 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4634 /* TODO: What about depth stencil buffers without stencil bits? */
4635 return WINED3DERR_INVALIDCALL;
4638 device_get_draw_rect(device, &draw_rect);
4640 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4641 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4648 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4649 WINED3DPRIMITIVETYPE primitive_type)
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4653 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4655 This->updateStateBlock->changed.primitive_type = TRUE;
4656 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4659 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4660 WINED3DPRIMITIVETYPE *primitive_type)
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4666 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4668 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4671 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4677 if (!This->stateBlock->state.vertex_declaration)
4679 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4680 return WINED3DERR_INVALIDCALL;
4683 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4684 if(This->stateBlock->streamIsUP) {
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4686 This->stateBlock->streamIsUP = FALSE;
4689 if (This->stateBlock->loadBaseVertexIndex)
4691 This->stateBlock->loadBaseVertexIndex = 0;
4692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4694 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4695 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4699 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 IWineD3DBuffer *pIB;
4706 pIB = This->stateBlock->pIndexData;
4708 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4709 * without an index buffer set. (The first time at least...)
4710 * D3D8 simply dies, but I doubt it can do much harm to return
4711 * D3DERR_INVALIDCALL there as well. */
4712 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4713 return WINED3DERR_INVALIDCALL;
4716 if (!This->stateBlock->state.vertex_declaration)
4718 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4719 return WINED3DERR_INVALIDCALL;
4722 if(This->stateBlock->streamIsUP) {
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4724 This->stateBlock->streamIsUP = FALSE;
4726 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4728 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4730 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4736 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4737 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4741 drawPrimitive(iface, index_count, startIndex, idxStride,
4742 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4747 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4748 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 struct wined3d_stream_state *stream;
4754 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4755 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4757 if (!This->stateBlock->state.vertex_declaration)
4759 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4760 return WINED3DERR_INVALIDCALL;
4763 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4764 stream = &This->stateBlock->streams[0];
4765 vb = (IWineD3DBuffer *)stream->buffer;
4766 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4767 if (vb) IWineD3DBuffer_Release(vb);
4769 stream->stride = VertexStreamZeroStride;
4770 This->stateBlock->streamIsUP = TRUE;
4771 This->stateBlock->loadBaseVertexIndex = 0;
4773 /* TODO: Only mark dirty if drawing from a different UP address */
4774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4776 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4778 /* MSDN specifies stream zero settings must be set to NULL */
4779 stream->buffer = NULL;
4782 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4783 * the new stream sources or use UP drawing again
4788 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4789 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4790 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4794 struct wined3d_stream_state *stream;
4798 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4799 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4801 if (!This->stateBlock->state.vertex_declaration)
4803 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4804 return WINED3DERR_INVALIDCALL;
4807 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4813 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4814 stream = &This->stateBlock->streams[0];
4815 vb = (IWineD3DBuffer *)stream->buffer;
4816 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4817 if (vb) IWineD3DBuffer_Release(vb);
4819 stream->stride = VertexStreamZeroStride;
4820 This->stateBlock->streamIsUP = TRUE;
4822 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4823 This->stateBlock->baseVertexIndex = 0;
4824 This->stateBlock->loadBaseVertexIndex = 0;
4825 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4829 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4831 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4832 stream->buffer = NULL;
4834 ib = This->stateBlock->pIndexData;
4836 IWineD3DBuffer_Release(ib);
4837 This->stateBlock->pIndexData = NULL;
4839 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4840 * SetStreamSource to specify a vertex buffer
4846 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4847 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4851 /* Mark the state dirty until we have nicer tracking
4852 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4857 This->stateBlock->baseVertexIndex = 0;
4858 This->up_strided = DrawPrimStrideData;
4859 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4860 This->up_strided = NULL;
4864 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4865 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4866 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4869 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4871 /* Mark the state dirty until we have nicer tracking
4872 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4877 This->stateBlock->streamIsUP = TRUE;
4878 This->stateBlock->baseVertexIndex = 0;
4879 This->up_strided = DrawPrimStrideData;
4880 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4881 This->up_strided = NULL;
4885 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4886 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4887 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4889 WINED3DLOCKED_BOX src;
4890 WINED3DLOCKED_BOX dst;
4893 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4894 iface, pSourceVolume, pDestinationVolume);
4896 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4897 * dirtification to improve loading performance.
4899 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4900 if(FAILED(hr)) return hr;
4901 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4903 IWineD3DVolume_UnlockBox(pSourceVolume);
4907 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4909 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4911 IWineD3DVolume_UnlockBox(pSourceVolume);
4913 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4918 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4919 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4921 unsigned int level_count, i;
4922 WINED3DRESOURCETYPE type;
4925 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4927 /* Verify that the source and destination textures are non-NULL. */
4928 if (!src_texture || !dst_texture)
4930 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4931 return WINED3DERR_INVALIDCALL;
4934 if (src_texture == dst_texture)
4936 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4937 return WINED3DERR_INVALIDCALL;
4940 /* Verify that the source and destination textures are the same type. */
4941 type = IWineD3DBaseTexture_GetType(src_texture);
4942 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4944 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4945 return WINED3DERR_INVALIDCALL;
4948 /* Check that both textures have the identical numbers of levels. */
4949 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4950 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4952 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4953 return WINED3DERR_INVALIDCALL;
4956 /* Make sure that the destination texture is loaded. */
4957 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4959 /* Update every surface level of the texture. */
4962 case WINED3DRTYPE_TEXTURE:
4964 IWineD3DSurface *src_surface;
4965 IWineD3DSurface *dst_surface;
4967 for (i = 0; i < level_count; ++i)
4969 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4970 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4971 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4972 IWineD3DSurface_Release(dst_surface);
4973 IWineD3DSurface_Release(src_surface);
4976 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4983 case WINED3DRTYPE_CUBETEXTURE:
4985 IWineD3DSurface *src_surface;
4986 IWineD3DSurface *dst_surface;
4987 WINED3DCUBEMAP_FACES face;
4989 for (i = 0; i < level_count; ++i)
4991 /* Update each cube face. */
4992 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4994 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4995 face, i, &src_surface);
4996 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4997 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4998 face, i, &dst_surface);
4999 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5000 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5001 IWineD3DSurface_Release(dst_surface);
5002 IWineD3DSurface_Release(src_surface);
5005 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5013 case WINED3DRTYPE_VOLUMETEXTURE:
5015 IWineD3DVolume *src_volume;
5016 IWineD3DVolume *dst_volume;
5018 for (i = 0; i < level_count; ++i)
5020 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5021 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5022 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5023 IWineD3DVolume_Release(dst_volume);
5024 IWineD3DVolume_Release(src_volume);
5027 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5035 FIXME("Unsupported texture type %#x.\n", type);
5036 return WINED3DERR_INVALIDCALL;
5042 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5043 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5045 IWineD3DSwapChain *swapchain;
5048 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5050 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5051 if (FAILED(hr)) return hr;
5053 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5054 IWineD3DSwapChain_Release(swapchain);
5059 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5061 IWineD3DBaseTextureImpl *texture;
5064 TRACE("(%p) : %p\n", This, pNumPasses);
5066 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5068 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5070 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5071 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5073 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5075 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5076 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5079 texture = This->stateBlock->state.textures[i];
5080 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5082 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5084 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5087 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5089 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5092 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5093 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5095 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5100 /* return a sensible default */
5103 TRACE("returning D3D_OK\n");
5107 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5111 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5113 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5114 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5115 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5117 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5122 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 PALETTEENTRY **palettes;
5128 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5130 if (PaletteNumber >= MAX_PALETTES) {
5131 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5132 return WINED3DERR_INVALIDCALL;
5135 if (PaletteNumber >= This->NumberOfPalettes) {
5136 NewSize = This->NumberOfPalettes;
5139 } while(PaletteNumber >= NewSize);
5140 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5142 ERR("Out of memory!\n");
5143 return E_OUTOFMEMORY;
5145 This->palettes = palettes;
5146 This->NumberOfPalettes = NewSize;
5149 if (!This->palettes[PaletteNumber]) {
5150 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5151 if (!This->palettes[PaletteNumber]) {
5152 ERR("Out of memory!\n");
5153 return E_OUTOFMEMORY;
5157 for (j = 0; j < 256; ++j) {
5158 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5159 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5160 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5161 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5163 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5164 TRACE("(%p) : returning\n", This);
5168 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5172 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5173 /* What happens in such situation isn't documented; Native seems to silently abort
5174 on such conditions. Return Invalid Call. */
5175 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5176 return WINED3DERR_INVALIDCALL;
5178 for (j = 0; j < 256; ++j) {
5179 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5180 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5181 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5182 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5184 TRACE("(%p) : returning\n", This);
5188 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5190 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5191 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5192 (tested with reference rasterizer). Return Invalid Call. */
5193 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5194 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5195 return WINED3DERR_INVALIDCALL;
5197 /*TODO: stateblocks */
5198 if (This->currentPalette != PaletteNumber) {
5199 This->currentPalette = PaletteNumber;
5200 dirtify_p8_texture_samplers(This);
5202 TRACE("(%p) : returning\n", This);
5206 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 WARN("(%p) : returning Invalid Call\n", This);
5212 return WINED3DERR_INVALIDCALL;
5214 /*TODO: stateblocks */
5215 *PaletteNumber = This->currentPalette;
5216 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5220 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 FIXME("(%p) : stub\n", This);
5229 This->softwareVertexProcessing = bSoftware;
5234 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5239 FIXME("(%p) : stub\n", This);
5242 return This->softwareVertexProcessing;
5245 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5246 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5248 IWineD3DSwapChain *swapchain;
5251 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5252 iface, swapchain_idx, raster_status);
5254 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5257 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5261 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5262 IWineD3DSwapChain_Release(swapchain);
5265 WARN("Failed to get raster status, hr %#x.\n", hr);
5272 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5275 if(nSegments != 0.0f) {
5278 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5285 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5290 FIXME("iface %p stub!\n", iface);
5296 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5297 IWineD3DSurface *src_surface, const RECT *src_rect,
5298 IWineD3DSurface *dst_surface, const POINT *dst_point)
5300 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5301 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5303 const struct wined3d_format *src_format;
5304 const struct wined3d_format *dst_format;
5305 const struct wined3d_gl_info *gl_info;
5306 struct wined3d_context *context;
5307 const unsigned char *data;
5308 UINT update_w, update_h;
5309 CONVERT_TYPES convert;
5313 struct wined3d_format format;
5315 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5316 iface, src_surface, wine_dbgstr_rect(src_rect),
5317 dst_surface, wine_dbgstr_point(dst_point));
5319 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5321 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5322 src_surface, dst_surface);
5323 return WINED3DERR_INVALIDCALL;
5326 src_format = src_impl->resource.format;
5327 dst_format = dst_impl->resource.format;
5329 if (src_format->id != dst_format->id)
5331 WARN("Source and destination surfaces should have the same format.\n");
5332 return WINED3DERR_INVALIDCALL;
5335 dst_x = dst_point ? dst_point->x : 0;
5336 dst_y = dst_point ? dst_point->y : 0;
5338 /* This call loads the OpenGL surface directly, instead of copying the
5339 * surface to the destination's sysmem copy. If surface conversion is
5340 * needed, use BltFast instead to copy in sysmem and use regular surface
5342 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5343 if (convert != NO_CONVERSION || format.convert)
5344 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5346 context = context_acquire(This, NULL);
5347 gl_info = context->gl_info;
5350 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5351 checkGLcall("glActiveTextureARB");
5354 /* Make sure the surface is loaded and up to date */
5355 surface_internal_preload(dst_impl, SRGB_RGB);
5356 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5358 src_w = src_impl->currentDesc.Width;
5359 src_h = src_impl->currentDesc.Height;
5360 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5361 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5363 data = IWineD3DSurface_GetData(src_surface);
5364 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5368 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5370 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5371 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5372 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5376 data += (src_rect->top / src_format->block_height) * src_pitch;
5377 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5380 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5381 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5382 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5384 if (row_length == src_pitch)
5386 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5387 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5393 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5394 * can't use the unpack row length like below. */
5395 for (row = 0, y = dst_y; row < row_count; ++row)
5397 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5398 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5399 y += src_format->block_height;
5403 checkGLcall("glCompressedTexSubImage2DARB");
5409 data += src_rect->top * src_w * src_format->byte_count;
5410 data += src_rect->left * src_format->byte_count;
5413 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5414 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5415 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5417 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5418 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5419 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5420 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5421 checkGLcall("glTexSubImage2D");
5425 context_release(context);
5427 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5428 sampler = This->rev_tex_unit_map[0];
5429 if (sampler != WINED3D_UNMAPPED_STAGE)
5431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5437 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5439 struct WineD3DRectPatch *patch;
5440 GLenum old_primitive_type;
5444 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5446 if(!(Handle || pRectPatchInfo)) {
5447 /* TODO: Write a test for the return value, thus the FIXME */
5448 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5449 return WINED3DERR_INVALIDCALL;
5453 i = PATCHMAP_HASHFUNC(Handle);
5455 LIST_FOR_EACH(e, &This->patches[i]) {
5456 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5457 if(patch->Handle == Handle) {
5464 TRACE("Patch does not exist. Creating a new one\n");
5465 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5466 patch->Handle = Handle;
5467 list_add_head(&This->patches[i], &patch->entry);
5469 TRACE("Found existing patch %p\n", patch);
5472 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5473 * attributes we have to tesselate, read back, and draw. This needs a patch
5474 * management structure instance. Create one.
5476 * A possible improvement is to check if a vertex shader is used, and if not directly
5479 FIXME("Drawing an uncached patch. This is slow\n");
5480 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5483 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5484 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5485 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5488 TRACE("Tesselation density or patch info changed, retesselating\n");
5490 if(pRectPatchInfo) {
5491 patch->RectPatchInfo = *pRectPatchInfo;
5493 patch->numSegs[0] = pNumSegs[0];
5494 patch->numSegs[1] = pNumSegs[1];
5495 patch->numSegs[2] = pNumSegs[2];
5496 patch->numSegs[3] = pNumSegs[3];
5498 hr = tesselate_rectpatch(This, patch);
5500 WARN("Patch tesselation failed\n");
5502 /* Do not release the handle to store the params of the patch */
5504 HeapFree(GetProcessHeap(), 0, patch);
5510 This->currentPatch = patch;
5511 old_primitive_type = This->stateBlock->gl_primitive_type;
5512 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5513 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5514 This->stateBlock->gl_primitive_type = old_primitive_type;
5515 This->currentPatch = NULL;
5517 /* Destroy uncached patches */
5519 HeapFree(GetProcessHeap(), 0, patch->mem);
5520 HeapFree(GetProcessHeap(), 0, patch);
5525 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5526 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5528 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5529 iface, handle, segment_count, patch_info);
5534 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5537 struct WineD3DRectPatch *patch;
5539 TRACE("(%p) Handle(%d)\n", This, Handle);
5541 i = PATCHMAP_HASHFUNC(Handle);
5542 LIST_FOR_EACH(e, &This->patches[i]) {
5543 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5544 if(patch->Handle == Handle) {
5545 TRACE("Deleting patch %p\n", patch);
5546 list_remove(&patch->entry);
5547 HeapFree(GetProcessHeap(), 0, patch->mem);
5548 HeapFree(GetProcessHeap(), 0, patch);
5553 /* TODO: Write a test for the return value */
5554 FIXME("Attempt to destroy nonexistent patch\n");
5555 return WINED3DERR_INVALIDCALL;
5558 /* Do not call while under the GL lock. */
5559 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5560 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5562 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5564 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5565 iface, surface, wine_dbgstr_rect(rect),
5566 color->r, color->g, color->b, color->a);
5568 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5570 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5571 return WINED3DERR_INVALIDCALL;
5574 return surface_color_fill(s, rect, color);
5577 /* Do not call while under the GL lock. */
5578 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5579 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5581 IWineD3DResource *resource;
5584 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5587 ERR("Failed to get resource, hr %#x\n", hr);
5591 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5593 FIXME("Only supported on surface resources\n");
5594 IWineD3DResource_Release(resource);
5598 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5599 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5601 IWineD3DResource_Release(resource);
5604 /* rendertarget and depth stencil functions */
5605 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5606 DWORD render_target_idx, IWineD3DSurface **render_target)
5608 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5610 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5611 iface, render_target_idx, render_target);
5613 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5615 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5616 return WINED3DERR_INVALIDCALL;
5619 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5620 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5622 TRACE("Returning render target %p.\n", *render_target);
5627 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5628 IWineD3DSurface *front, IWineD3DSurface *back)
5630 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5631 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5632 IWineD3DSwapChainImpl *swapchain;
5635 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5637 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5639 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5643 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5645 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5646 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5647 return WINED3DERR_INVALIDCALL;
5652 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5654 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5655 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5656 return WINED3DERR_INVALIDCALL;
5659 if (!swapchain->back_buffers)
5661 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5662 if (!swapchain->back_buffers)
5664 ERR("Failed to allocate back buffer array memory.\n");
5665 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5666 return E_OUTOFMEMORY;
5671 if (swapchain->front_buffer != front_impl)
5673 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5675 if (swapchain->front_buffer)
5676 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5677 swapchain->front_buffer = front_impl;
5680 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5683 if (swapchain->back_buffers[0] != back_impl)
5685 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5687 if (swapchain->back_buffers[0])
5688 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5689 swapchain->back_buffers[0] = back_impl;
5693 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5694 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5695 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5696 swapchain->presentParms.BackBufferCount = 1;
5698 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5702 swapchain->presentParms.BackBufferCount = 0;
5703 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5704 swapchain->back_buffers = NULL;
5708 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5712 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5714 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5716 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5718 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5719 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5720 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5721 IWineD3DSurface_AddRef(*depth_stencil);
5726 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5727 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5729 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5730 IWineD3DSurfaceImpl *prev;
5732 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5733 iface, render_target_idx, render_target, set_viewport);
5735 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5737 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5738 return WINED3DERR_INVALIDCALL;
5741 prev = device->render_targets[render_target_idx];
5742 if (render_target == (IWineD3DSurface *)prev)
5744 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5748 /* Render target 0 can't be set to NULL. */
5749 if (!render_target && !render_target_idx)
5751 WARN("Trying to set render target 0 to NULL.\n");
5752 return WINED3DERR_INVALIDCALL;
5755 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5757 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5758 return WINED3DERR_INVALIDCALL;
5761 if (render_target) IWineD3DSurface_AddRef(render_target);
5762 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5763 /* Release after the assignment, to prevent device_resource_released()
5764 * from seeing the surface as still in use. */
5765 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5767 /* Render target 0 is special. */
5768 if (!render_target_idx && set_viewport)
5770 /* Set the viewport and scissor rectangles, if requested. Tests show
5771 * that stateblock recording is ignored, the change goes directly
5772 * into the primary stateblock. */
5773 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5774 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5775 device->stateBlock->state.viewport.X = 0;
5776 device->stateBlock->state.viewport.Y = 0;
5777 device->stateBlock->state.viewport.MaxZ = 1.0f;
5778 device->stateBlock->state.viewport.MinZ = 0.0f;
5779 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5781 device->stateBlock->state.scissor_rect.top = 0;
5782 device->stateBlock->state.scissor_rect.left = 0;
5783 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5784 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5785 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5791 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 IWineD3DSurfaceImpl *tmp;
5796 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5798 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5800 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5804 if (This->depth_stencil)
5806 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5807 || This->depth_stencil->Flags & SFLAG_DISCARD)
5809 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5810 This->depth_stencil->currentDesc.Width,
5811 This->depth_stencil->currentDesc.Height);
5812 if (This->depth_stencil == This->onscreen_depth_stencil)
5814 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5815 This->onscreen_depth_stencil = NULL;
5820 tmp = This->depth_stencil;
5821 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5822 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5823 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5825 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5827 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5836 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5837 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5840 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5841 WINED3DLOCKED_RECT lockedRect;
5843 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5844 iface, XHotSpot, YHotSpot, cursor_image);
5846 /* some basic validation checks */
5847 if (This->cursorTexture)
5849 struct wined3d_context *context = context_acquire(This, NULL);
5851 glDeleteTextures(1, &This->cursorTexture);
5853 context_release(context);
5854 This->cursorTexture = 0;
5857 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5858 This->haveHardwareCursor = TRUE;
5860 This->haveHardwareCursor = FALSE;
5864 WINED3DLOCKED_RECT rect;
5866 /* MSDN: Cursor must be A8R8G8B8 */
5867 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5869 WARN("surface %p has an invalid format.\n", cursor_image);
5870 return WINED3DERR_INVALIDCALL;
5873 /* MSDN: Cursor must be smaller than the display mode */
5874 if (s->currentDesc.Width > This->ddraw_width
5875 || s->currentDesc.Height > This->ddraw_height)
5877 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5878 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5879 return WINED3DERR_INVALIDCALL;
5882 if (!This->haveHardwareCursor) {
5883 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5885 /* Do not store the surface's pointer because the application may
5886 * release it after setting the cursor image. Windows doesn't
5887 * addref the set surface, so we can't do this either without
5888 * creating circular refcount dependencies. Copy out the gl texture
5891 This->cursorWidth = s->currentDesc.Width;
5892 This->cursorHeight = s->currentDesc.Height;
5893 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5895 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5896 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5897 struct wined3d_context *context;
5898 char *mem, *bits = rect.pBits;
5899 GLint intfmt = format->glInternal;
5900 GLint gl_format = format->glFormat;
5901 GLint type = format->glType;
5902 INT height = This->cursorHeight;
5903 INT width = This->cursorWidth;
5904 INT bpp = format->byte_count;
5908 /* Reformat the texture memory (pitch and width can be
5910 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5911 for(i = 0; i < height; i++)
5912 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5913 IWineD3DSurface_UnlockRect(cursor_image);
5915 context = context_acquire(This, NULL);
5919 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5921 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5922 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5925 /* Make sure that a proper texture unit is selected */
5926 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5927 checkGLcall("glActiveTextureARB");
5928 sampler = This->rev_tex_unit_map[0];
5929 if (sampler != WINED3D_UNMAPPED_STAGE)
5931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5933 /* Create a new cursor texture */
5934 glGenTextures(1, &This->cursorTexture);
5935 checkGLcall("glGenTextures");
5936 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5937 checkGLcall("glBindTexture");
5938 /* Copy the bitmap memory into the cursor texture */
5939 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5940 HeapFree(GetProcessHeap(), 0, mem);
5941 checkGLcall("glTexImage2D");
5943 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5945 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5946 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5951 context_release(context);
5955 FIXME("A cursor texture was not returned.\n");
5956 This->cursorTexture = 0;
5961 /* Draw a hardware cursor */
5962 ICONINFO cursorInfo;
5964 /* Create and clear maskBits because it is not needed for
5965 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5967 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5968 (s->currentDesc.Width * s->currentDesc.Height / 8));
5969 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5970 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5971 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5973 cursorInfo.fIcon = FALSE;
5974 cursorInfo.xHotspot = XHotSpot;
5975 cursorInfo.yHotspot = YHotSpot;
5976 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5977 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5978 IWineD3DSurface_UnlockRect(cursor_image);
5979 /* Create our cursor and clean up. */
5980 cursor = CreateIconIndirect(&cursorInfo);
5982 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5983 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5984 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5985 This->hardwareCursor = cursor;
5986 HeapFree(GetProcessHeap(), 0, maskBits);
5990 This->xHotSpot = XHotSpot;
5991 This->yHotSpot = YHotSpot;
5995 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5997 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5999 This->xScreenSpace = XScreenSpace;
6000 This->yScreenSpace = YScreenSpace;
6006 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6008 BOOL oldVisible = This->bCursorVisible;
6011 TRACE("(%p) : visible(%d)\n", This, bShow);
6014 * When ShowCursor is first called it should make the cursor appear at the OS's last
6015 * known cursor position. Because of this, some applications just repetitively call
6016 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6019 This->xScreenSpace = pt.x;
6020 This->yScreenSpace = pt.y;
6022 if (This->haveHardwareCursor) {
6023 This->bCursorVisible = bShow;
6025 SetCursor(This->hardwareCursor);
6031 if (This->cursorTexture)
6032 This->bCursorVisible = bShow;
6038 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6039 TRACE("checking resource %p for eviction\n", resource);
6040 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6041 TRACE("Evicting %p\n", resource);
6042 IWineD3DResource_UnLoad(resource);
6044 IWineD3DResource_Release(resource);
6048 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6050 TRACE("iface %p.\n", iface);
6052 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6053 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6054 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6059 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6061 IWineD3DDeviceImpl *device = surface->resource.device;
6062 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6064 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6065 if(surface->Flags & SFLAG_DIBSECTION) {
6066 /* Release the DC */
6067 SelectObject(surface->hDC, surface->dib.holdbitmap);
6068 DeleteDC(surface->hDC);
6069 /* Release the DIB section */
6070 DeleteObject(surface->dib.DIBsection);
6071 surface->dib.bitmap_data = NULL;
6072 surface->resource.allocatedMemory = NULL;
6073 surface->Flags &= ~SFLAG_DIBSECTION;
6075 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6076 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6077 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6078 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6080 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6081 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6083 surface->pow2Width = surface->pow2Height = 1;
6084 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6085 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6088 if (surface->texture_name)
6090 struct wined3d_context *context = context_acquire(device, NULL);
6092 glDeleteTextures(1, &surface->texture_name);
6094 context_release(context);
6095 surface->texture_name = 0;
6096 surface->Flags &= ~SFLAG_CLIENT;
6098 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6099 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6100 surface->Flags |= SFLAG_NONPOW2;
6102 surface->Flags &= ~SFLAG_NONPOW2;
6104 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6105 surface->resource.allocatedMemory = NULL;
6106 surface->resource.heapMemory = NULL;
6107 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6109 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6111 if (!surface_init_sysmem(surface))
6113 return E_OUTOFMEMORY;
6118 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6119 TRACE("Unloading resource %p\n", resource);
6120 IWineD3DResource_UnLoad(resource);
6121 IWineD3DResource_Release(resource);
6125 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6128 WINED3DDISPLAYMODE m;
6131 /* All Windowed modes are supported, as is leaving the current mode */
6132 if(pp->Windowed) return TRUE;
6133 if(!pp->BackBufferWidth) return TRUE;
6134 if(!pp->BackBufferHeight) return TRUE;
6136 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6137 for(i = 0; i < count; i++) {
6138 memset(&m, 0, sizeof(m));
6139 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6141 ERR("EnumAdapterModes failed\n");
6143 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6144 /* Mode found, it is supported */
6148 /* Mode not found -> not supported */
6152 /* Do not call while under the GL lock. */
6153 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6156 const struct wined3d_gl_info *gl_info;
6157 struct wined3d_context *context;
6158 IWineD3DBaseShaderImpl *shader;
6160 context = context_acquire(This, NULL);
6161 gl_info = context->gl_info;
6163 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6164 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6165 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6169 if(This->depth_blt_texture) {
6170 glDeleteTextures(1, &This->depth_blt_texture);
6171 This->depth_blt_texture = 0;
6173 if (This->depth_blt_rb) {
6174 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6175 This->depth_blt_rb = 0;
6176 This->depth_blt_rb_w = 0;
6177 This->depth_blt_rb_h = 0;
6181 This->blitter->free_private(iface);
6182 This->frag_pipe->free_private(iface);
6183 This->shader_backend->shader_free_private(iface);
6184 destroy_dummy_textures(This, gl_info);
6186 context_release(context);
6188 while (This->numContexts)
6190 context_destroy(This, This->contexts[0]);
6192 HeapFree(GetProcessHeap(), 0, swapchain->context);
6193 swapchain->context = NULL;
6194 swapchain->num_contexts = 0;
6197 /* Do not call while under the GL lock. */
6198 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6201 struct wined3d_context *context;
6203 IWineD3DSurfaceImpl *target;
6205 /* Recreate the primary swapchain's context */
6206 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6207 if (!swapchain->context)
6209 ERR("Failed to allocate memory for swapchain context array.\n");
6210 return E_OUTOFMEMORY;
6213 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6214 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6216 WARN("Failed to create context.\n");
6217 HeapFree(GetProcessHeap(), 0, swapchain->context);
6221 swapchain->context[0] = context;
6222 swapchain->num_contexts = 1;
6223 create_dummy_textures(This);
6224 context_release(context);
6226 hr = This->shader_backend->shader_alloc_private(iface);
6229 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6233 hr = This->frag_pipe->alloc_private(iface);
6236 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6237 This->shader_backend->shader_free_private(iface);
6241 hr = This->blitter->alloc_private(iface);
6244 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6245 This->frag_pipe->free_private(iface);
6246 This->shader_backend->shader_free_private(iface);
6253 context_acquire(This, NULL);
6254 destroy_dummy_textures(This, context->gl_info);
6255 context_release(context);
6256 context_destroy(This, context);
6257 HeapFree(GetProcessHeap(), 0, swapchain->context);
6258 swapchain->num_contexts = 0;
6262 /* Do not call while under the GL lock. */
6263 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6264 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6267 IWineD3DSwapChainImpl *swapchain;
6269 BOOL DisplayModeChanged = FALSE;
6270 WINED3DDISPLAYMODE mode;
6271 TRACE("(%p)\n", This);
6273 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6275 ERR("Failed to get the first implicit swapchain\n");
6279 if(!is_display_mode_supported(This, pPresentationParameters)) {
6280 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6281 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6282 pPresentationParameters->BackBufferHeight);
6283 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6284 return WINED3DERR_INVALIDCALL;
6287 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6288 * on an existing gl context, so there's no real need for recreation.
6290 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6292 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6294 TRACE("New params:\n");
6295 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6296 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6297 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6298 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6299 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6300 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6301 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6302 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6303 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6304 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6305 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6306 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6307 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6309 /* No special treatment of these parameters. Just store them */
6310 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6311 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6312 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6313 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6315 /* What to do about these? */
6316 if (pPresentationParameters->BackBufferCount
6317 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6318 ERR("Cannot change the back buffer count yet\n");
6320 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6321 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6322 ERR("Cannot change the back buffer format yet\n");
6325 if (pPresentationParameters->hDeviceWindow
6326 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6327 ERR("Cannot change the device window yet\n");
6329 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6333 TRACE("Creating the depth stencil buffer\n");
6335 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6336 pPresentationParameters->BackBufferWidth,
6337 pPresentationParameters->BackBufferHeight,
6338 pPresentationParameters->AutoDepthStencilFormat,
6339 pPresentationParameters->MultiSampleType,
6340 pPresentationParameters->MultiSampleQuality,
6342 (IWineD3DSurface **)&This->auto_depth_stencil);
6345 ERR("Failed to create the depth stencil buffer\n");
6346 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6347 return WINED3DERR_INVALIDCALL;
6351 if (This->onscreen_depth_stencil)
6353 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6354 This->onscreen_depth_stencil = NULL;
6357 /* Reset the depth stencil */
6358 if (pPresentationParameters->EnableAutoDepthStencil)
6359 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6361 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6363 TRACE("Resetting stateblock\n");
6364 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6365 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6367 delete_opengl_contexts(iface, swapchain);
6369 if(pPresentationParameters->Windowed) {
6370 mode.Width = swapchain->orig_width;
6371 mode.Height = swapchain->orig_height;
6372 mode.RefreshRate = 0;
6373 mode.Format = swapchain->presentParms.BackBufferFormat;
6375 mode.Width = pPresentationParameters->BackBufferWidth;
6376 mode.Height = pPresentationParameters->BackBufferHeight;
6377 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6378 mode.Format = swapchain->presentParms.BackBufferFormat;
6381 /* Should Width == 800 && Height == 0 set 800x600? */
6382 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6383 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6384 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6388 if(!pPresentationParameters->Windowed) {
6389 DisplayModeChanged = TRUE;
6391 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6392 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6394 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6397 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6401 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6403 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6406 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6410 if (This->auto_depth_stencil)
6412 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6415 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6421 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6422 || DisplayModeChanged)
6424 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6426 if (!pPresentationParameters->Windowed)
6428 if(swapchain->presentParms.Windowed) {
6429 /* switch from windowed to fs */
6430 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6431 pPresentationParameters->BackBufferHeight);
6433 /* Fullscreen -> fullscreen mode change */
6434 MoveWindow(swapchain->device_window, 0, 0,
6435 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6439 else if (!swapchain->presentParms.Windowed)
6441 /* Fullscreen -> windowed switch */
6442 swapchain_restore_fullscreen_window(swapchain);
6444 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6445 } else if(!pPresentationParameters->Windowed) {
6446 DWORD style = This->style, exStyle = This->exStyle;
6447 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6448 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6449 * Reset to clear up their mess. Guild Wars also loses the device during that.
6453 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6454 pPresentationParameters->BackBufferHeight);
6455 This->style = style;
6456 This->exStyle = exStyle;
6459 /* Note: No parent needed for initial internal stateblock */
6460 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6461 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6462 else TRACE("Created stateblock %p\n", This->stateBlock);
6463 This->updateStateBlock = This->stateBlock;
6464 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6466 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6468 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6471 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6474 GetClientRect(swapchain->win_handle, &client_rect);
6476 if(!swapchain->presentParms.BackBufferCount)
6478 TRACE("Single buffered rendering\n");
6479 swapchain->render_to_fbo = FALSE;
6481 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6482 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6484 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6485 swapchain->presentParms.BackBufferWidth,
6486 swapchain->presentParms.BackBufferHeight,
6487 client_rect.right, client_rect.bottom);
6488 swapchain->render_to_fbo = TRUE;
6492 TRACE("Rendering directly to GL_BACK\n");
6493 swapchain->render_to_fbo = FALSE;
6497 hr = create_primary_opengl_context(iface, swapchain);
6498 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6500 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6506 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6508 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6510 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6516 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6518 TRACE("(%p) : pParameters %p\n", This, pParameters);
6520 *pParameters = This->createParms;
6524 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6525 IWineD3DSwapChain *swapchain;
6527 TRACE("Relaying to swapchain\n");
6529 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6530 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6531 IWineD3DSwapChain_Release(swapchain);
6535 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6536 IWineD3DSwapChain *swapchain;
6538 TRACE("Relaying to swapchain\n");
6540 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6541 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6542 IWineD3DSwapChain_Release(swapchain);
6547 /** ********************************************************
6548 * Notification functions
6549 ** ********************************************************/
6550 /** This function must be called in the release of a resource when ref == 0,
6551 * the contents of resource must still be correct,
6552 * any handles to other resource held by the caller must be closed
6553 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6554 *****************************************************/
6555 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6557 TRACE("(%p) : Adding resource %p\n", This, resource);
6559 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6562 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6564 TRACE("(%p) : Removing resource %p\n", This, resource);
6566 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6569 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6571 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6574 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6576 context_resource_released(device, resource, type);
6580 case WINED3DRTYPE_SURFACE:
6581 if (!device->d3d_initialized) break;
6583 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6585 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6587 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6588 device->render_targets[i] = NULL;
6592 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6594 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6595 device->depth_stencil = NULL;
6599 case WINED3DRTYPE_TEXTURE:
6600 case WINED3DRTYPE_CUBETEXTURE:
6601 case WINED3DRTYPE_VOLUMETEXTURE:
6602 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6604 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6606 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6607 resource, device->stateBlock, i);
6608 device->stateBlock->state.textures[i] = NULL;
6611 if (device->updateStateBlock != device->stateBlock
6612 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6614 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6615 resource, device->updateStateBlock, i);
6616 device->updateStateBlock->state.textures[i] = NULL;
6621 case WINED3DRTYPE_BUFFER:
6622 for (i = 0; i < MAX_STREAMS; ++i)
6624 if (device->stateBlock && device->stateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6626 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6627 resource, device->stateBlock, i);
6628 device->stateBlock->streams[i].buffer = NULL;
6631 if (device->updateStateBlock != device->stateBlock
6632 && device->updateStateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6634 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6635 resource, device->updateStateBlock, i);
6636 device->updateStateBlock->streams[i].buffer = NULL;
6641 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6643 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6644 resource, device->stateBlock);
6645 device->stateBlock->pIndexData = NULL;
6648 if (device->updateStateBlock != device->stateBlock
6649 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6651 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6652 resource, device->updateStateBlock);
6653 device->updateStateBlock->pIndexData = NULL;
6661 /* Remove the resource from the resourceStore */
6662 device_resource_remove(device, resource);
6664 TRACE("Resource released.\n");
6667 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6669 IWineD3DResourceImpl *resource, *cursor;
6671 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6673 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6674 TRACE("enumerating resource %p\n", resource);
6675 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6676 ret = pCallback((IWineD3DResource *) resource, pData);
6677 if(ret == S_FALSE) {
6678 TRACE("Canceling enumeration\n");
6685 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6688 IWineD3DResourceImpl *resource;
6690 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6692 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6693 if (type == WINED3DRTYPE_SURFACE)
6695 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6697 TRACE("Found surface %p for dc %p.\n", resource, dc);
6698 *surface = (IWineD3DSurface *)resource;
6704 return WINED3DERR_INVALIDCALL;
6707 /**********************************************************
6708 * IWineD3DDevice VTbl follows
6709 **********************************************************/
6711 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6713 /*** IUnknown methods ***/
6714 IWineD3DDeviceImpl_QueryInterface,
6715 IWineD3DDeviceImpl_AddRef,
6716 IWineD3DDeviceImpl_Release,
6717 /*** IWineD3DDevice methods ***/
6718 /*** Creation methods**/
6719 IWineD3DDeviceImpl_CreateBuffer,
6720 IWineD3DDeviceImpl_CreateVertexBuffer,
6721 IWineD3DDeviceImpl_CreateIndexBuffer,
6722 IWineD3DDeviceImpl_CreateStateBlock,
6723 IWineD3DDeviceImpl_CreateSurface,
6724 IWineD3DDeviceImpl_CreateRendertargetView,
6725 IWineD3DDeviceImpl_CreateTexture,
6726 IWineD3DDeviceImpl_CreateVolumeTexture,
6727 IWineD3DDeviceImpl_CreateVolume,
6728 IWineD3DDeviceImpl_CreateCubeTexture,
6729 IWineD3DDeviceImpl_CreateQuery,
6730 IWineD3DDeviceImpl_CreateSwapChain,
6731 IWineD3DDeviceImpl_CreateVertexDeclaration,
6732 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6733 IWineD3DDeviceImpl_CreateVertexShader,
6734 IWineD3DDeviceImpl_CreateGeometryShader,
6735 IWineD3DDeviceImpl_CreatePixelShader,
6736 IWineD3DDeviceImpl_CreatePalette,
6737 /*** Odd functions **/
6738 IWineD3DDeviceImpl_Init3D,
6739 IWineD3DDeviceImpl_InitGDI,
6740 IWineD3DDeviceImpl_Uninit3D,
6741 IWineD3DDeviceImpl_UninitGDI,
6742 IWineD3DDeviceImpl_SetMultithreaded,
6743 IWineD3DDeviceImpl_EvictManagedResources,
6744 IWineD3DDeviceImpl_GetAvailableTextureMem,
6745 IWineD3DDeviceImpl_GetBackBuffer,
6746 IWineD3DDeviceImpl_GetCreationParameters,
6747 IWineD3DDeviceImpl_GetDeviceCaps,
6748 IWineD3DDeviceImpl_GetDirect3D,
6749 IWineD3DDeviceImpl_GetDisplayMode,
6750 IWineD3DDeviceImpl_SetDisplayMode,
6751 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6752 IWineD3DDeviceImpl_GetRasterStatus,
6753 IWineD3DDeviceImpl_GetSwapChain,
6754 IWineD3DDeviceImpl_Reset,
6755 IWineD3DDeviceImpl_SetDialogBoxMode,
6756 IWineD3DDeviceImpl_SetCursorProperties,
6757 IWineD3DDeviceImpl_SetCursorPosition,
6758 IWineD3DDeviceImpl_ShowCursor,
6759 /*** Getters and setters **/
6760 IWineD3DDeviceImpl_SetClipPlane,
6761 IWineD3DDeviceImpl_GetClipPlane,
6762 IWineD3DDeviceImpl_SetClipStatus,
6763 IWineD3DDeviceImpl_GetClipStatus,
6764 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6765 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6766 IWineD3DDeviceImpl_SetDepthStencilSurface,
6767 IWineD3DDeviceImpl_GetDepthStencilSurface,
6768 IWineD3DDeviceImpl_SetGammaRamp,
6769 IWineD3DDeviceImpl_GetGammaRamp,
6770 IWineD3DDeviceImpl_SetIndexBuffer,
6771 IWineD3DDeviceImpl_GetIndexBuffer,
6772 IWineD3DDeviceImpl_SetBaseVertexIndex,
6773 IWineD3DDeviceImpl_GetBaseVertexIndex,
6774 IWineD3DDeviceImpl_SetLight,
6775 IWineD3DDeviceImpl_GetLight,
6776 IWineD3DDeviceImpl_SetLightEnable,
6777 IWineD3DDeviceImpl_GetLightEnable,
6778 IWineD3DDeviceImpl_SetMaterial,
6779 IWineD3DDeviceImpl_GetMaterial,
6780 IWineD3DDeviceImpl_SetNPatchMode,
6781 IWineD3DDeviceImpl_GetNPatchMode,
6782 IWineD3DDeviceImpl_SetPaletteEntries,
6783 IWineD3DDeviceImpl_GetPaletteEntries,
6784 IWineD3DDeviceImpl_SetPixelShader,
6785 IWineD3DDeviceImpl_GetPixelShader,
6786 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6787 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6788 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6789 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6790 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6791 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6792 IWineD3DDeviceImpl_SetRenderState,
6793 IWineD3DDeviceImpl_GetRenderState,
6794 IWineD3DDeviceImpl_SetRenderTarget,
6795 IWineD3DDeviceImpl_GetRenderTarget,
6796 IWineD3DDeviceImpl_SetFrontBackBuffers,
6797 IWineD3DDeviceImpl_SetSamplerState,
6798 IWineD3DDeviceImpl_GetSamplerState,
6799 IWineD3DDeviceImpl_SetScissorRect,
6800 IWineD3DDeviceImpl_GetScissorRect,
6801 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6802 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6803 IWineD3DDeviceImpl_SetStreamSource,
6804 IWineD3DDeviceImpl_GetStreamSource,
6805 IWineD3DDeviceImpl_SetStreamSourceFreq,
6806 IWineD3DDeviceImpl_GetStreamSourceFreq,
6807 IWineD3DDeviceImpl_SetTexture,
6808 IWineD3DDeviceImpl_GetTexture,
6809 IWineD3DDeviceImpl_SetTextureStageState,
6810 IWineD3DDeviceImpl_GetTextureStageState,
6811 IWineD3DDeviceImpl_SetTransform,
6812 IWineD3DDeviceImpl_GetTransform,
6813 IWineD3DDeviceImpl_SetVertexDeclaration,
6814 IWineD3DDeviceImpl_GetVertexDeclaration,
6815 IWineD3DDeviceImpl_SetVertexShader,
6816 IWineD3DDeviceImpl_GetVertexShader,
6817 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6818 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6819 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6820 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6821 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6822 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6823 IWineD3DDeviceImpl_SetViewport,
6824 IWineD3DDeviceImpl_GetViewport,
6825 IWineD3DDeviceImpl_MultiplyTransform,
6826 IWineD3DDeviceImpl_ValidateDevice,
6827 IWineD3DDeviceImpl_ProcessVertices,
6828 /*** State block ***/
6829 IWineD3DDeviceImpl_BeginStateBlock,
6830 IWineD3DDeviceImpl_EndStateBlock,
6831 /*** Scene management ***/
6832 IWineD3DDeviceImpl_BeginScene,
6833 IWineD3DDeviceImpl_EndScene,
6834 IWineD3DDeviceImpl_Present,
6835 IWineD3DDeviceImpl_Clear,
6836 IWineD3DDeviceImpl_ClearRendertargetView,
6838 IWineD3DDeviceImpl_SetPrimitiveType,
6839 IWineD3DDeviceImpl_GetPrimitiveType,
6840 IWineD3DDeviceImpl_DrawPrimitive,
6841 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6842 IWineD3DDeviceImpl_DrawPrimitiveUP,
6843 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6844 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6845 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6846 IWineD3DDeviceImpl_DrawRectPatch,
6847 IWineD3DDeviceImpl_DrawTriPatch,
6848 IWineD3DDeviceImpl_DeletePatch,
6849 IWineD3DDeviceImpl_ColorFill,
6850 IWineD3DDeviceImpl_UpdateTexture,
6851 IWineD3DDeviceImpl_UpdateSurface,
6852 IWineD3DDeviceImpl_GetFrontBufferData,
6853 /*** object tracking ***/
6854 IWineD3DDeviceImpl_EnumResources,
6855 IWineD3DDeviceImpl_GetSurfaceFromDC,
6856 IWineD3DDeviceImpl_AcquireFocusWindow,
6857 IWineD3DDeviceImpl_ReleaseFocusWindow,
6860 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6861 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6862 IWineD3DDeviceParent *device_parent)
6864 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6865 const struct fragment_pipeline *fragment_pipeline;
6866 struct shader_caps shader_caps;
6867 struct fragment_caps ffp_caps;
6868 WINED3DDISPLAYMODE mode;
6872 device->lpVtbl = &IWineD3DDevice_Vtbl;
6874 device->wined3d = (IWineD3D *)wined3d;
6875 IWineD3D_AddRef(device->wined3d);
6876 device->adapter = wined3d->adapter_count ? adapter : NULL;
6877 device->device_parent = device_parent;
6878 list_init(&device->resources);
6879 list_init(&device->shaders);
6881 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6882 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6884 /* Get the initial screen setup for ddraw. */
6885 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6888 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6889 IWineD3D_Release(device->wined3d);
6892 device->ddraw_width = mode.Width;
6893 device->ddraw_height = mode.Height;
6894 device->ddraw_format = mode.Format;
6896 /* Save the creation parameters. */
6897 device->createParms.AdapterOrdinal = adapter_idx;
6898 device->createParms.DeviceType = device_type;
6899 device->createParms.hFocusWindow = focus_window;
6900 device->createParms.BehaviorFlags = flags;
6902 device->devType = device_type;
6903 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6905 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6906 device->shader_backend = adapter->shader_backend;
6908 if (device->shader_backend)
6910 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6911 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6912 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6913 device->vs_clipping = shader_caps.VSClipping;
6915 fragment_pipeline = adapter->fragment_pipe;
6916 device->frag_pipe = fragment_pipeline;
6917 if (fragment_pipeline)
6919 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6920 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6922 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6923 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6926 ERR("Failed to compile state table, hr %#x.\n", hr);
6927 IWineD3D_Release(device->wined3d);
6931 device->blitter = adapter->blitter;
6937 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6938 DWORD rep = This->StateTable[state].representative;
6939 struct wined3d_context *context;
6944 for(i = 0; i < This->numContexts; i++) {
6945 context = This->contexts[i];
6946 if(isStateDirty(context, rep)) continue;
6948 context->dirtyArray[context->numDirtyEntries++] = rep;
6949 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6950 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6951 context->isStateDirty[idx] |= (1 << shift);
6955 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6957 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6958 *width = context->current_rt->pow2Width;
6959 *height = context->current_rt->pow2Height;
6962 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6964 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6965 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6966 * current context's drawable, which is the size of the back buffer of the swapchain
6967 * the active context belongs to. */
6968 *width = swapchain->presentParms.BackBufferWidth;
6969 *height = swapchain->presentParms.BackBufferHeight;
6972 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6973 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6975 if (device->filter_messages)
6977 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6978 window, message, wparam, lparam);
6979 return DefWindowProcW(window, message, wparam, lparam);
6982 if (message == WM_DESTROY)
6984 TRACE("unregister window %p.\n", window);
6985 wined3d_unregister_window(window);
6987 if (device->focus_window == window) device->focus_window = NULL;
6988 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6991 return CallWindowProcW(proc, window, message, wparam, lparam);