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 = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
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->vertexShader,
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->vertexShader && 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 (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->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 = (IWineD3DBaseTextureImpl *)stateblock->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 (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->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 (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->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 = This->updateStateBlock->vertexDecl;
3169 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3171 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3172 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3174 This->updateStateBlock->vertexDecl = 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 = This->stateBlock->vertexDecl;
3196 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3204 This->updateStateBlock->vertexShader = pShader;
3205 This->updateStateBlock->changed.vertexShader = TRUE;
3207 if (This->isRecordingState) {
3208 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3209 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3210 TRACE("Recording... not performing anything\n");
3212 } else if(oldShader == pShader) {
3213 /* Checked here to allow proper stateblock recording */
3214 TRACE("App is setting the old shader over, nothing to do\n");
3218 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3219 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3220 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3227 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3229 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3230 IWineD3DVertexShader *shader;
3232 TRACE("iface %p.\n", iface);
3234 shader = device->stateBlock->vertexShader;
3235 if (shader) IWineD3DVertexShader_AddRef(shader);
3237 TRACE("Returning %p.\n", shader);
3241 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3242 IWineD3DDevice *iface,
3244 CONST BOOL *srcData,
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3250 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3251 iface, srcData, start, count);
3253 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3255 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3256 for (i = 0; i < cnt; i++)
3257 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3259 for (i = start; i < cnt + start; ++i) {
3260 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3263 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3268 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3269 IWineD3DDevice *iface,
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 int cnt = min(count, MAX_CONST_B - start);
3277 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3278 iface, dstData, start, count);
3280 if (!dstData || cnt < 0)
3281 return WINED3DERR_INVALIDCALL;
3283 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3288 IWineD3DDevice *iface,
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3296 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3297 iface, srcData, start, count);
3299 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3301 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3302 for (i = 0; i < cnt; i++)
3303 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3304 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3306 for (i = start; i < cnt + start; ++i) {
3307 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3310 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3316 IWineD3DDevice *iface,
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 int cnt = min(count, MAX_CONST_I - start);
3324 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3325 iface, dstData, start, count);
3327 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3328 return WINED3DERR_INVALIDCALL;
3330 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3334 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3335 IWineD3DDevice *iface,
3337 CONST float *srcData,
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3343 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3344 iface, srcData, start, count);
3346 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3347 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3348 return WINED3DERR_INVALIDCALL;
3350 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3352 for (i = 0; i < count; i++)
3353 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3354 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3357 if (!This->isRecordingState)
3359 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3363 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3364 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3369 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3370 IWineD3DDevice *iface,
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 int cnt = min(count, This->d3d_vshader_constantF - start);
3378 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3379 iface, dstData, start, count);
3381 if (!dstData || cnt < 0)
3382 return WINED3DERR_INVALIDCALL;
3384 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3388 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3390 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3396 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3398 DWORD i = This->rev_tex_unit_map[unit];
3399 DWORD j = This->texUnitMap[stage];
3401 This->texUnitMap[stage] = unit;
3402 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3404 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3407 This->rev_tex_unit_map[unit] = stage;
3408 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3410 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3414 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3417 This->fixed_function_usage_map = 0;
3418 for (i = 0; i < MAX_TEXTURES; ++i)
3420 const struct wined3d_state *state = &This->stateBlock->state;
3421 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3422 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3423 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3424 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3425 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3426 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3427 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3428 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3430 if (color_op == WINED3DTOP_DISABLE) {
3431 /* Not used, and disable higher stages */
3435 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3436 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3437 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3438 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3439 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3440 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3441 This->fixed_function_usage_map |= (1 << i);
3444 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3445 This->fixed_function_usage_map |= (1 << (i + 1));
3450 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3452 unsigned int i, tex;
3455 device_update_fixed_function_usage_map(This);
3456 ffu_map = This->fixed_function_usage_map;
3458 if (This->max_ffp_textures == gl_info->limits.texture_stages
3459 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3461 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3463 if (!(ffu_map & 1)) continue;
3465 if (This->texUnitMap[i] != i) {
3466 device_map_stage(This, i, i);
3467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3468 markTextureStagesDirty(This, i);
3474 /* Now work out the mapping */
3476 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3478 if (!(ffu_map & 1)) continue;
3480 if (This->texUnitMap[i] != tex) {
3481 device_map_stage(This, i, tex);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3483 markTextureStagesDirty(This, i);
3490 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3492 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3493 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3496 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3497 if (sampler_type[i] && This->texUnitMap[i] != i)
3499 device_map_stage(This, i, i);
3500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3501 if (i < gl_info->limits.texture_stages)
3503 markTextureStagesDirty(This, i);
3509 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3510 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3512 DWORD current_mapping = This->rev_tex_unit_map[unit];
3514 /* Not currently used */
3515 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3517 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3518 /* Used by a fragment sampler */
3520 if (!pshader_sampler_tokens) {
3521 /* No pixel shader, check fixed function */
3522 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3525 /* Pixel shader, check the shader's sampler map */
3526 return !pshader_sampler_tokens[current_mapping];
3529 /* Used by a vertex sampler */
3530 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3533 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3535 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3536 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3537 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3538 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3542 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3544 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3545 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3546 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3549 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3550 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3551 if (vshader_sampler_type[i])
3553 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3555 /* Already mapped somewhere */
3559 while (start >= 0) {
3560 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3562 device_map_stage(This, vsampler_idx, start);
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3575 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3577 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3578 BOOL vs = use_vs(This->stateBlock);
3579 BOOL ps = use_ps(This->stateBlock);
3582 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3583 * that would be really messy and require shader recompilation
3584 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3585 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3587 if (ps) device_map_psamplers(This, gl_info);
3588 else device_map_fixed_function_samplers(This, gl_info);
3590 if (vs) device_map_vsamplers(This, ps, gl_info);
3593 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3595 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3596 This->updateStateBlock->pixelShader = pShader;
3597 This->updateStateBlock->changed.pixelShader = TRUE;
3599 /* Handle recording of state blocks */
3600 if (This->isRecordingState) {
3601 TRACE("Recording... not performing anything\n");
3604 if (This->isRecordingState) {
3605 TRACE("Recording... not performing anything\n");
3606 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3607 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3611 if(pShader == oldShader) {
3612 TRACE("App is setting the old pixel shader over, nothing to do\n");
3616 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3617 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3619 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3625 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3627 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3628 IWineD3DPixelShader *shader;
3630 TRACE("iface %p.\n", iface);
3632 shader = device->stateBlock->pixelShader;
3633 if (shader) IWineD3DPixelShader_AddRef(shader);
3635 TRACE("Returning %p.\n", shader);
3639 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3640 IWineD3DDevice *iface,
3642 CONST BOOL *srcData,
3645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3646 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3648 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3649 iface, srcData, start, count);
3651 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3653 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3654 for (i = 0; i < cnt; i++)
3655 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3657 for (i = start; i < cnt + start; ++i) {
3658 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3661 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3666 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3667 IWineD3DDevice *iface,
3672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3673 int cnt = min(count, MAX_CONST_B - start);
3675 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3676 iface, dstData, start, count);
3678 if (!dstData || cnt < 0)
3679 return WINED3DERR_INVALIDCALL;
3681 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3685 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3686 IWineD3DDevice *iface,
3691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3692 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3694 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3695 iface, srcData, start, count);
3697 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3699 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3700 for (i = 0; i < cnt; i++)
3701 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3702 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3704 for (i = start; i < cnt + start; ++i) {
3705 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3708 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3713 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3714 IWineD3DDevice *iface,
3719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3720 int cnt = min(count, MAX_CONST_I - start);
3722 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3723 iface, dstData, start, count);
3725 if (!dstData || cnt < 0)
3726 return WINED3DERR_INVALIDCALL;
3728 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3732 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3733 IWineD3DDevice *iface,
3735 CONST float *srcData,
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3742 iface, srcData, start, count);
3744 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3745 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3746 return WINED3DERR_INVALIDCALL;
3748 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3750 for (i = 0; i < count; i++)
3751 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3752 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3755 if (!This->isRecordingState)
3757 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3761 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3762 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3767 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3768 IWineD3DDevice *iface,
3773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3774 int cnt = min(count, This->d3d_pshader_constantF - start);
3776 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3777 iface, dstData, start, count);
3779 if (!dstData || cnt < 0)
3780 return WINED3DERR_INVALIDCALL;
3782 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3786 /* Context activation is done by the caller. */
3787 /* Do not call while under the GL lock. */
3788 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3789 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3790 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3793 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3794 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3797 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3801 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3803 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3806 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3808 ERR("Source has no position mask\n");
3809 return WINED3DERR_INVALIDCALL;
3812 if (!dest->resource.allocatedMemory)
3813 buffer_get_sysmem(dest, gl_info);
3815 /* Get a pointer into the destination vbo(create one if none exists) and
3816 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3818 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3820 dest->flags |= WINED3D_BUFFER_CREATEBO;
3821 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3824 if (dest->buffer_object)
3826 unsigned char extrabytes = 0;
3827 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3828 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3829 * this may write 4 extra bytes beyond the area that should be written
3831 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3832 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3833 if(!dest_conv_addr) {
3834 ERR("Out of memory\n");
3835 /* Continue without storing converted vertices */
3837 dest_conv = dest_conv_addr;
3840 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3842 static BOOL warned = FALSE;
3844 * The clipping code is not quite correct. Some things need
3845 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3846 * so disable clipping for now.
3847 * (The graphics in Half-Life are broken, and my processvertices
3848 * test crashes with IDirect3DDevice3)
3854 FIXME("Clipping is broken and disabled for now\n");
3856 } else doClip = FALSE;
3857 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3859 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3862 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3863 WINED3DTS_PROJECTION,
3865 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3866 WINED3DTS_WORLDMATRIX(0),
3869 TRACE("View mat:\n");
3870 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);
3871 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);
3872 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);
3873 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);
3875 TRACE("Proj mat:\n");
3876 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);
3877 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);
3878 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);
3879 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);
3881 TRACE("World mat:\n");
3882 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);
3883 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);
3884 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);
3885 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);
3887 /* Get the viewport */
3888 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3889 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3890 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3892 multiply_matrix(&mat,&view_mat,&world_mat);
3893 multiply_matrix(&mat,&proj_mat,&mat);
3895 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3897 for (i = 0; i < dwCount; i+= 1) {
3898 unsigned int tex_index;
3900 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3901 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3902 /* The position first */
3903 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3904 const float *p = (const float *)(element->data + i * element->stride);
3906 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3908 /* Multiplication with world, view and projection matrix */
3909 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);
3910 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);
3911 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);
3912 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);
3914 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3916 /* WARNING: The following things are taken from d3d7 and were not yet checked
3917 * against d3d8 or d3d9!
3920 /* Clipping conditions: From msdn
3922 * A vertex is clipped if it does not match the following requirements
3926 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3928 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3929 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3934 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3935 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3938 /* "Normal" viewport transformation (not clipped)
3939 * 1) The values are divided by rhw
3940 * 2) The y axis is negative, so multiply it with -1
3941 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3942 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3943 * 4) Multiply x with Width/2 and add Width/2
3944 * 5) The same for the height
3945 * 6) Add the viewpoint X and Y to the 2D coordinates and
3946 * The minimum Z value to z
3947 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3949 * Well, basically it's simply a linear transformation into viewport
3961 z *= vp.MaxZ - vp.MinZ;
3963 x += vp.Width / 2 + vp.X;
3964 y += vp.Height / 2 + vp.Y;
3969 /* That vertex got clipped
3970 * Contrary to OpenGL it is not dropped completely, it just
3971 * undergoes a different calculation.
3973 TRACE("Vertex got clipped\n");
3980 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3981 * outside of the main vertex buffer memory. That needs some more
3986 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3989 ( (float *) dest_ptr)[0] = x;
3990 ( (float *) dest_ptr)[1] = y;
3991 ( (float *) dest_ptr)[2] = z;
3992 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3994 dest_ptr += 3 * sizeof(float);
3996 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3997 dest_ptr += sizeof(float);
4002 ( (float *) dest_conv)[0] = x * w;
4003 ( (float *) dest_conv)[1] = y * w;
4004 ( (float *) dest_conv)[2] = z * w;
4005 ( (float *) dest_conv)[3] = w;
4007 dest_conv += 3 * sizeof(float);
4009 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4010 dest_conv += sizeof(float);
4014 if (DestFVF & WINED3DFVF_PSIZE) {
4015 dest_ptr += sizeof(DWORD);
4016 if(dest_conv) dest_conv += sizeof(DWORD);
4018 if (DestFVF & WINED3DFVF_NORMAL) {
4019 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4020 const float *normal = (const float *)(element->data + i * element->stride);
4021 /* AFAIK this should go into the lighting information */
4022 FIXME("Didn't expect the destination to have a normal\n");
4023 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4025 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4029 if (DestFVF & WINED3DFVF_DIFFUSE) {
4030 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4031 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4032 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4034 static BOOL warned = FALSE;
4037 ERR("No diffuse color in source, but destination has one\n");
4041 *( (DWORD *) dest_ptr) = 0xffffffff;
4042 dest_ptr += sizeof(DWORD);
4045 *( (DWORD *) dest_conv) = 0xffffffff;
4046 dest_conv += sizeof(DWORD);
4050 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4052 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4053 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4054 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4055 dest_conv += sizeof(DWORD);
4060 if (DestFVF & WINED3DFVF_SPECULAR)
4062 /* What's the color value in the feedback buffer? */
4063 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4064 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4065 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4067 static BOOL warned = FALSE;
4070 ERR("No specular color in source, but destination has one\n");
4074 *( (DWORD *) dest_ptr) = 0xFF000000;
4075 dest_ptr += sizeof(DWORD);
4078 *( (DWORD *) dest_conv) = 0xFF000000;
4079 dest_conv += sizeof(DWORD);
4083 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4085 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4086 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4087 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4088 dest_conv += sizeof(DWORD);
4093 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4094 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4095 const float *tex_coord = (const float *)(element->data + i * element->stride);
4096 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4098 ERR("No source texture, but destination requests one\n");
4099 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4100 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4103 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4105 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4115 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4116 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4117 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4118 dwCount * get_flexible_vertex_size(DestFVF),
4120 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4124 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4129 #undef copy_and_next
4131 /* Do not call while under the GL lock. */
4132 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4133 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4137 struct wined3d_stream_info stream_info;
4138 const struct wined3d_gl_info *gl_info;
4139 struct wined3d_context *context;
4140 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4143 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4146 ERR("Output vertex declaration not implemented yet\n");
4149 /* Need any context to write to the vbo. */
4150 context = context_acquire(This, NULL);
4151 gl_info = context->gl_info;
4153 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4154 * control the streamIsUP flag, thus restore it afterwards.
4156 This->stateBlock->streamIsUP = FALSE;
4157 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4158 This->stateBlock->streamIsUP = streamWasUP;
4160 if(vbo || SrcStartIndex) {
4162 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4163 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4165 * Also get the start index in, but only loop over all elements if there's something to add at all.
4167 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4169 struct wined3d_stream_info_element *e;
4171 if (!(stream_info.use_map & (1 << i))) continue;
4173 e = &stream_info.elements[i];
4174 if (e->buffer_object)
4176 struct wined3d_buffer *vb = This->stateBlock->streams[e->stream_idx].buffer;
4177 e->buffer_object = 0;
4178 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4180 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4181 vb->buffer_object = 0;
4184 if (e->data) e->data += e->stride * SrcStartIndex;
4188 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4189 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4191 context_release(context);
4197 * Get / Set Texture Stage States
4198 * TODO: Verify against dx9 definitions
4200 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4203 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4206 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4208 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4210 WARN("Invalid Type %d passed.\n", Type);
4214 if (Stage >= gl_info->limits.texture_stages)
4216 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4217 Stage, gl_info->limits.texture_stages - 1);
4221 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4222 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4223 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4225 if (This->isRecordingState) {
4226 TRACE("Recording... not performing anything\n");
4230 /* Checked after the assignments to allow proper stateblock recording */
4231 if(oldValue == Value) {
4232 TRACE("App is setting the old value over, nothing to do\n");
4236 if (Stage > This->stateBlock->state.lowest_disabled_stage
4237 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4238 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4240 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4241 * Changes in other states are important on disabled stages too
4246 if(Type == WINED3DTSS_COLOROP) {
4249 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4250 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4251 * they have to be disabled
4253 * The current stage is dirtified below.
4255 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4257 TRACE("Additionally dirtifying stage %u\n", i);
4258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4260 This->stateBlock->state.lowest_disabled_stage = Stage;
4261 TRACE("New lowest disabled: %u\n", Stage);
4262 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4263 /* Previously disabled stage enabled. Stages above it may need enabling
4264 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4265 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4267 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4270 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4272 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4274 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4277 This->stateBlock->state.lowest_disabled_stage = i;
4278 TRACE("New lowest disabled: %u\n", i);
4282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4287 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4291 TRACE("iface %p, stage %u, state %s, value %p.\n",
4292 iface, Stage, debug_d3dtexturestate(Type), pValue);
4294 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4296 WARN("Invalid Type %d passed.\n", Type);
4300 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4301 TRACE("Returning %#x.\n", *pValue);
4309 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4310 DWORD stage, IWineD3DBaseTexture *texture)
4312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4313 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4314 IWineD3DBaseTexture *prev;
4316 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4318 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4319 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4321 /* Windows accepts overflowing this array... we do not. */
4322 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4324 WARN("Ignoring invalid stage %u.\n", stage);
4328 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4329 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4331 WARN("Rejecting attempt to set scratch texture.\n");
4332 return WINED3DERR_INVALIDCALL;
4335 This->updateStateBlock->changed.textures |= 1 << stage;
4337 prev = This->updateStateBlock->textures[stage];
4338 TRACE("Previous texture %p.\n", prev);
4340 if (texture == prev)
4342 TRACE("App is setting the same texture again, nothing to do.\n");
4346 TRACE("Setting new texture to %p.\n", texture);
4347 This->updateStateBlock->textures[stage] = texture;
4349 if (This->isRecordingState)
4351 TRACE("Recording... not performing anything\n");
4353 if (texture) IWineD3DBaseTexture_AddRef(texture);
4354 if (prev) IWineD3DBaseTexture_Release(prev);
4361 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4362 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4363 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4365 IWineD3DBaseTexture_AddRef(texture);
4367 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4372 if (!prev && stage < gl_info->limits.texture_stages)
4374 /* The source arguments for color and alpha ops have different
4375 * meanings when a NULL texture is bound, so the COLOROP and
4376 * ALPHAOP have to be dirtified. */
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4381 if (bind_count == 1) t->baseTexture.sampler = stage;
4386 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4387 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4389 IWineD3DBaseTexture_Release(prev);
4391 if (!texture && stage < gl_info->limits.texture_stages)
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4397 if (bind_count && t->baseTexture.sampler == stage)
4401 /* Search for other stages the texture is bound to. Shouldn't
4402 * happen if applications bind textures to a single stage only. */
4403 TRACE("Searching for other stages the texture is bound to.\n");
4404 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4406 if (This->updateStateBlock->textures[i] == prev)
4408 TRACE("Texture is also bound to stage %u.\n", i);
4409 t->baseTexture.sampler = i;
4416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4421 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4424 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4426 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4427 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4430 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4431 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4432 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4435 *ppTexture=This->stateBlock->textures[Stage];
4437 IWineD3DBaseTexture_AddRef(*ppTexture);
4439 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4447 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4448 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4450 IWineD3DSwapChain *swapchain;
4453 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4454 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4456 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4459 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4463 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4464 IWineD3DSwapChain_Release(swapchain);
4467 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4474 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 WARN("(%p) : stub, calling idirect3d for now\n", This);
4477 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4480 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4482 IWineD3DSwapChain *swapChain;
4485 if(iSwapChain > 0) {
4486 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4487 if (hr == WINED3D_OK) {
4488 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4489 IWineD3DSwapChain_Release(swapChain);
4491 FIXME("(%p) Error getting display mode\n", This);
4494 /* Don't read the real display mode,
4495 but return the stored mode instead. X11 can't change the color
4496 depth, and some apps are pretty angry if they SetDisplayMode from
4497 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4499 Also don't relay to the swapchain because with ddraw it's possible
4500 that there isn't a swapchain at all */
4501 pMode->Width = This->ddraw_width;
4502 pMode->Height = This->ddraw_height;
4503 pMode->Format = This->ddraw_format;
4504 pMode->RefreshRate = 0;
4512 * Stateblock related functions
4515 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4517 IWineD3DStateBlock *stateblock;
4520 TRACE("(%p)\n", This);
4522 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4524 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4525 if (FAILED(hr)) return hr;
4527 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4528 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4529 This->isRecordingState = TRUE;
4531 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4536 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4540 if (!This->isRecordingState) {
4541 WARN("(%p) not recording! returning error\n", This);
4542 *ppStateBlock = NULL;
4543 return WINED3DERR_INVALIDCALL;
4546 stateblock_init_contained_states(object);
4548 *ppStateBlock = (IWineD3DStateBlock*) object;
4549 This->isRecordingState = FALSE;
4550 This->updateStateBlock = This->stateBlock;
4551 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4552 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4553 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4558 * Scene related functions
4560 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4561 /* At the moment we have no need for any functionality at the beginning
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 TRACE("(%p)\n", This);
4567 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4568 return WINED3DERR_INVALIDCALL;
4570 This->inScene = TRUE;
4574 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 struct wined3d_context *context;
4579 TRACE("(%p)\n", This);
4581 if(!This->inScene) {
4582 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4583 return WINED3DERR_INVALIDCALL;
4586 context = context_acquire(This, NULL);
4587 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4589 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4591 context_release(context);
4593 This->inScene = FALSE;
4597 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4598 const RECT *pSourceRect, const RECT *pDestRect,
4599 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4601 IWineD3DSwapChain *swapChain = NULL;
4603 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4605 TRACE("iface %p.\n", iface);
4607 for(i = 0 ; i < swapchains ; i ++) {
4609 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4610 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4611 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4612 IWineD3DSwapChain_Release(swapChain);
4618 /* Do not call while under the GL lock. */
4619 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4620 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4622 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4623 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4626 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4627 iface, rect_count, rects, flags, color, depth, stencil);
4629 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4631 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4632 /* TODO: What about depth stencil buffers without stencil bits? */
4633 return WINED3DERR_INVALIDCALL;
4636 device_get_draw_rect(device, &draw_rect);
4638 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4639 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4646 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4647 WINED3DPRIMITIVETYPE primitive_type)
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4653 This->updateStateBlock->changed.primitive_type = TRUE;
4654 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4657 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4658 WINED3DPRIMITIVETYPE *primitive_type)
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4664 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4666 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4669 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4675 if(!This->stateBlock->vertexDecl) {
4676 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4677 return WINED3DERR_INVALIDCALL;
4680 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4681 if(This->stateBlock->streamIsUP) {
4682 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4683 This->stateBlock->streamIsUP = FALSE;
4686 if (This->stateBlock->loadBaseVertexIndex)
4688 This->stateBlock->loadBaseVertexIndex = 0;
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4691 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4692 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4696 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4700 IWineD3DBuffer *pIB;
4703 pIB = This->stateBlock->pIndexData;
4705 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4706 * without an index buffer set. (The first time at least...)
4707 * D3D8 simply dies, but I doubt it can do much harm to return
4708 * D3DERR_INVALIDCALL there as well. */
4709 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4710 return WINED3DERR_INVALIDCALL;
4713 if(!This->stateBlock->vertexDecl) {
4714 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4715 return WINED3DERR_INVALIDCALL;
4718 if(This->stateBlock->streamIsUP) {
4719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4720 This->stateBlock->streamIsUP = FALSE;
4722 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4724 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4726 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4732 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4733 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4737 drawPrimitive(iface, index_count, startIndex, idxStride,
4738 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4743 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4744 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4747 struct wined3d_stream_state *stream;
4750 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4751 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4753 if(!This->stateBlock->vertexDecl) {
4754 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4755 return WINED3DERR_INVALIDCALL;
4758 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4759 stream = &This->stateBlock->streams[0];
4760 vb = (IWineD3DBuffer *)stream->buffer;
4761 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4762 if (vb) IWineD3DBuffer_Release(vb);
4764 stream->stride = VertexStreamZeroStride;
4765 This->stateBlock->streamIsUP = TRUE;
4766 This->stateBlock->loadBaseVertexIndex = 0;
4768 /* TODO: Only mark dirty if drawing from a different UP address */
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4771 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4773 /* MSDN specifies stream zero settings must be set to NULL */
4774 stream->buffer = NULL;
4777 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4778 * the new stream sources or use UP drawing again
4783 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4784 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4785 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4789 struct wined3d_stream_state *stream;
4793 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4794 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4796 if(!This->stateBlock->vertexDecl) {
4797 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4798 return WINED3DERR_INVALIDCALL;
4801 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4807 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4808 stream = &This->stateBlock->streams[0];
4809 vb = (IWineD3DBuffer *)stream->buffer;
4810 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4811 if (vb) IWineD3DBuffer_Release(vb);
4813 stream->stride = VertexStreamZeroStride;
4814 This->stateBlock->streamIsUP = TRUE;
4816 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4817 This->stateBlock->baseVertexIndex = 0;
4818 This->stateBlock->loadBaseVertexIndex = 0;
4819 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4823 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4825 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4826 stream->buffer = NULL;
4828 ib = This->stateBlock->pIndexData;
4830 IWineD3DBuffer_Release(ib);
4831 This->stateBlock->pIndexData = NULL;
4833 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4834 * SetStreamSource to specify a vertex buffer
4840 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4841 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4845 /* Mark the state dirty until we have nicer tracking
4846 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4851 This->stateBlock->baseVertexIndex = 0;
4852 This->up_strided = DrawPrimStrideData;
4853 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4854 This->up_strided = NULL;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4859 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4860 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4863 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4865 /* Mark the state dirty until we have nicer tracking
4866 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4871 This->stateBlock->streamIsUP = TRUE;
4872 This->stateBlock->baseVertexIndex = 0;
4873 This->up_strided = DrawPrimStrideData;
4874 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4875 This->up_strided = NULL;
4879 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4880 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4881 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4883 WINED3DLOCKED_BOX src;
4884 WINED3DLOCKED_BOX dst;
4887 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4888 iface, pSourceVolume, pDestinationVolume);
4890 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4891 * dirtification to improve loading performance.
4893 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4894 if(FAILED(hr)) return hr;
4895 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4897 IWineD3DVolume_UnlockBox(pSourceVolume);
4901 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4903 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4905 IWineD3DVolume_UnlockBox(pSourceVolume);
4907 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4912 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4913 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4915 unsigned int level_count, i;
4916 WINED3DRESOURCETYPE type;
4919 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4921 /* Verify that the source and destination textures are non-NULL. */
4922 if (!src_texture || !dst_texture)
4924 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4925 return WINED3DERR_INVALIDCALL;
4928 if (src_texture == dst_texture)
4930 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4931 return WINED3DERR_INVALIDCALL;
4934 /* Verify that the source and destination textures are the same type. */
4935 type = IWineD3DBaseTexture_GetType(src_texture);
4936 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4938 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4939 return WINED3DERR_INVALIDCALL;
4942 /* Check that both textures have the identical numbers of levels. */
4943 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4944 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4946 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4947 return WINED3DERR_INVALIDCALL;
4950 /* Make sure that the destination texture is loaded. */
4951 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4953 /* Update every surface level of the texture. */
4956 case WINED3DRTYPE_TEXTURE:
4958 IWineD3DSurface *src_surface;
4959 IWineD3DSurface *dst_surface;
4961 for (i = 0; i < level_count; ++i)
4963 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4964 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4965 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4966 IWineD3DSurface_Release(dst_surface);
4967 IWineD3DSurface_Release(src_surface);
4970 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4977 case WINED3DRTYPE_CUBETEXTURE:
4979 IWineD3DSurface *src_surface;
4980 IWineD3DSurface *dst_surface;
4981 WINED3DCUBEMAP_FACES face;
4983 for (i = 0; i < level_count; ++i)
4985 /* Update each cube face. */
4986 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4988 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4989 face, i, &src_surface);
4990 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4991 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4992 face, i, &dst_surface);
4993 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4994 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4995 IWineD3DSurface_Release(dst_surface);
4996 IWineD3DSurface_Release(src_surface);
4999 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5007 case WINED3DRTYPE_VOLUMETEXTURE:
5009 IWineD3DVolume *src_volume;
5010 IWineD3DVolume *dst_volume;
5012 for (i = 0; i < level_count; ++i)
5014 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5015 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5016 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5017 IWineD3DVolume_Release(dst_volume);
5018 IWineD3DVolume_Release(src_volume);
5021 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5029 FIXME("Unsupported texture type %#x.\n", type);
5030 return WINED3DERR_INVALIDCALL;
5036 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5037 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5039 IWineD3DSwapChain *swapchain;
5042 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5044 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5045 if (FAILED(hr)) return hr;
5047 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5048 IWineD3DSwapChain_Release(swapchain);
5053 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 IWineD3DBaseTextureImpl *texture;
5058 TRACE("(%p) : %p\n", This, pNumPasses);
5060 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5062 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5064 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5065 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5067 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5069 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5070 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5073 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5074 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5076 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5078 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5081 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5083 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5086 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5087 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5089 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5094 /* return a sensible default */
5097 TRACE("returning D3D_OK\n");
5101 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5105 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5107 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5108 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5109 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5111 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5116 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 PALETTEENTRY **palettes;
5122 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5124 if (PaletteNumber >= MAX_PALETTES) {
5125 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5126 return WINED3DERR_INVALIDCALL;
5129 if (PaletteNumber >= This->NumberOfPalettes) {
5130 NewSize = This->NumberOfPalettes;
5133 } while(PaletteNumber >= NewSize);
5134 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5136 ERR("Out of memory!\n");
5137 return E_OUTOFMEMORY;
5139 This->palettes = palettes;
5140 This->NumberOfPalettes = NewSize;
5143 if (!This->palettes[PaletteNumber]) {
5144 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5145 if (!This->palettes[PaletteNumber]) {
5146 ERR("Out of memory!\n");
5147 return E_OUTOFMEMORY;
5151 for (j = 0; j < 256; ++j) {
5152 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5153 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5154 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5155 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5157 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5158 TRACE("(%p) : returning\n", This);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5166 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5167 /* What happens in such situation isn't documented; Native seems to silently abort
5168 on such conditions. Return Invalid Call. */
5169 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5170 return WINED3DERR_INVALIDCALL;
5172 for (j = 0; j < 256; ++j) {
5173 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5174 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5175 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5176 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5178 TRACE("(%p) : returning\n", This);
5182 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5184 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5185 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5186 (tested with reference rasterizer). Return Invalid Call. */
5187 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5188 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5189 return WINED3DERR_INVALIDCALL;
5191 /*TODO: stateblocks */
5192 if (This->currentPalette != PaletteNumber) {
5193 This->currentPalette = PaletteNumber;
5194 dirtify_p8_texture_samplers(This);
5196 TRACE("(%p) : returning\n", This);
5200 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 WARN("(%p) : returning Invalid Call\n", This);
5206 return WINED3DERR_INVALIDCALL;
5208 /*TODO: stateblocks */
5209 *PaletteNumber = This->currentPalette;
5210 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5214 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5219 FIXME("(%p) : stub\n", This);
5223 This->softwareVertexProcessing = bSoftware;
5228 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 FIXME("(%p) : stub\n", This);
5236 return This->softwareVertexProcessing;
5239 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5240 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5242 IWineD3DSwapChain *swapchain;
5245 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5246 iface, swapchain_idx, raster_status);
5248 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5251 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5255 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5256 IWineD3DSwapChain_Release(swapchain);
5259 WARN("Failed to get raster status, hr %#x.\n", hr);
5266 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5269 if(nSegments != 0.0f) {
5272 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5279 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5284 FIXME("iface %p stub!\n", iface);
5290 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5291 IWineD3DSurface *src_surface, const RECT *src_rect,
5292 IWineD3DSurface *dst_surface, const POINT *dst_point)
5294 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5295 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5297 const struct wined3d_format *src_format;
5298 const struct wined3d_format *dst_format;
5299 const struct wined3d_gl_info *gl_info;
5300 struct wined3d_context *context;
5301 const unsigned char *data;
5302 UINT update_w, update_h;
5303 CONVERT_TYPES convert;
5307 struct wined3d_format format;
5309 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5310 iface, src_surface, wine_dbgstr_rect(src_rect),
5311 dst_surface, wine_dbgstr_point(dst_point));
5313 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5315 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5316 src_surface, dst_surface);
5317 return WINED3DERR_INVALIDCALL;
5320 src_format = src_impl->resource.format;
5321 dst_format = dst_impl->resource.format;
5323 if (src_format->id != dst_format->id)
5325 WARN("Source and destination surfaces should have the same format.\n");
5326 return WINED3DERR_INVALIDCALL;
5329 dst_x = dst_point ? dst_point->x : 0;
5330 dst_y = dst_point ? dst_point->y : 0;
5332 /* This call loads the OpenGL surface directly, instead of copying the
5333 * surface to the destination's sysmem copy. If surface conversion is
5334 * needed, use BltFast instead to copy in sysmem and use regular surface
5336 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5337 if (convert != NO_CONVERSION || format.convert)
5338 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5340 context = context_acquire(This, NULL);
5341 gl_info = context->gl_info;
5344 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5345 checkGLcall("glActiveTextureARB");
5348 /* Make sure the surface is loaded and up to date */
5349 surface_internal_preload(dst_impl, SRGB_RGB);
5350 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5352 src_w = src_impl->currentDesc.Width;
5353 src_h = src_impl->currentDesc.Height;
5354 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5355 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5357 data = IWineD3DSurface_GetData(src_surface);
5358 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5362 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5364 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5365 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5366 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5370 data += (src_rect->top / src_format->block_height) * src_pitch;
5371 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5374 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5375 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5376 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5378 if (row_length == src_pitch)
5380 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5381 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5387 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5388 * can't use the unpack row length like below. */
5389 for (row = 0, y = dst_y; row < row_count; ++row)
5391 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5392 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5393 y += src_format->block_height;
5397 checkGLcall("glCompressedTexSubImage2DARB");
5403 data += src_rect->top * src_w * src_format->byte_count;
5404 data += src_rect->left * src_format->byte_count;
5407 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5408 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5409 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5411 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5412 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5413 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5414 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5415 checkGLcall("glTexSubImage2D");
5419 context_release(context);
5421 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5422 sampler = This->rev_tex_unit_map[0];
5423 if (sampler != WINED3D_UNMAPPED_STAGE)
5425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5431 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5433 struct WineD3DRectPatch *patch;
5434 GLenum old_primitive_type;
5438 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5440 if(!(Handle || pRectPatchInfo)) {
5441 /* TODO: Write a test for the return value, thus the FIXME */
5442 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5443 return WINED3DERR_INVALIDCALL;
5447 i = PATCHMAP_HASHFUNC(Handle);
5449 LIST_FOR_EACH(e, &This->patches[i]) {
5450 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5451 if(patch->Handle == Handle) {
5458 TRACE("Patch does not exist. Creating a new one\n");
5459 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5460 patch->Handle = Handle;
5461 list_add_head(&This->patches[i], &patch->entry);
5463 TRACE("Found existing patch %p\n", patch);
5466 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5467 * attributes we have to tesselate, read back, and draw. This needs a patch
5468 * management structure instance. Create one.
5470 * A possible improvement is to check if a vertex shader is used, and if not directly
5473 FIXME("Drawing an uncached patch. This is slow\n");
5474 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5477 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5478 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5479 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5482 TRACE("Tesselation density or patch info changed, retesselating\n");
5484 if(pRectPatchInfo) {
5485 patch->RectPatchInfo = *pRectPatchInfo;
5487 patch->numSegs[0] = pNumSegs[0];
5488 patch->numSegs[1] = pNumSegs[1];
5489 patch->numSegs[2] = pNumSegs[2];
5490 patch->numSegs[3] = pNumSegs[3];
5492 hr = tesselate_rectpatch(This, patch);
5494 WARN("Patch tesselation failed\n");
5496 /* Do not release the handle to store the params of the patch */
5498 HeapFree(GetProcessHeap(), 0, patch);
5504 This->currentPatch = patch;
5505 old_primitive_type = This->stateBlock->gl_primitive_type;
5506 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5507 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5508 This->stateBlock->gl_primitive_type = old_primitive_type;
5509 This->currentPatch = NULL;
5511 /* Destroy uncached patches */
5513 HeapFree(GetProcessHeap(), 0, patch->mem);
5514 HeapFree(GetProcessHeap(), 0, patch);
5519 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5520 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5522 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5523 iface, handle, segment_count, patch_info);
5528 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5531 struct WineD3DRectPatch *patch;
5533 TRACE("(%p) Handle(%d)\n", This, Handle);
5535 i = PATCHMAP_HASHFUNC(Handle);
5536 LIST_FOR_EACH(e, &This->patches[i]) {
5537 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5538 if(patch->Handle == Handle) {
5539 TRACE("Deleting patch %p\n", patch);
5540 list_remove(&patch->entry);
5541 HeapFree(GetProcessHeap(), 0, patch->mem);
5542 HeapFree(GetProcessHeap(), 0, patch);
5547 /* TODO: Write a test for the return value */
5548 FIXME("Attempt to destroy nonexistent patch\n");
5549 return WINED3DERR_INVALIDCALL;
5552 /* Do not call while under the GL lock. */
5553 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5554 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5556 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5558 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5559 iface, surface, wine_dbgstr_rect(rect),
5560 color->r, color->g, color->b, color->a);
5562 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5564 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5565 return WINED3DERR_INVALIDCALL;
5568 return surface_color_fill(s, rect, color);
5571 /* Do not call while under the GL lock. */
5572 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5573 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5575 IWineD3DResource *resource;
5578 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5581 ERR("Failed to get resource, hr %#x\n", hr);
5585 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5587 FIXME("Only supported on surface resources\n");
5588 IWineD3DResource_Release(resource);
5592 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5593 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5595 IWineD3DResource_Release(resource);
5598 /* rendertarget and depth stencil functions */
5599 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5600 DWORD render_target_idx, IWineD3DSurface **render_target)
5602 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5604 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5605 iface, render_target_idx, render_target);
5607 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5609 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5610 return WINED3DERR_INVALIDCALL;
5613 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5614 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5616 TRACE("Returning render target %p.\n", *render_target);
5621 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5622 IWineD3DSurface *front, IWineD3DSurface *back)
5624 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5625 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5626 IWineD3DSwapChainImpl *swapchain;
5629 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5631 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5633 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5637 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5639 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5640 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5641 return WINED3DERR_INVALIDCALL;
5646 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5648 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5649 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5650 return WINED3DERR_INVALIDCALL;
5653 if (!swapchain->back_buffers)
5655 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5656 if (!swapchain->back_buffers)
5658 ERR("Failed to allocate back buffer array memory.\n");
5659 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5660 return E_OUTOFMEMORY;
5665 if (swapchain->front_buffer != front_impl)
5667 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5669 if (swapchain->front_buffer)
5670 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5671 swapchain->front_buffer = front_impl;
5674 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5677 if (swapchain->back_buffers[0] != back_impl)
5679 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5681 if (swapchain->back_buffers[0])
5682 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5683 swapchain->back_buffers[0] = back_impl;
5687 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5688 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5689 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5690 swapchain->presentParms.BackBufferCount = 1;
5692 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5696 swapchain->presentParms.BackBufferCount = 0;
5697 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5698 swapchain->back_buffers = NULL;
5702 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5706 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5708 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5710 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5712 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5713 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5714 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5715 IWineD3DSurface_AddRef(*depth_stencil);
5720 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5721 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5723 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5724 IWineD3DSurfaceImpl *prev;
5726 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5727 iface, render_target_idx, render_target, set_viewport);
5729 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5731 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5732 return WINED3DERR_INVALIDCALL;
5735 prev = device->render_targets[render_target_idx];
5736 if (render_target == (IWineD3DSurface *)prev)
5738 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5742 /* Render target 0 can't be set to NULL. */
5743 if (!render_target && !render_target_idx)
5745 WARN("Trying to set render target 0 to NULL.\n");
5746 return WINED3DERR_INVALIDCALL;
5749 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5751 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5752 return WINED3DERR_INVALIDCALL;
5755 if (render_target) IWineD3DSurface_AddRef(render_target);
5756 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5757 /* Release after the assignment, to prevent device_resource_released()
5758 * from seeing the surface as still in use. */
5759 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5761 /* Render target 0 is special. */
5762 if (!render_target_idx && set_viewport)
5764 /* Set the viewport and scissor rectangles, if requested. Tests show
5765 * that stateblock recording is ignored, the change goes directly
5766 * into the primary stateblock. */
5767 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5768 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5769 device->stateBlock->state.viewport.X = 0;
5770 device->stateBlock->state.viewport.Y = 0;
5771 device->stateBlock->state.viewport.MaxZ = 1.0f;
5772 device->stateBlock->state.viewport.MinZ = 0.0f;
5773 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5775 device->stateBlock->state.scissor_rect.top = 0;
5776 device->stateBlock->state.scissor_rect.left = 0;
5777 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5778 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5779 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5785 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5788 IWineD3DSurfaceImpl *tmp;
5790 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5792 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5794 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5798 if (This->depth_stencil)
5800 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5801 || This->depth_stencil->Flags & SFLAG_DISCARD)
5803 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5804 This->depth_stencil->currentDesc.Width,
5805 This->depth_stencil->currentDesc.Height);
5806 if (This->depth_stencil == This->onscreen_depth_stencil)
5808 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5809 This->onscreen_depth_stencil = NULL;
5814 tmp = This->depth_stencil;
5815 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5816 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5817 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5819 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5821 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5830 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5831 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5834 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5835 WINED3DLOCKED_RECT lockedRect;
5837 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5838 iface, XHotSpot, YHotSpot, cursor_image);
5840 /* some basic validation checks */
5841 if (This->cursorTexture)
5843 struct wined3d_context *context = context_acquire(This, NULL);
5845 glDeleteTextures(1, &This->cursorTexture);
5847 context_release(context);
5848 This->cursorTexture = 0;
5851 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5852 This->haveHardwareCursor = TRUE;
5854 This->haveHardwareCursor = FALSE;
5858 WINED3DLOCKED_RECT rect;
5860 /* MSDN: Cursor must be A8R8G8B8 */
5861 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5863 WARN("surface %p has an invalid format.\n", cursor_image);
5864 return WINED3DERR_INVALIDCALL;
5867 /* MSDN: Cursor must be smaller than the display mode */
5868 if (s->currentDesc.Width > This->ddraw_width
5869 || s->currentDesc.Height > This->ddraw_height)
5871 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5872 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5873 return WINED3DERR_INVALIDCALL;
5876 if (!This->haveHardwareCursor) {
5877 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5879 /* Do not store the surface's pointer because the application may
5880 * release it after setting the cursor image. Windows doesn't
5881 * addref the set surface, so we can't do this either without
5882 * creating circular refcount dependencies. Copy out the gl texture
5885 This->cursorWidth = s->currentDesc.Width;
5886 This->cursorHeight = s->currentDesc.Height;
5887 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5889 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5890 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5891 struct wined3d_context *context;
5892 char *mem, *bits = rect.pBits;
5893 GLint intfmt = format->glInternal;
5894 GLint gl_format = format->glFormat;
5895 GLint type = format->glType;
5896 INT height = This->cursorHeight;
5897 INT width = This->cursorWidth;
5898 INT bpp = format->byte_count;
5902 /* Reformat the texture memory (pitch and width can be
5904 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5905 for(i = 0; i < height; i++)
5906 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5907 IWineD3DSurface_UnlockRect(cursor_image);
5909 context = context_acquire(This, NULL);
5913 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5915 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5916 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5919 /* Make sure that a proper texture unit is selected */
5920 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5921 checkGLcall("glActiveTextureARB");
5922 sampler = This->rev_tex_unit_map[0];
5923 if (sampler != WINED3D_UNMAPPED_STAGE)
5925 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5927 /* Create a new cursor texture */
5928 glGenTextures(1, &This->cursorTexture);
5929 checkGLcall("glGenTextures");
5930 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5931 checkGLcall("glBindTexture");
5932 /* Copy the bitmap memory into the cursor texture */
5933 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5934 HeapFree(GetProcessHeap(), 0, mem);
5935 checkGLcall("glTexImage2D");
5937 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5939 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5940 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5945 context_release(context);
5949 FIXME("A cursor texture was not returned.\n");
5950 This->cursorTexture = 0;
5955 /* Draw a hardware cursor */
5956 ICONINFO cursorInfo;
5958 /* Create and clear maskBits because it is not needed for
5959 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5961 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5962 (s->currentDesc.Width * s->currentDesc.Height / 8));
5963 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5964 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5965 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5967 cursorInfo.fIcon = FALSE;
5968 cursorInfo.xHotspot = XHotSpot;
5969 cursorInfo.yHotspot = YHotSpot;
5970 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5971 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5972 IWineD3DSurface_UnlockRect(cursor_image);
5973 /* Create our cursor and clean up. */
5974 cursor = CreateIconIndirect(&cursorInfo);
5976 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5977 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5978 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5979 This->hardwareCursor = cursor;
5980 HeapFree(GetProcessHeap(), 0, maskBits);
5984 This->xHotSpot = XHotSpot;
5985 This->yHotSpot = YHotSpot;
5989 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5991 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5993 This->xScreenSpace = XScreenSpace;
5994 This->yScreenSpace = YScreenSpace;
6000 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6002 BOOL oldVisible = This->bCursorVisible;
6005 TRACE("(%p) : visible(%d)\n", This, bShow);
6008 * When ShowCursor is first called it should make the cursor appear at the OS's last
6009 * known cursor position. Because of this, some applications just repetitively call
6010 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6013 This->xScreenSpace = pt.x;
6014 This->yScreenSpace = pt.y;
6016 if (This->haveHardwareCursor) {
6017 This->bCursorVisible = bShow;
6019 SetCursor(This->hardwareCursor);
6025 if (This->cursorTexture)
6026 This->bCursorVisible = bShow;
6032 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6033 TRACE("checking resource %p for eviction\n", resource);
6034 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6035 TRACE("Evicting %p\n", resource);
6036 IWineD3DResource_UnLoad(resource);
6038 IWineD3DResource_Release(resource);
6042 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6044 TRACE("iface %p.\n", iface);
6046 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6047 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6048 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6053 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6055 IWineD3DDeviceImpl *device = surface->resource.device;
6056 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6058 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6059 if(surface->Flags & SFLAG_DIBSECTION) {
6060 /* Release the DC */
6061 SelectObject(surface->hDC, surface->dib.holdbitmap);
6062 DeleteDC(surface->hDC);
6063 /* Release the DIB section */
6064 DeleteObject(surface->dib.DIBsection);
6065 surface->dib.bitmap_data = NULL;
6066 surface->resource.allocatedMemory = NULL;
6067 surface->Flags &= ~SFLAG_DIBSECTION;
6069 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6070 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6071 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6072 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6074 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6075 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6077 surface->pow2Width = surface->pow2Height = 1;
6078 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6079 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6082 if (surface->texture_name)
6084 struct wined3d_context *context = context_acquire(device, NULL);
6086 glDeleteTextures(1, &surface->texture_name);
6088 context_release(context);
6089 surface->texture_name = 0;
6090 surface->Flags &= ~SFLAG_CLIENT;
6092 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6093 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6094 surface->Flags |= SFLAG_NONPOW2;
6096 surface->Flags &= ~SFLAG_NONPOW2;
6098 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6099 surface->resource.allocatedMemory = NULL;
6100 surface->resource.heapMemory = NULL;
6101 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6103 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6105 if (!surface_init_sysmem(surface))
6107 return E_OUTOFMEMORY;
6112 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6113 TRACE("Unloading resource %p\n", resource);
6114 IWineD3DResource_UnLoad(resource);
6115 IWineD3DResource_Release(resource);
6119 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6122 WINED3DDISPLAYMODE m;
6125 /* All Windowed modes are supported, as is leaving the current mode */
6126 if(pp->Windowed) return TRUE;
6127 if(!pp->BackBufferWidth) return TRUE;
6128 if(!pp->BackBufferHeight) return TRUE;
6130 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6131 for(i = 0; i < count; i++) {
6132 memset(&m, 0, sizeof(m));
6133 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6135 ERR("EnumAdapterModes failed\n");
6137 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6138 /* Mode found, it is supported */
6142 /* Mode not found -> not supported */
6146 /* Do not call while under the GL lock. */
6147 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6150 const struct wined3d_gl_info *gl_info;
6151 struct wined3d_context *context;
6152 IWineD3DBaseShaderImpl *shader;
6154 context = context_acquire(This, NULL);
6155 gl_info = context->gl_info;
6157 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6158 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6159 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6163 if(This->depth_blt_texture) {
6164 glDeleteTextures(1, &This->depth_blt_texture);
6165 This->depth_blt_texture = 0;
6167 if (This->depth_blt_rb) {
6168 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6169 This->depth_blt_rb = 0;
6170 This->depth_blt_rb_w = 0;
6171 This->depth_blt_rb_h = 0;
6175 This->blitter->free_private(iface);
6176 This->frag_pipe->free_private(iface);
6177 This->shader_backend->shader_free_private(iface);
6178 destroy_dummy_textures(This, gl_info);
6180 context_release(context);
6182 while (This->numContexts)
6184 context_destroy(This, This->contexts[0]);
6186 HeapFree(GetProcessHeap(), 0, swapchain->context);
6187 swapchain->context = NULL;
6188 swapchain->num_contexts = 0;
6191 /* Do not call while under the GL lock. */
6192 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6195 struct wined3d_context *context;
6197 IWineD3DSurfaceImpl *target;
6199 /* Recreate the primary swapchain's context */
6200 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6201 if (!swapchain->context)
6203 ERR("Failed to allocate memory for swapchain context array.\n");
6204 return E_OUTOFMEMORY;
6207 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6208 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6210 WARN("Failed to create context.\n");
6211 HeapFree(GetProcessHeap(), 0, swapchain->context);
6215 swapchain->context[0] = context;
6216 swapchain->num_contexts = 1;
6217 create_dummy_textures(This);
6218 context_release(context);
6220 hr = This->shader_backend->shader_alloc_private(iface);
6223 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6227 hr = This->frag_pipe->alloc_private(iface);
6230 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6231 This->shader_backend->shader_free_private(iface);
6235 hr = This->blitter->alloc_private(iface);
6238 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6239 This->frag_pipe->free_private(iface);
6240 This->shader_backend->shader_free_private(iface);
6247 context_acquire(This, NULL);
6248 destroy_dummy_textures(This, context->gl_info);
6249 context_release(context);
6250 context_destroy(This, context);
6251 HeapFree(GetProcessHeap(), 0, swapchain->context);
6252 swapchain->num_contexts = 0;
6256 /* Do not call while under the GL lock. */
6257 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6258 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6261 IWineD3DSwapChainImpl *swapchain;
6263 BOOL DisplayModeChanged = FALSE;
6264 WINED3DDISPLAYMODE mode;
6265 TRACE("(%p)\n", This);
6267 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6269 ERR("Failed to get the first implicit swapchain\n");
6273 if(!is_display_mode_supported(This, pPresentationParameters)) {
6274 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6275 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6276 pPresentationParameters->BackBufferHeight);
6277 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6278 return WINED3DERR_INVALIDCALL;
6281 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6282 * on an existing gl context, so there's no real need for recreation.
6284 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6286 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6288 TRACE("New params:\n");
6289 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6290 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6291 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6292 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6293 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6294 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6295 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6296 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6297 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6298 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6299 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6300 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6301 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6303 /* No special treatment of these parameters. Just store them */
6304 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6305 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6306 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6307 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6309 /* What to do about these? */
6310 if (pPresentationParameters->BackBufferCount
6311 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6312 ERR("Cannot change the back buffer count yet\n");
6314 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6315 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6316 ERR("Cannot change the back buffer format yet\n");
6319 if (pPresentationParameters->hDeviceWindow
6320 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6321 ERR("Cannot change the device window yet\n");
6323 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6327 TRACE("Creating the depth stencil buffer\n");
6329 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6330 pPresentationParameters->BackBufferWidth,
6331 pPresentationParameters->BackBufferHeight,
6332 pPresentationParameters->AutoDepthStencilFormat,
6333 pPresentationParameters->MultiSampleType,
6334 pPresentationParameters->MultiSampleQuality,
6336 (IWineD3DSurface **)&This->auto_depth_stencil);
6339 ERR("Failed to create the depth stencil buffer\n");
6340 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6341 return WINED3DERR_INVALIDCALL;
6345 if (This->onscreen_depth_stencil)
6347 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6348 This->onscreen_depth_stencil = NULL;
6351 /* Reset the depth stencil */
6352 if (pPresentationParameters->EnableAutoDepthStencil)
6353 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6355 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6357 TRACE("Resetting stateblock\n");
6358 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6359 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6361 delete_opengl_contexts(iface, swapchain);
6363 if(pPresentationParameters->Windowed) {
6364 mode.Width = swapchain->orig_width;
6365 mode.Height = swapchain->orig_height;
6366 mode.RefreshRate = 0;
6367 mode.Format = swapchain->presentParms.BackBufferFormat;
6369 mode.Width = pPresentationParameters->BackBufferWidth;
6370 mode.Height = pPresentationParameters->BackBufferHeight;
6371 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6372 mode.Format = swapchain->presentParms.BackBufferFormat;
6375 /* Should Width == 800 && Height == 0 set 800x600? */
6376 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6377 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6378 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6382 if(!pPresentationParameters->Windowed) {
6383 DisplayModeChanged = TRUE;
6385 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6386 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6388 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6391 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6395 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6397 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6400 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6404 if (This->auto_depth_stencil)
6406 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6409 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6415 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6416 || DisplayModeChanged)
6418 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6420 if (!pPresentationParameters->Windowed)
6422 if(swapchain->presentParms.Windowed) {
6423 /* switch from windowed to fs */
6424 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6425 pPresentationParameters->BackBufferHeight);
6427 /* Fullscreen -> fullscreen mode change */
6428 MoveWindow(swapchain->device_window, 0, 0,
6429 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6433 else if (!swapchain->presentParms.Windowed)
6435 /* Fullscreen -> windowed switch */
6436 swapchain_restore_fullscreen_window(swapchain);
6438 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6439 } else if(!pPresentationParameters->Windowed) {
6440 DWORD style = This->style, exStyle = This->exStyle;
6441 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6442 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6443 * Reset to clear up their mess. Guild Wars also loses the device during that.
6447 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6448 pPresentationParameters->BackBufferHeight);
6449 This->style = style;
6450 This->exStyle = exStyle;
6453 /* Note: No parent needed for initial internal stateblock */
6454 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6455 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6456 else TRACE("Created stateblock %p\n", This->stateBlock);
6457 This->updateStateBlock = This->stateBlock;
6458 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6460 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6462 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6465 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6468 GetClientRect(swapchain->win_handle, &client_rect);
6470 if(!swapchain->presentParms.BackBufferCount)
6472 TRACE("Single buffered rendering\n");
6473 swapchain->render_to_fbo = FALSE;
6475 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6476 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6478 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6479 swapchain->presentParms.BackBufferWidth,
6480 swapchain->presentParms.BackBufferHeight,
6481 client_rect.right, client_rect.bottom);
6482 swapchain->render_to_fbo = TRUE;
6486 TRACE("Rendering directly to GL_BACK\n");
6487 swapchain->render_to_fbo = FALSE;
6491 hr = create_primary_opengl_context(iface, swapchain);
6492 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6494 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6500 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6502 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6504 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6510 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6512 TRACE("(%p) : pParameters %p\n", This, pParameters);
6514 *pParameters = This->createParms;
6518 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6519 IWineD3DSwapChain *swapchain;
6521 TRACE("Relaying to swapchain\n");
6523 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6524 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6525 IWineD3DSwapChain_Release(swapchain);
6529 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6530 IWineD3DSwapChain *swapchain;
6532 TRACE("Relaying to swapchain\n");
6534 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6535 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6536 IWineD3DSwapChain_Release(swapchain);
6541 /** ********************************************************
6542 * Notification functions
6543 ** ********************************************************/
6544 /** This function must be called in the release of a resource when ref == 0,
6545 * the contents of resource must still be correct,
6546 * any handles to other resource held by the caller must be closed
6547 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6548 *****************************************************/
6549 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6551 TRACE("(%p) : Adding resource %p\n", This, resource);
6553 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6556 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6558 TRACE("(%p) : Removing resource %p\n", This, resource);
6560 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6563 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6565 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6568 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6570 context_resource_released(device, resource, type);
6574 case WINED3DRTYPE_SURFACE:
6575 if (!device->d3d_initialized) break;
6577 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6579 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6581 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6582 device->render_targets[i] = NULL;
6586 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6588 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6589 device->depth_stencil = NULL;
6593 case WINED3DRTYPE_TEXTURE:
6594 case WINED3DRTYPE_CUBETEXTURE:
6595 case WINED3DRTYPE_VOLUMETEXTURE:
6596 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6598 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6600 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6601 resource, device->stateBlock, i);
6602 device->stateBlock->textures[i] = NULL;
6605 if (device->updateStateBlock != device->stateBlock
6606 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6608 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6609 resource, device->updateStateBlock, i);
6610 device->updateStateBlock->textures[i] = NULL;
6615 case WINED3DRTYPE_BUFFER:
6616 for (i = 0; i < MAX_STREAMS; ++i)
6618 if (device->stateBlock && device->stateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6620 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6621 resource, device->stateBlock, i);
6622 device->stateBlock->streams[i].buffer = NULL;
6625 if (device->updateStateBlock != device->stateBlock
6626 && device->updateStateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6628 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6629 resource, device->updateStateBlock, i);
6630 device->updateStateBlock->streams[i].buffer = NULL;
6635 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6637 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6638 resource, device->stateBlock);
6639 device->stateBlock->pIndexData = NULL;
6642 if (device->updateStateBlock != device->stateBlock
6643 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6645 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6646 resource, device->updateStateBlock);
6647 device->updateStateBlock->pIndexData = NULL;
6655 /* Remove the resource from the resourceStore */
6656 device_resource_remove(device, resource);
6658 TRACE("Resource released.\n");
6661 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 IWineD3DResourceImpl *resource, *cursor;
6665 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6667 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6668 TRACE("enumerating resource %p\n", resource);
6669 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6670 ret = pCallback((IWineD3DResource *) resource, pData);
6671 if(ret == S_FALSE) {
6672 TRACE("Canceling enumeration\n");
6679 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6682 IWineD3DResourceImpl *resource;
6684 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6686 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6687 if (type == WINED3DRTYPE_SURFACE)
6689 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6691 TRACE("Found surface %p for dc %p.\n", resource, dc);
6692 *surface = (IWineD3DSurface *)resource;
6698 return WINED3DERR_INVALIDCALL;
6701 /**********************************************************
6702 * IWineD3DDevice VTbl follows
6703 **********************************************************/
6705 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6707 /*** IUnknown methods ***/
6708 IWineD3DDeviceImpl_QueryInterface,
6709 IWineD3DDeviceImpl_AddRef,
6710 IWineD3DDeviceImpl_Release,
6711 /*** IWineD3DDevice methods ***/
6712 /*** Creation methods**/
6713 IWineD3DDeviceImpl_CreateBuffer,
6714 IWineD3DDeviceImpl_CreateVertexBuffer,
6715 IWineD3DDeviceImpl_CreateIndexBuffer,
6716 IWineD3DDeviceImpl_CreateStateBlock,
6717 IWineD3DDeviceImpl_CreateSurface,
6718 IWineD3DDeviceImpl_CreateRendertargetView,
6719 IWineD3DDeviceImpl_CreateTexture,
6720 IWineD3DDeviceImpl_CreateVolumeTexture,
6721 IWineD3DDeviceImpl_CreateVolume,
6722 IWineD3DDeviceImpl_CreateCubeTexture,
6723 IWineD3DDeviceImpl_CreateQuery,
6724 IWineD3DDeviceImpl_CreateSwapChain,
6725 IWineD3DDeviceImpl_CreateVertexDeclaration,
6726 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6727 IWineD3DDeviceImpl_CreateVertexShader,
6728 IWineD3DDeviceImpl_CreateGeometryShader,
6729 IWineD3DDeviceImpl_CreatePixelShader,
6730 IWineD3DDeviceImpl_CreatePalette,
6731 /*** Odd functions **/
6732 IWineD3DDeviceImpl_Init3D,
6733 IWineD3DDeviceImpl_InitGDI,
6734 IWineD3DDeviceImpl_Uninit3D,
6735 IWineD3DDeviceImpl_UninitGDI,
6736 IWineD3DDeviceImpl_SetMultithreaded,
6737 IWineD3DDeviceImpl_EvictManagedResources,
6738 IWineD3DDeviceImpl_GetAvailableTextureMem,
6739 IWineD3DDeviceImpl_GetBackBuffer,
6740 IWineD3DDeviceImpl_GetCreationParameters,
6741 IWineD3DDeviceImpl_GetDeviceCaps,
6742 IWineD3DDeviceImpl_GetDirect3D,
6743 IWineD3DDeviceImpl_GetDisplayMode,
6744 IWineD3DDeviceImpl_SetDisplayMode,
6745 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6746 IWineD3DDeviceImpl_GetRasterStatus,
6747 IWineD3DDeviceImpl_GetSwapChain,
6748 IWineD3DDeviceImpl_Reset,
6749 IWineD3DDeviceImpl_SetDialogBoxMode,
6750 IWineD3DDeviceImpl_SetCursorProperties,
6751 IWineD3DDeviceImpl_SetCursorPosition,
6752 IWineD3DDeviceImpl_ShowCursor,
6753 /*** Getters and setters **/
6754 IWineD3DDeviceImpl_SetClipPlane,
6755 IWineD3DDeviceImpl_GetClipPlane,
6756 IWineD3DDeviceImpl_SetClipStatus,
6757 IWineD3DDeviceImpl_GetClipStatus,
6758 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6759 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6760 IWineD3DDeviceImpl_SetDepthStencilSurface,
6761 IWineD3DDeviceImpl_GetDepthStencilSurface,
6762 IWineD3DDeviceImpl_SetGammaRamp,
6763 IWineD3DDeviceImpl_GetGammaRamp,
6764 IWineD3DDeviceImpl_SetIndexBuffer,
6765 IWineD3DDeviceImpl_GetIndexBuffer,
6766 IWineD3DDeviceImpl_SetBaseVertexIndex,
6767 IWineD3DDeviceImpl_GetBaseVertexIndex,
6768 IWineD3DDeviceImpl_SetLight,
6769 IWineD3DDeviceImpl_GetLight,
6770 IWineD3DDeviceImpl_SetLightEnable,
6771 IWineD3DDeviceImpl_GetLightEnable,
6772 IWineD3DDeviceImpl_SetMaterial,
6773 IWineD3DDeviceImpl_GetMaterial,
6774 IWineD3DDeviceImpl_SetNPatchMode,
6775 IWineD3DDeviceImpl_GetNPatchMode,
6776 IWineD3DDeviceImpl_SetPaletteEntries,
6777 IWineD3DDeviceImpl_GetPaletteEntries,
6778 IWineD3DDeviceImpl_SetPixelShader,
6779 IWineD3DDeviceImpl_GetPixelShader,
6780 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6781 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6782 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6783 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6784 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6785 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6786 IWineD3DDeviceImpl_SetRenderState,
6787 IWineD3DDeviceImpl_GetRenderState,
6788 IWineD3DDeviceImpl_SetRenderTarget,
6789 IWineD3DDeviceImpl_GetRenderTarget,
6790 IWineD3DDeviceImpl_SetFrontBackBuffers,
6791 IWineD3DDeviceImpl_SetSamplerState,
6792 IWineD3DDeviceImpl_GetSamplerState,
6793 IWineD3DDeviceImpl_SetScissorRect,
6794 IWineD3DDeviceImpl_GetScissorRect,
6795 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6796 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6797 IWineD3DDeviceImpl_SetStreamSource,
6798 IWineD3DDeviceImpl_GetStreamSource,
6799 IWineD3DDeviceImpl_SetStreamSourceFreq,
6800 IWineD3DDeviceImpl_GetStreamSourceFreq,
6801 IWineD3DDeviceImpl_SetTexture,
6802 IWineD3DDeviceImpl_GetTexture,
6803 IWineD3DDeviceImpl_SetTextureStageState,
6804 IWineD3DDeviceImpl_GetTextureStageState,
6805 IWineD3DDeviceImpl_SetTransform,
6806 IWineD3DDeviceImpl_GetTransform,
6807 IWineD3DDeviceImpl_SetVertexDeclaration,
6808 IWineD3DDeviceImpl_GetVertexDeclaration,
6809 IWineD3DDeviceImpl_SetVertexShader,
6810 IWineD3DDeviceImpl_GetVertexShader,
6811 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6812 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6813 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6814 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6815 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6816 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6817 IWineD3DDeviceImpl_SetViewport,
6818 IWineD3DDeviceImpl_GetViewport,
6819 IWineD3DDeviceImpl_MultiplyTransform,
6820 IWineD3DDeviceImpl_ValidateDevice,
6821 IWineD3DDeviceImpl_ProcessVertices,
6822 /*** State block ***/
6823 IWineD3DDeviceImpl_BeginStateBlock,
6824 IWineD3DDeviceImpl_EndStateBlock,
6825 /*** Scene management ***/
6826 IWineD3DDeviceImpl_BeginScene,
6827 IWineD3DDeviceImpl_EndScene,
6828 IWineD3DDeviceImpl_Present,
6829 IWineD3DDeviceImpl_Clear,
6830 IWineD3DDeviceImpl_ClearRendertargetView,
6832 IWineD3DDeviceImpl_SetPrimitiveType,
6833 IWineD3DDeviceImpl_GetPrimitiveType,
6834 IWineD3DDeviceImpl_DrawPrimitive,
6835 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6836 IWineD3DDeviceImpl_DrawPrimitiveUP,
6837 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6838 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6839 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6840 IWineD3DDeviceImpl_DrawRectPatch,
6841 IWineD3DDeviceImpl_DrawTriPatch,
6842 IWineD3DDeviceImpl_DeletePatch,
6843 IWineD3DDeviceImpl_ColorFill,
6844 IWineD3DDeviceImpl_UpdateTexture,
6845 IWineD3DDeviceImpl_UpdateSurface,
6846 IWineD3DDeviceImpl_GetFrontBufferData,
6847 /*** object tracking ***/
6848 IWineD3DDeviceImpl_EnumResources,
6849 IWineD3DDeviceImpl_GetSurfaceFromDC,
6850 IWineD3DDeviceImpl_AcquireFocusWindow,
6851 IWineD3DDeviceImpl_ReleaseFocusWindow,
6854 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6855 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6856 IWineD3DDeviceParent *device_parent)
6858 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6859 const struct fragment_pipeline *fragment_pipeline;
6860 struct shader_caps shader_caps;
6861 struct fragment_caps ffp_caps;
6862 WINED3DDISPLAYMODE mode;
6866 device->lpVtbl = &IWineD3DDevice_Vtbl;
6868 device->wined3d = (IWineD3D *)wined3d;
6869 IWineD3D_AddRef(device->wined3d);
6870 device->adapter = wined3d->adapter_count ? adapter : NULL;
6871 device->device_parent = device_parent;
6872 list_init(&device->resources);
6873 list_init(&device->shaders);
6875 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6876 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6878 /* Get the initial screen setup for ddraw. */
6879 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6882 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6883 IWineD3D_Release(device->wined3d);
6886 device->ddraw_width = mode.Width;
6887 device->ddraw_height = mode.Height;
6888 device->ddraw_format = mode.Format;
6890 /* Save the creation parameters. */
6891 device->createParms.AdapterOrdinal = adapter_idx;
6892 device->createParms.DeviceType = device_type;
6893 device->createParms.hFocusWindow = focus_window;
6894 device->createParms.BehaviorFlags = flags;
6896 device->devType = device_type;
6897 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6899 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6900 device->shader_backend = adapter->shader_backend;
6902 if (device->shader_backend)
6904 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6905 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6906 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6907 device->vs_clipping = shader_caps.VSClipping;
6909 fragment_pipeline = adapter->fragment_pipe;
6910 device->frag_pipe = fragment_pipeline;
6911 if (fragment_pipeline)
6913 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6914 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6916 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6917 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6920 ERR("Failed to compile state table, hr %#x.\n", hr);
6921 IWineD3D_Release(device->wined3d);
6925 device->blitter = adapter->blitter;
6931 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6932 DWORD rep = This->StateTable[state].representative;
6933 struct wined3d_context *context;
6938 for(i = 0; i < This->numContexts; i++) {
6939 context = This->contexts[i];
6940 if(isStateDirty(context, rep)) continue;
6942 context->dirtyArray[context->numDirtyEntries++] = rep;
6943 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6944 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6945 context->isStateDirty[idx] |= (1 << shift);
6949 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6951 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6952 *width = context->current_rt->pow2Width;
6953 *height = context->current_rt->pow2Height;
6956 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6958 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6959 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6960 * current context's drawable, which is the size of the back buffer of the swapchain
6961 * the active context belongs to. */
6962 *width = swapchain->presentParms.BackBufferWidth;
6963 *height = swapchain->presentParms.BackBufferHeight;
6966 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6967 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6969 if (device->filter_messages)
6971 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6972 window, message, wparam, lparam);
6973 return DefWindowProcW(window, message, wparam, lparam);
6976 if (message == WM_DESTROY)
6978 TRACE("unregister window %p.\n", window);
6979 wined3d_unregister_window(window);
6981 if (device->focus_window == window) device->focus_window = NULL;
6982 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6985 return CallWindowProcW(proc, window, message, wparam, lparam);