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 GLenum dimensions = t->baseTexture.target;
4365 IWineD3DBaseTexture_AddRef(texture);
4367 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4370 if (!prev && stage < gl_info->limits.texture_stages)
4372 /* The source arguments for color and alpha ops have different
4373 * meanings when a NULL texture is bound, so the COLOROP and
4374 * ALPHAOP have to be dirtified. */
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4379 if (bind_count == 1) t->baseTexture.sampler = stage;
4384 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4385 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4387 IWineD3DBaseTexture_Release(prev);
4389 if (!texture && stage < gl_info->limits.texture_stages)
4391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4395 if (bind_count && t->baseTexture.sampler == stage)
4399 /* Search for other stages the texture is bound to. Shouldn't
4400 * happen if applications bind textures to a single stage only. */
4401 TRACE("Searching for other stages the texture is bound to.\n");
4402 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4404 if (This->updateStateBlock->textures[i] == prev)
4406 TRACE("Texture is also bound to stage %u.\n", i);
4407 t->baseTexture.sampler = i;
4414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4419 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4422 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4424 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4425 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4428 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4429 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4430 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4433 *ppTexture=This->stateBlock->textures[Stage];
4435 IWineD3DBaseTexture_AddRef(*ppTexture);
4437 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4445 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4446 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4448 IWineD3DSwapChain *swapchain;
4451 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4452 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4454 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4457 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4461 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4462 IWineD3DSwapChain_Release(swapchain);
4465 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4472 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4474 WARN("(%p) : stub, calling idirect3d for now\n", This);
4475 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4478 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 IWineD3DSwapChain *swapChain;
4483 if(iSwapChain > 0) {
4484 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4485 if (hr == WINED3D_OK) {
4486 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4487 IWineD3DSwapChain_Release(swapChain);
4489 FIXME("(%p) Error getting display mode\n", This);
4492 /* Don't read the real display mode,
4493 but return the stored mode instead. X11 can't change the color
4494 depth, and some apps are pretty angry if they SetDisplayMode from
4495 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4497 Also don't relay to the swapchain because with ddraw it's possible
4498 that there isn't a swapchain at all */
4499 pMode->Width = This->ddraw_width;
4500 pMode->Height = This->ddraw_height;
4501 pMode->Format = This->ddraw_format;
4502 pMode->RefreshRate = 0;
4510 * Stateblock related functions
4513 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 IWineD3DStateBlock *stateblock;
4518 TRACE("(%p)\n", This);
4520 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4522 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4523 if (FAILED(hr)) return hr;
4525 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4526 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4527 This->isRecordingState = TRUE;
4529 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4534 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4536 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4538 if (!This->isRecordingState) {
4539 WARN("(%p) not recording! returning error\n", This);
4540 *ppStateBlock = NULL;
4541 return WINED3DERR_INVALIDCALL;
4544 stateblock_init_contained_states(object);
4546 *ppStateBlock = (IWineD3DStateBlock*) object;
4547 This->isRecordingState = FALSE;
4548 This->updateStateBlock = This->stateBlock;
4549 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4550 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4551 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4556 * Scene related functions
4558 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4559 /* At the moment we have no need for any functionality at the beginning
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p)\n", This);
4565 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4566 return WINED3DERR_INVALIDCALL;
4568 This->inScene = TRUE;
4572 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 struct wined3d_context *context;
4577 TRACE("(%p)\n", This);
4579 if(!This->inScene) {
4580 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4581 return WINED3DERR_INVALIDCALL;
4584 context = context_acquire(This, NULL);
4585 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4587 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4589 context_release(context);
4591 This->inScene = FALSE;
4595 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4596 const RECT *pSourceRect, const RECT *pDestRect,
4597 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4599 IWineD3DSwapChain *swapChain = NULL;
4601 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4603 TRACE("iface %p.\n", iface);
4605 for(i = 0 ; i < swapchains ; i ++) {
4607 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4608 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4609 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4610 IWineD3DSwapChain_Release(swapChain);
4616 /* Do not call while under the GL lock. */
4617 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4618 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4620 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4621 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4624 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4625 iface, rect_count, rects, flags, color, depth, stencil);
4627 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4629 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4630 /* TODO: What about depth stencil buffers without stencil bits? */
4631 return WINED3DERR_INVALIDCALL;
4634 device_get_draw_rect(device, &draw_rect);
4636 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4637 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4644 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4645 WINED3DPRIMITIVETYPE primitive_type)
4647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4651 This->updateStateBlock->changed.primitive_type = TRUE;
4652 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4655 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4656 WINED3DPRIMITIVETYPE *primitive_type)
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4662 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4664 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4667 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4673 if(!This->stateBlock->vertexDecl) {
4674 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4675 return WINED3DERR_INVALIDCALL;
4678 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4679 if(This->stateBlock->streamIsUP) {
4680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4681 This->stateBlock->streamIsUP = FALSE;
4684 if (This->stateBlock->loadBaseVertexIndex)
4686 This->stateBlock->loadBaseVertexIndex = 0;
4687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4689 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4690 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4694 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4698 IWineD3DBuffer *pIB;
4701 pIB = This->stateBlock->pIndexData;
4703 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4704 * without an index buffer set. (The first time at least...)
4705 * D3D8 simply dies, but I doubt it can do much harm to return
4706 * D3DERR_INVALIDCALL there as well. */
4707 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4708 return WINED3DERR_INVALIDCALL;
4711 if(!This->stateBlock->vertexDecl) {
4712 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4713 return WINED3DERR_INVALIDCALL;
4716 if(This->stateBlock->streamIsUP) {
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4718 This->stateBlock->streamIsUP = FALSE;
4720 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4722 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4724 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4730 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4731 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4735 drawPrimitive(iface, index_count, startIndex, idxStride,
4736 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4741 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4742 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 struct wined3d_stream_state *stream;
4748 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4749 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4751 if(!This->stateBlock->vertexDecl) {
4752 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4753 return WINED3DERR_INVALIDCALL;
4756 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4757 stream = &This->stateBlock->streams[0];
4758 vb = (IWineD3DBuffer *)stream->buffer;
4759 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4760 if (vb) IWineD3DBuffer_Release(vb);
4762 stream->stride = VertexStreamZeroStride;
4763 This->stateBlock->streamIsUP = TRUE;
4764 This->stateBlock->loadBaseVertexIndex = 0;
4766 /* TODO: Only mark dirty if drawing from a different UP address */
4767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4769 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4771 /* MSDN specifies stream zero settings must be set to NULL */
4772 stream->buffer = NULL;
4775 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4776 * the new stream sources or use UP drawing again
4781 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4782 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4783 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4787 struct wined3d_stream_state *stream;
4791 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4792 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4794 if(!This->stateBlock->vertexDecl) {
4795 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4796 return WINED3DERR_INVALIDCALL;
4799 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4805 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4806 stream = &This->stateBlock->streams[0];
4807 vb = (IWineD3DBuffer *)stream->buffer;
4808 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4809 if (vb) IWineD3DBuffer_Release(vb);
4811 stream->stride = VertexStreamZeroStride;
4812 This->stateBlock->streamIsUP = TRUE;
4814 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4815 This->stateBlock->baseVertexIndex = 0;
4816 This->stateBlock->loadBaseVertexIndex = 0;
4817 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4821 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4823 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4824 stream->buffer = NULL;
4826 ib = This->stateBlock->pIndexData;
4828 IWineD3DBuffer_Release(ib);
4829 This->stateBlock->pIndexData = NULL;
4831 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4832 * SetStreamSource to specify a vertex buffer
4838 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4839 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4843 /* Mark the state dirty until we have nicer tracking
4844 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4849 This->stateBlock->baseVertexIndex = 0;
4850 This->up_strided = DrawPrimStrideData;
4851 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4852 This->up_strided = NULL;
4856 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4857 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4858 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4861 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4863 /* Mark the state dirty until we have nicer tracking
4864 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4869 This->stateBlock->streamIsUP = TRUE;
4870 This->stateBlock->baseVertexIndex = 0;
4871 This->up_strided = DrawPrimStrideData;
4872 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4873 This->up_strided = NULL;
4877 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4878 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4879 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4881 WINED3DLOCKED_BOX src;
4882 WINED3DLOCKED_BOX dst;
4885 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4886 iface, pSourceVolume, pDestinationVolume);
4888 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4889 * dirtification to improve loading performance.
4891 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4892 if(FAILED(hr)) return hr;
4893 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4895 IWineD3DVolume_UnlockBox(pSourceVolume);
4899 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4901 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4903 IWineD3DVolume_UnlockBox(pSourceVolume);
4905 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4910 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4911 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4913 unsigned int level_count, i;
4914 WINED3DRESOURCETYPE type;
4917 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4919 /* Verify that the source and destination textures are non-NULL. */
4920 if (!src_texture || !dst_texture)
4922 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4923 return WINED3DERR_INVALIDCALL;
4926 if (src_texture == dst_texture)
4928 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4929 return WINED3DERR_INVALIDCALL;
4932 /* Verify that the source and destination textures are the same type. */
4933 type = IWineD3DBaseTexture_GetType(src_texture);
4934 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4936 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4937 return WINED3DERR_INVALIDCALL;
4940 /* Check that both textures have the identical numbers of levels. */
4941 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4942 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4944 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4945 return WINED3DERR_INVALIDCALL;
4948 /* Make sure that the destination texture is loaded. */
4949 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4951 /* Update every surface level of the texture. */
4954 case WINED3DRTYPE_TEXTURE:
4956 IWineD3DSurface *src_surface;
4957 IWineD3DSurface *dst_surface;
4959 for (i = 0; i < level_count; ++i)
4961 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4962 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4963 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4964 IWineD3DSurface_Release(dst_surface);
4965 IWineD3DSurface_Release(src_surface);
4968 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4975 case WINED3DRTYPE_CUBETEXTURE:
4977 IWineD3DSurface *src_surface;
4978 IWineD3DSurface *dst_surface;
4979 WINED3DCUBEMAP_FACES face;
4981 for (i = 0; i < level_count; ++i)
4983 /* Update each cube face. */
4984 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4986 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4987 face, i, &src_surface);
4988 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4989 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4990 face, i, &dst_surface);
4991 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4992 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4993 IWineD3DSurface_Release(dst_surface);
4994 IWineD3DSurface_Release(src_surface);
4997 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5005 case WINED3DRTYPE_VOLUMETEXTURE:
5007 IWineD3DVolume *src_volume;
5008 IWineD3DVolume *dst_volume;
5010 for (i = 0; i < level_count; ++i)
5012 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5013 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5014 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5015 IWineD3DVolume_Release(dst_volume);
5016 IWineD3DVolume_Release(src_volume);
5019 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5027 FIXME("Unsupported texture type %#x.\n", type);
5028 return WINED3DERR_INVALIDCALL;
5034 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5035 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5037 IWineD3DSwapChain *swapchain;
5040 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5042 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5043 if (FAILED(hr)) return hr;
5045 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5046 IWineD3DSwapChain_Release(swapchain);
5051 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 IWineD3DBaseTextureImpl *texture;
5056 TRACE("(%p) : %p\n", This, pNumPasses);
5058 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5060 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5062 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5063 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5065 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5067 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5068 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5071 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5072 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5074 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5076 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5079 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5081 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5084 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5085 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5087 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5092 /* return a sensible default */
5095 TRACE("returning D3D_OK\n");
5099 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5103 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5105 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5106 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5107 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5109 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5114 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5118 PALETTEENTRY **palettes;
5120 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5122 if (PaletteNumber >= MAX_PALETTES) {
5123 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5124 return WINED3DERR_INVALIDCALL;
5127 if (PaletteNumber >= This->NumberOfPalettes) {
5128 NewSize = This->NumberOfPalettes;
5131 } while(PaletteNumber >= NewSize);
5132 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5134 ERR("Out of memory!\n");
5135 return E_OUTOFMEMORY;
5137 This->palettes = palettes;
5138 This->NumberOfPalettes = NewSize;
5141 if (!This->palettes[PaletteNumber]) {
5142 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5143 if (!This->palettes[PaletteNumber]) {
5144 ERR("Out of memory!\n");
5145 return E_OUTOFMEMORY;
5149 for (j = 0; j < 256; ++j) {
5150 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5151 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5152 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5153 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5155 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5156 TRACE("(%p) : returning\n", This);
5160 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5164 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5165 /* What happens in such situation isn't documented; Native seems to silently abort
5166 on such conditions. Return Invalid Call. */
5167 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5168 return WINED3DERR_INVALIDCALL;
5170 for (j = 0; j < 256; ++j) {
5171 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5172 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5173 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5174 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5176 TRACE("(%p) : returning\n", This);
5180 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5182 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5183 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5184 (tested with reference rasterizer). Return Invalid Call. */
5185 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5186 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5187 return WINED3DERR_INVALIDCALL;
5189 /*TODO: stateblocks */
5190 if (This->currentPalette != PaletteNumber) {
5191 This->currentPalette = PaletteNumber;
5192 dirtify_p8_texture_samplers(This);
5194 TRACE("(%p) : returning\n", This);
5198 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 WARN("(%p) : returning Invalid Call\n", This);
5204 return WINED3DERR_INVALIDCALL;
5206 /*TODO: stateblocks */
5207 *PaletteNumber = This->currentPalette;
5208 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5212 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5217 FIXME("(%p) : stub\n", This);
5221 This->softwareVertexProcessing = bSoftware;
5226 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5231 FIXME("(%p) : stub\n", This);
5234 return This->softwareVertexProcessing;
5237 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5238 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5240 IWineD3DSwapChain *swapchain;
5243 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5244 iface, swapchain_idx, raster_status);
5246 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5249 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5253 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5254 IWineD3DSwapChain_Release(swapchain);
5257 WARN("Failed to get raster status, hr %#x.\n", hr);
5264 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5267 if(nSegments != 0.0f) {
5270 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5277 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5282 FIXME("iface %p stub!\n", iface);
5288 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5289 IWineD3DSurface *src_surface, const RECT *src_rect,
5290 IWineD3DSurface *dst_surface, const POINT *dst_point)
5292 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5293 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 const struct wined3d_format *src_format;
5296 const struct wined3d_format *dst_format;
5297 const struct wined3d_gl_info *gl_info;
5298 struct wined3d_context *context;
5299 const unsigned char *data;
5300 UINT update_w, update_h;
5301 CONVERT_TYPES convert;
5305 struct wined3d_format format;
5307 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5308 iface, src_surface, wine_dbgstr_rect(src_rect),
5309 dst_surface, wine_dbgstr_point(dst_point));
5311 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5313 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5314 src_surface, dst_surface);
5315 return WINED3DERR_INVALIDCALL;
5318 src_format = src_impl->resource.format;
5319 dst_format = dst_impl->resource.format;
5321 if (src_format->id != dst_format->id)
5323 WARN("Source and destination surfaces should have the same format.\n");
5324 return WINED3DERR_INVALIDCALL;
5327 dst_x = dst_point ? dst_point->x : 0;
5328 dst_y = dst_point ? dst_point->y : 0;
5330 /* This call loads the OpenGL surface directly, instead of copying the
5331 * surface to the destination's sysmem copy. If surface conversion is
5332 * needed, use BltFast instead to copy in sysmem and use regular surface
5334 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5335 if (convert != NO_CONVERSION || format.convert)
5336 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5338 context = context_acquire(This, NULL);
5339 gl_info = context->gl_info;
5342 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5343 checkGLcall("glActiveTextureARB");
5346 /* Make sure the surface is loaded and up to date */
5347 surface_internal_preload(dst_impl, SRGB_RGB);
5348 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5350 src_w = src_impl->currentDesc.Width;
5351 src_h = src_impl->currentDesc.Height;
5352 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5353 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5355 data = IWineD3DSurface_GetData(src_surface);
5356 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5360 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5362 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5363 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5364 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5368 data += (src_rect->top / src_format->block_height) * src_pitch;
5369 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5372 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5373 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5374 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5376 if (row_length == src_pitch)
5378 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5379 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5385 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5386 * can't use the unpack row length like below. */
5387 for (row = 0, y = dst_y; row < row_count; ++row)
5389 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5390 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5391 y += src_format->block_height;
5395 checkGLcall("glCompressedTexSubImage2DARB");
5401 data += src_rect->top * src_w * src_format->byte_count;
5402 data += src_rect->left * src_format->byte_count;
5405 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5406 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5407 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5409 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5410 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5411 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5412 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5413 checkGLcall("glTexSubImage2D");
5417 context_release(context);
5419 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5420 sampler = This->rev_tex_unit_map[0];
5421 if (sampler != WINED3D_UNMAPPED_STAGE)
5423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5429 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5431 struct WineD3DRectPatch *patch;
5432 GLenum old_primitive_type;
5436 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5438 if(!(Handle || pRectPatchInfo)) {
5439 /* TODO: Write a test for the return value, thus the FIXME */
5440 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5441 return WINED3DERR_INVALIDCALL;
5445 i = PATCHMAP_HASHFUNC(Handle);
5447 LIST_FOR_EACH(e, &This->patches[i]) {
5448 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5449 if(patch->Handle == Handle) {
5456 TRACE("Patch does not exist. Creating a new one\n");
5457 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5458 patch->Handle = Handle;
5459 list_add_head(&This->patches[i], &patch->entry);
5461 TRACE("Found existing patch %p\n", patch);
5464 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5465 * attributes we have to tesselate, read back, and draw. This needs a patch
5466 * management structure instance. Create one.
5468 * A possible improvement is to check if a vertex shader is used, and if not directly
5471 FIXME("Drawing an uncached patch. This is slow\n");
5472 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5475 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5476 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5477 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5480 TRACE("Tesselation density or patch info changed, retesselating\n");
5482 if(pRectPatchInfo) {
5483 patch->RectPatchInfo = *pRectPatchInfo;
5485 patch->numSegs[0] = pNumSegs[0];
5486 patch->numSegs[1] = pNumSegs[1];
5487 patch->numSegs[2] = pNumSegs[2];
5488 patch->numSegs[3] = pNumSegs[3];
5490 hr = tesselate_rectpatch(This, patch);
5492 WARN("Patch tesselation failed\n");
5494 /* Do not release the handle to store the params of the patch */
5496 HeapFree(GetProcessHeap(), 0, patch);
5502 This->currentPatch = patch;
5503 old_primitive_type = This->stateBlock->gl_primitive_type;
5504 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5505 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5506 This->stateBlock->gl_primitive_type = old_primitive_type;
5507 This->currentPatch = NULL;
5509 /* Destroy uncached patches */
5511 HeapFree(GetProcessHeap(), 0, patch->mem);
5512 HeapFree(GetProcessHeap(), 0, patch);
5517 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5518 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5520 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5521 iface, handle, segment_count, patch_info);
5526 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5529 struct WineD3DRectPatch *patch;
5531 TRACE("(%p) Handle(%d)\n", This, Handle);
5533 i = PATCHMAP_HASHFUNC(Handle);
5534 LIST_FOR_EACH(e, &This->patches[i]) {
5535 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5536 if(patch->Handle == Handle) {
5537 TRACE("Deleting patch %p\n", patch);
5538 list_remove(&patch->entry);
5539 HeapFree(GetProcessHeap(), 0, patch->mem);
5540 HeapFree(GetProcessHeap(), 0, patch);
5545 /* TODO: Write a test for the return value */
5546 FIXME("Attempt to destroy nonexistent patch\n");
5547 return WINED3DERR_INVALIDCALL;
5550 /* Do not call while under the GL lock. */
5551 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5552 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5554 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5556 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5557 iface, surface, wine_dbgstr_rect(rect),
5558 color->r, color->g, color->b, color->a);
5560 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5562 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5563 return WINED3DERR_INVALIDCALL;
5566 return surface_color_fill(s, rect, color);
5569 /* Do not call while under the GL lock. */
5570 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5571 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5573 IWineD3DResource *resource;
5576 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5579 ERR("Failed to get resource, hr %#x\n", hr);
5583 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5585 FIXME("Only supported on surface resources\n");
5586 IWineD3DResource_Release(resource);
5590 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5591 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5593 IWineD3DResource_Release(resource);
5596 /* rendertarget and depth stencil functions */
5597 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5598 DWORD render_target_idx, IWineD3DSurface **render_target)
5600 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5602 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5603 iface, render_target_idx, render_target);
5605 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5607 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5608 return WINED3DERR_INVALIDCALL;
5611 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5612 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5614 TRACE("Returning render target %p.\n", *render_target);
5619 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5620 IWineD3DSurface *front, IWineD3DSurface *back)
5622 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5623 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5624 IWineD3DSwapChainImpl *swapchain;
5627 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5629 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5631 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5635 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5637 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5638 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5639 return WINED3DERR_INVALIDCALL;
5644 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5646 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5647 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5648 return WINED3DERR_INVALIDCALL;
5651 if (!swapchain->back_buffers)
5653 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5654 if (!swapchain->back_buffers)
5656 ERR("Failed to allocate back buffer array memory.\n");
5657 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5658 return E_OUTOFMEMORY;
5663 if (swapchain->front_buffer != front_impl)
5665 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5667 if (swapchain->front_buffer)
5668 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5669 swapchain->front_buffer = front_impl;
5672 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5675 if (swapchain->back_buffers[0] != back_impl)
5677 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5679 if (swapchain->back_buffers[0])
5680 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5681 swapchain->back_buffers[0] = back_impl;
5685 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5686 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5687 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5688 swapchain->presentParms.BackBufferCount = 1;
5690 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5694 swapchain->presentParms.BackBufferCount = 0;
5695 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5696 swapchain->back_buffers = NULL;
5700 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5706 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5708 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5710 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5711 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5712 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5713 IWineD3DSurface_AddRef(*depth_stencil);
5718 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5719 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5721 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5722 IWineD3DSurfaceImpl *prev;
5724 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5725 iface, render_target_idx, render_target, set_viewport);
5727 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5729 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5730 return WINED3DERR_INVALIDCALL;
5733 prev = device->render_targets[render_target_idx];
5734 if (render_target == (IWineD3DSurface *)prev)
5736 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5740 /* Render target 0 can't be set to NULL. */
5741 if (!render_target && !render_target_idx)
5743 WARN("Trying to set render target 0 to NULL.\n");
5744 return WINED3DERR_INVALIDCALL;
5747 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5749 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5750 return WINED3DERR_INVALIDCALL;
5753 if (render_target) IWineD3DSurface_AddRef(render_target);
5754 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5755 /* Release after the assignment, to prevent device_resource_released()
5756 * from seeing the surface as still in use. */
5757 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5759 /* Render target 0 is special. */
5760 if (!render_target_idx && set_viewport)
5762 /* Set the viewport and scissor rectangles, if requested. Tests show
5763 * that stateblock recording is ignored, the change goes directly
5764 * into the primary stateblock. */
5765 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5766 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5767 device->stateBlock->state.viewport.X = 0;
5768 device->stateBlock->state.viewport.Y = 0;
5769 device->stateBlock->state.viewport.MaxZ = 1.0f;
5770 device->stateBlock->state.viewport.MinZ = 0.0f;
5771 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5773 device->stateBlock->state.scissor_rect.top = 0;
5774 device->stateBlock->state.scissor_rect.left = 0;
5775 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5776 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5777 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5783 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5786 IWineD3DSurfaceImpl *tmp;
5788 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5790 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5792 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5796 if (This->depth_stencil)
5798 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5799 || This->depth_stencil->Flags & SFLAG_DISCARD)
5801 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5802 This->depth_stencil->currentDesc.Width,
5803 This->depth_stencil->currentDesc.Height);
5804 if (This->depth_stencil == This->onscreen_depth_stencil)
5806 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5807 This->onscreen_depth_stencil = NULL;
5812 tmp = This->depth_stencil;
5813 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5814 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5815 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5817 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5819 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5828 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5829 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5833 WINED3DLOCKED_RECT lockedRect;
5835 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5836 iface, XHotSpot, YHotSpot, cursor_image);
5838 /* some basic validation checks */
5839 if (This->cursorTexture)
5841 struct wined3d_context *context = context_acquire(This, NULL);
5843 glDeleteTextures(1, &This->cursorTexture);
5845 context_release(context);
5846 This->cursorTexture = 0;
5849 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5850 This->haveHardwareCursor = TRUE;
5852 This->haveHardwareCursor = FALSE;
5856 WINED3DLOCKED_RECT rect;
5858 /* MSDN: Cursor must be A8R8G8B8 */
5859 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5861 WARN("surface %p has an invalid format.\n", cursor_image);
5862 return WINED3DERR_INVALIDCALL;
5865 /* MSDN: Cursor must be smaller than the display mode */
5866 if (s->currentDesc.Width > This->ddraw_width
5867 || s->currentDesc.Height > This->ddraw_height)
5869 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5870 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5871 return WINED3DERR_INVALIDCALL;
5874 if (!This->haveHardwareCursor) {
5875 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5877 /* Do not store the surface's pointer because the application may
5878 * release it after setting the cursor image. Windows doesn't
5879 * addref the set surface, so we can't do this either without
5880 * creating circular refcount dependencies. Copy out the gl texture
5883 This->cursorWidth = s->currentDesc.Width;
5884 This->cursorHeight = s->currentDesc.Height;
5885 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5887 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5888 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5889 struct wined3d_context *context;
5890 char *mem, *bits = rect.pBits;
5891 GLint intfmt = format->glInternal;
5892 GLint gl_format = format->glFormat;
5893 GLint type = format->glType;
5894 INT height = This->cursorHeight;
5895 INT width = This->cursorWidth;
5896 INT bpp = format->byte_count;
5900 /* Reformat the texture memory (pitch and width can be
5902 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5903 for(i = 0; i < height; i++)
5904 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5905 IWineD3DSurface_UnlockRect(cursor_image);
5907 context = context_acquire(This, NULL);
5911 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5913 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5914 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5917 /* Make sure that a proper texture unit is selected */
5918 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5919 checkGLcall("glActiveTextureARB");
5920 sampler = This->rev_tex_unit_map[0];
5921 if (sampler != WINED3D_UNMAPPED_STAGE)
5923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5925 /* Create a new cursor texture */
5926 glGenTextures(1, &This->cursorTexture);
5927 checkGLcall("glGenTextures");
5928 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5929 checkGLcall("glBindTexture");
5930 /* Copy the bitmap memory into the cursor texture */
5931 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5932 HeapFree(GetProcessHeap(), 0, mem);
5933 checkGLcall("glTexImage2D");
5935 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5937 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5938 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5943 context_release(context);
5947 FIXME("A cursor texture was not returned.\n");
5948 This->cursorTexture = 0;
5953 /* Draw a hardware cursor */
5954 ICONINFO cursorInfo;
5956 /* Create and clear maskBits because it is not needed for
5957 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5959 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5960 (s->currentDesc.Width * s->currentDesc.Height / 8));
5961 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5962 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5963 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5965 cursorInfo.fIcon = FALSE;
5966 cursorInfo.xHotspot = XHotSpot;
5967 cursorInfo.yHotspot = YHotSpot;
5968 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5969 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5970 IWineD3DSurface_UnlockRect(cursor_image);
5971 /* Create our cursor and clean up. */
5972 cursor = CreateIconIndirect(&cursorInfo);
5974 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5975 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5976 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5977 This->hardwareCursor = cursor;
5978 HeapFree(GetProcessHeap(), 0, maskBits);
5982 This->xHotSpot = XHotSpot;
5983 This->yHotSpot = YHotSpot;
5987 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5989 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5991 This->xScreenSpace = XScreenSpace;
5992 This->yScreenSpace = YScreenSpace;
5998 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6000 BOOL oldVisible = This->bCursorVisible;
6003 TRACE("(%p) : visible(%d)\n", This, bShow);
6006 * When ShowCursor is first called it should make the cursor appear at the OS's last
6007 * known cursor position. Because of this, some applications just repetitively call
6008 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6011 This->xScreenSpace = pt.x;
6012 This->yScreenSpace = pt.y;
6014 if (This->haveHardwareCursor) {
6015 This->bCursorVisible = bShow;
6017 SetCursor(This->hardwareCursor);
6023 if (This->cursorTexture)
6024 This->bCursorVisible = bShow;
6030 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6031 TRACE("checking resource %p for eviction\n", resource);
6032 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6033 TRACE("Evicting %p\n", resource);
6034 IWineD3DResource_UnLoad(resource);
6036 IWineD3DResource_Release(resource);
6040 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6042 TRACE("iface %p.\n", iface);
6044 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6045 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6046 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6051 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6053 IWineD3DDeviceImpl *device = surface->resource.device;
6054 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6056 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6057 if(surface->Flags & SFLAG_DIBSECTION) {
6058 /* Release the DC */
6059 SelectObject(surface->hDC, surface->dib.holdbitmap);
6060 DeleteDC(surface->hDC);
6061 /* Release the DIB section */
6062 DeleteObject(surface->dib.DIBsection);
6063 surface->dib.bitmap_data = NULL;
6064 surface->resource.allocatedMemory = NULL;
6065 surface->Flags &= ~SFLAG_DIBSECTION;
6067 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6068 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6069 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6070 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6072 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6073 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6075 surface->pow2Width = surface->pow2Height = 1;
6076 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6077 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6080 if (surface->texture_name)
6082 struct wined3d_context *context = context_acquire(device, NULL);
6084 glDeleteTextures(1, &surface->texture_name);
6086 context_release(context);
6087 surface->texture_name = 0;
6088 surface->Flags &= ~SFLAG_CLIENT;
6090 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6091 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6092 surface->Flags |= SFLAG_NONPOW2;
6094 surface->Flags &= ~SFLAG_NONPOW2;
6096 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6097 surface->resource.allocatedMemory = NULL;
6098 surface->resource.heapMemory = NULL;
6099 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6101 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6103 if (!surface_init_sysmem(surface))
6105 return E_OUTOFMEMORY;
6110 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6111 TRACE("Unloading resource %p\n", resource);
6112 IWineD3DResource_UnLoad(resource);
6113 IWineD3DResource_Release(resource);
6117 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6120 WINED3DDISPLAYMODE m;
6123 /* All Windowed modes are supported, as is leaving the current mode */
6124 if(pp->Windowed) return TRUE;
6125 if(!pp->BackBufferWidth) return TRUE;
6126 if(!pp->BackBufferHeight) return TRUE;
6128 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6129 for(i = 0; i < count; i++) {
6130 memset(&m, 0, sizeof(m));
6131 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6133 ERR("EnumAdapterModes failed\n");
6135 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6136 /* Mode found, it is supported */
6140 /* Mode not found -> not supported */
6144 /* Do not call while under the GL lock. */
6145 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6148 const struct wined3d_gl_info *gl_info;
6149 struct wined3d_context *context;
6150 IWineD3DBaseShaderImpl *shader;
6152 context = context_acquire(This, NULL);
6153 gl_info = context->gl_info;
6155 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6156 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6157 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6161 if(This->depth_blt_texture) {
6162 glDeleteTextures(1, &This->depth_blt_texture);
6163 This->depth_blt_texture = 0;
6165 if (This->depth_blt_rb) {
6166 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6167 This->depth_blt_rb = 0;
6168 This->depth_blt_rb_w = 0;
6169 This->depth_blt_rb_h = 0;
6173 This->blitter->free_private(iface);
6174 This->frag_pipe->free_private(iface);
6175 This->shader_backend->shader_free_private(iface);
6176 destroy_dummy_textures(This, gl_info);
6178 context_release(context);
6180 while (This->numContexts)
6182 context_destroy(This, This->contexts[0]);
6184 HeapFree(GetProcessHeap(), 0, swapchain->context);
6185 swapchain->context = NULL;
6186 swapchain->num_contexts = 0;
6189 /* Do not call while under the GL lock. */
6190 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6193 struct wined3d_context *context;
6195 IWineD3DSurfaceImpl *target;
6197 /* Recreate the primary swapchain's context */
6198 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6199 if (!swapchain->context)
6201 ERR("Failed to allocate memory for swapchain context array.\n");
6202 return E_OUTOFMEMORY;
6205 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6206 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6208 WARN("Failed to create context.\n");
6209 HeapFree(GetProcessHeap(), 0, swapchain->context);
6213 swapchain->context[0] = context;
6214 swapchain->num_contexts = 1;
6215 create_dummy_textures(This);
6216 context_release(context);
6218 hr = This->shader_backend->shader_alloc_private(iface);
6221 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6225 hr = This->frag_pipe->alloc_private(iface);
6228 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6229 This->shader_backend->shader_free_private(iface);
6233 hr = This->blitter->alloc_private(iface);
6236 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6237 This->frag_pipe->free_private(iface);
6238 This->shader_backend->shader_free_private(iface);
6245 context_acquire(This, NULL);
6246 destroy_dummy_textures(This, context->gl_info);
6247 context_release(context);
6248 context_destroy(This, context);
6249 HeapFree(GetProcessHeap(), 0, swapchain->context);
6250 swapchain->num_contexts = 0;
6254 /* Do not call while under the GL lock. */
6255 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6256 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6259 IWineD3DSwapChainImpl *swapchain;
6261 BOOL DisplayModeChanged = FALSE;
6262 WINED3DDISPLAYMODE mode;
6263 TRACE("(%p)\n", This);
6265 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6267 ERR("Failed to get the first implicit swapchain\n");
6271 if(!is_display_mode_supported(This, pPresentationParameters)) {
6272 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6273 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6274 pPresentationParameters->BackBufferHeight);
6275 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6276 return WINED3DERR_INVALIDCALL;
6279 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6280 * on an existing gl context, so there's no real need for recreation.
6282 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6284 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6286 TRACE("New params:\n");
6287 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6288 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6289 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6290 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6291 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6292 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6293 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6294 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6295 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6296 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6297 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6298 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6299 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6301 /* No special treatment of these parameters. Just store them */
6302 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6303 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6304 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6305 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6307 /* What to do about these? */
6308 if (pPresentationParameters->BackBufferCount
6309 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6310 ERR("Cannot change the back buffer count yet\n");
6312 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6313 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6314 ERR("Cannot change the back buffer format yet\n");
6317 if (pPresentationParameters->hDeviceWindow
6318 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6319 ERR("Cannot change the device window yet\n");
6321 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6325 TRACE("Creating the depth stencil buffer\n");
6327 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6328 pPresentationParameters->BackBufferWidth,
6329 pPresentationParameters->BackBufferHeight,
6330 pPresentationParameters->AutoDepthStencilFormat,
6331 pPresentationParameters->MultiSampleType,
6332 pPresentationParameters->MultiSampleQuality,
6334 (IWineD3DSurface **)&This->auto_depth_stencil);
6337 ERR("Failed to create the depth stencil buffer\n");
6338 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6339 return WINED3DERR_INVALIDCALL;
6343 if (This->onscreen_depth_stencil)
6345 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6346 This->onscreen_depth_stencil = NULL;
6349 /* Reset the depth stencil */
6350 if (pPresentationParameters->EnableAutoDepthStencil)
6351 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6353 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6355 TRACE("Resetting stateblock\n");
6356 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6357 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6359 delete_opengl_contexts(iface, swapchain);
6361 if(pPresentationParameters->Windowed) {
6362 mode.Width = swapchain->orig_width;
6363 mode.Height = swapchain->orig_height;
6364 mode.RefreshRate = 0;
6365 mode.Format = swapchain->presentParms.BackBufferFormat;
6367 mode.Width = pPresentationParameters->BackBufferWidth;
6368 mode.Height = pPresentationParameters->BackBufferHeight;
6369 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6370 mode.Format = swapchain->presentParms.BackBufferFormat;
6373 /* Should Width == 800 && Height == 0 set 800x600? */
6374 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6375 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6376 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6380 if(!pPresentationParameters->Windowed) {
6381 DisplayModeChanged = TRUE;
6383 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6384 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6386 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6389 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6393 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6395 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6398 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6402 if (This->auto_depth_stencil)
6404 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6407 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6413 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6414 || DisplayModeChanged)
6416 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6418 if (!pPresentationParameters->Windowed)
6420 if(swapchain->presentParms.Windowed) {
6421 /* switch from windowed to fs */
6422 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6423 pPresentationParameters->BackBufferHeight);
6425 /* Fullscreen -> fullscreen mode change */
6426 MoveWindow(swapchain->device_window, 0, 0,
6427 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6431 else if (!swapchain->presentParms.Windowed)
6433 /* Fullscreen -> windowed switch */
6434 swapchain_restore_fullscreen_window(swapchain);
6436 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6437 } else if(!pPresentationParameters->Windowed) {
6438 DWORD style = This->style, exStyle = This->exStyle;
6439 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6440 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6441 * Reset to clear up their mess. Guild Wars also loses the device during that.
6445 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6446 pPresentationParameters->BackBufferHeight);
6447 This->style = style;
6448 This->exStyle = exStyle;
6451 /* Note: No parent needed for initial internal stateblock */
6452 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6453 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6454 else TRACE("Created stateblock %p\n", This->stateBlock);
6455 This->updateStateBlock = This->stateBlock;
6456 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6458 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6460 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6463 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6466 GetClientRect(swapchain->win_handle, &client_rect);
6468 if(!swapchain->presentParms.BackBufferCount)
6470 TRACE("Single buffered rendering\n");
6471 swapchain->render_to_fbo = FALSE;
6473 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6474 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6476 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6477 swapchain->presentParms.BackBufferWidth,
6478 swapchain->presentParms.BackBufferHeight,
6479 client_rect.right, client_rect.bottom);
6480 swapchain->render_to_fbo = TRUE;
6484 TRACE("Rendering directly to GL_BACK\n");
6485 swapchain->render_to_fbo = FALSE;
6489 hr = create_primary_opengl_context(iface, swapchain);
6490 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6492 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6498 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6500 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6502 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6508 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6510 TRACE("(%p) : pParameters %p\n", This, pParameters);
6512 *pParameters = This->createParms;
6516 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6517 IWineD3DSwapChain *swapchain;
6519 TRACE("Relaying to swapchain\n");
6521 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6522 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6523 IWineD3DSwapChain_Release(swapchain);
6527 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6528 IWineD3DSwapChain *swapchain;
6530 TRACE("Relaying to swapchain\n");
6532 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6533 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6534 IWineD3DSwapChain_Release(swapchain);
6539 /** ********************************************************
6540 * Notification functions
6541 ** ********************************************************/
6542 /** This function must be called in the release of a resource when ref == 0,
6543 * the contents of resource must still be correct,
6544 * any handles to other resource held by the caller must be closed
6545 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6546 *****************************************************/
6547 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6549 TRACE("(%p) : Adding resource %p\n", This, resource);
6551 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6554 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6556 TRACE("(%p) : Removing resource %p\n", This, resource);
6558 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6561 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6563 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6566 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6568 context_resource_released(device, resource, type);
6572 case WINED3DRTYPE_SURFACE:
6573 if (!device->d3d_initialized) break;
6575 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6577 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6579 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6580 device->render_targets[i] = NULL;
6584 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6586 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6587 device->depth_stencil = NULL;
6591 case WINED3DRTYPE_TEXTURE:
6592 case WINED3DRTYPE_CUBETEXTURE:
6593 case WINED3DRTYPE_VOLUMETEXTURE:
6594 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6596 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6598 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6599 resource, device->stateBlock, i);
6600 device->stateBlock->textures[i] = NULL;
6603 if (device->updateStateBlock != device->stateBlock
6604 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6606 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6607 resource, device->updateStateBlock, i);
6608 device->updateStateBlock->textures[i] = NULL;
6613 case WINED3DRTYPE_BUFFER:
6614 for (i = 0; i < MAX_STREAMS; ++i)
6616 if (device->stateBlock && device->stateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6618 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6619 resource, device->stateBlock, i);
6620 device->stateBlock->streams[i].buffer = NULL;
6623 if (device->updateStateBlock != device->stateBlock
6624 && device->updateStateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6626 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6627 resource, device->updateStateBlock, i);
6628 device->updateStateBlock->streams[i].buffer = NULL;
6633 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6635 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6636 resource, device->stateBlock);
6637 device->stateBlock->pIndexData = NULL;
6640 if (device->updateStateBlock != device->stateBlock
6641 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6643 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6644 resource, device->updateStateBlock);
6645 device->updateStateBlock->pIndexData = NULL;
6653 /* Remove the resource from the resourceStore */
6654 device_resource_remove(device, resource);
6656 TRACE("Resource released.\n");
6659 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6661 IWineD3DResourceImpl *resource, *cursor;
6663 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6665 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6666 TRACE("enumerating resource %p\n", resource);
6667 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6668 ret = pCallback((IWineD3DResource *) resource, pData);
6669 if(ret == S_FALSE) {
6670 TRACE("Canceling enumeration\n");
6677 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6680 IWineD3DResourceImpl *resource;
6682 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6684 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6685 if (type == WINED3DRTYPE_SURFACE)
6687 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6689 TRACE("Found surface %p for dc %p.\n", resource, dc);
6690 *surface = (IWineD3DSurface *)resource;
6696 return WINED3DERR_INVALIDCALL;
6699 /**********************************************************
6700 * IWineD3DDevice VTbl follows
6701 **********************************************************/
6703 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6705 /*** IUnknown methods ***/
6706 IWineD3DDeviceImpl_QueryInterface,
6707 IWineD3DDeviceImpl_AddRef,
6708 IWineD3DDeviceImpl_Release,
6709 /*** IWineD3DDevice methods ***/
6710 /*** Creation methods**/
6711 IWineD3DDeviceImpl_CreateBuffer,
6712 IWineD3DDeviceImpl_CreateVertexBuffer,
6713 IWineD3DDeviceImpl_CreateIndexBuffer,
6714 IWineD3DDeviceImpl_CreateStateBlock,
6715 IWineD3DDeviceImpl_CreateSurface,
6716 IWineD3DDeviceImpl_CreateRendertargetView,
6717 IWineD3DDeviceImpl_CreateTexture,
6718 IWineD3DDeviceImpl_CreateVolumeTexture,
6719 IWineD3DDeviceImpl_CreateVolume,
6720 IWineD3DDeviceImpl_CreateCubeTexture,
6721 IWineD3DDeviceImpl_CreateQuery,
6722 IWineD3DDeviceImpl_CreateSwapChain,
6723 IWineD3DDeviceImpl_CreateVertexDeclaration,
6724 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6725 IWineD3DDeviceImpl_CreateVertexShader,
6726 IWineD3DDeviceImpl_CreateGeometryShader,
6727 IWineD3DDeviceImpl_CreatePixelShader,
6728 IWineD3DDeviceImpl_CreatePalette,
6729 /*** Odd functions **/
6730 IWineD3DDeviceImpl_Init3D,
6731 IWineD3DDeviceImpl_InitGDI,
6732 IWineD3DDeviceImpl_Uninit3D,
6733 IWineD3DDeviceImpl_UninitGDI,
6734 IWineD3DDeviceImpl_SetMultithreaded,
6735 IWineD3DDeviceImpl_EvictManagedResources,
6736 IWineD3DDeviceImpl_GetAvailableTextureMem,
6737 IWineD3DDeviceImpl_GetBackBuffer,
6738 IWineD3DDeviceImpl_GetCreationParameters,
6739 IWineD3DDeviceImpl_GetDeviceCaps,
6740 IWineD3DDeviceImpl_GetDirect3D,
6741 IWineD3DDeviceImpl_GetDisplayMode,
6742 IWineD3DDeviceImpl_SetDisplayMode,
6743 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6744 IWineD3DDeviceImpl_GetRasterStatus,
6745 IWineD3DDeviceImpl_GetSwapChain,
6746 IWineD3DDeviceImpl_Reset,
6747 IWineD3DDeviceImpl_SetDialogBoxMode,
6748 IWineD3DDeviceImpl_SetCursorProperties,
6749 IWineD3DDeviceImpl_SetCursorPosition,
6750 IWineD3DDeviceImpl_ShowCursor,
6751 /*** Getters and setters **/
6752 IWineD3DDeviceImpl_SetClipPlane,
6753 IWineD3DDeviceImpl_GetClipPlane,
6754 IWineD3DDeviceImpl_SetClipStatus,
6755 IWineD3DDeviceImpl_GetClipStatus,
6756 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6757 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6758 IWineD3DDeviceImpl_SetDepthStencilSurface,
6759 IWineD3DDeviceImpl_GetDepthStencilSurface,
6760 IWineD3DDeviceImpl_SetGammaRamp,
6761 IWineD3DDeviceImpl_GetGammaRamp,
6762 IWineD3DDeviceImpl_SetIndexBuffer,
6763 IWineD3DDeviceImpl_GetIndexBuffer,
6764 IWineD3DDeviceImpl_SetBaseVertexIndex,
6765 IWineD3DDeviceImpl_GetBaseVertexIndex,
6766 IWineD3DDeviceImpl_SetLight,
6767 IWineD3DDeviceImpl_GetLight,
6768 IWineD3DDeviceImpl_SetLightEnable,
6769 IWineD3DDeviceImpl_GetLightEnable,
6770 IWineD3DDeviceImpl_SetMaterial,
6771 IWineD3DDeviceImpl_GetMaterial,
6772 IWineD3DDeviceImpl_SetNPatchMode,
6773 IWineD3DDeviceImpl_GetNPatchMode,
6774 IWineD3DDeviceImpl_SetPaletteEntries,
6775 IWineD3DDeviceImpl_GetPaletteEntries,
6776 IWineD3DDeviceImpl_SetPixelShader,
6777 IWineD3DDeviceImpl_GetPixelShader,
6778 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6779 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6780 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6781 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6782 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6783 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6784 IWineD3DDeviceImpl_SetRenderState,
6785 IWineD3DDeviceImpl_GetRenderState,
6786 IWineD3DDeviceImpl_SetRenderTarget,
6787 IWineD3DDeviceImpl_GetRenderTarget,
6788 IWineD3DDeviceImpl_SetFrontBackBuffers,
6789 IWineD3DDeviceImpl_SetSamplerState,
6790 IWineD3DDeviceImpl_GetSamplerState,
6791 IWineD3DDeviceImpl_SetScissorRect,
6792 IWineD3DDeviceImpl_GetScissorRect,
6793 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6794 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6795 IWineD3DDeviceImpl_SetStreamSource,
6796 IWineD3DDeviceImpl_GetStreamSource,
6797 IWineD3DDeviceImpl_SetStreamSourceFreq,
6798 IWineD3DDeviceImpl_GetStreamSourceFreq,
6799 IWineD3DDeviceImpl_SetTexture,
6800 IWineD3DDeviceImpl_GetTexture,
6801 IWineD3DDeviceImpl_SetTextureStageState,
6802 IWineD3DDeviceImpl_GetTextureStageState,
6803 IWineD3DDeviceImpl_SetTransform,
6804 IWineD3DDeviceImpl_GetTransform,
6805 IWineD3DDeviceImpl_SetVertexDeclaration,
6806 IWineD3DDeviceImpl_GetVertexDeclaration,
6807 IWineD3DDeviceImpl_SetVertexShader,
6808 IWineD3DDeviceImpl_GetVertexShader,
6809 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6810 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6811 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6812 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6813 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6814 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6815 IWineD3DDeviceImpl_SetViewport,
6816 IWineD3DDeviceImpl_GetViewport,
6817 IWineD3DDeviceImpl_MultiplyTransform,
6818 IWineD3DDeviceImpl_ValidateDevice,
6819 IWineD3DDeviceImpl_ProcessVertices,
6820 /*** State block ***/
6821 IWineD3DDeviceImpl_BeginStateBlock,
6822 IWineD3DDeviceImpl_EndStateBlock,
6823 /*** Scene management ***/
6824 IWineD3DDeviceImpl_BeginScene,
6825 IWineD3DDeviceImpl_EndScene,
6826 IWineD3DDeviceImpl_Present,
6827 IWineD3DDeviceImpl_Clear,
6828 IWineD3DDeviceImpl_ClearRendertargetView,
6830 IWineD3DDeviceImpl_SetPrimitiveType,
6831 IWineD3DDeviceImpl_GetPrimitiveType,
6832 IWineD3DDeviceImpl_DrawPrimitive,
6833 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6834 IWineD3DDeviceImpl_DrawPrimitiveUP,
6835 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6836 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6837 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6838 IWineD3DDeviceImpl_DrawRectPatch,
6839 IWineD3DDeviceImpl_DrawTriPatch,
6840 IWineD3DDeviceImpl_DeletePatch,
6841 IWineD3DDeviceImpl_ColorFill,
6842 IWineD3DDeviceImpl_UpdateTexture,
6843 IWineD3DDeviceImpl_UpdateSurface,
6844 IWineD3DDeviceImpl_GetFrontBufferData,
6845 /*** object tracking ***/
6846 IWineD3DDeviceImpl_EnumResources,
6847 IWineD3DDeviceImpl_GetSurfaceFromDC,
6848 IWineD3DDeviceImpl_AcquireFocusWindow,
6849 IWineD3DDeviceImpl_ReleaseFocusWindow,
6852 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6853 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6854 IWineD3DDeviceParent *device_parent)
6856 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6857 const struct fragment_pipeline *fragment_pipeline;
6858 struct shader_caps shader_caps;
6859 struct fragment_caps ffp_caps;
6860 WINED3DDISPLAYMODE mode;
6864 device->lpVtbl = &IWineD3DDevice_Vtbl;
6866 device->wined3d = (IWineD3D *)wined3d;
6867 IWineD3D_AddRef(device->wined3d);
6868 device->adapter = wined3d->adapter_count ? adapter : NULL;
6869 device->device_parent = device_parent;
6870 list_init(&device->resources);
6871 list_init(&device->shaders);
6873 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6874 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6876 /* Get the initial screen setup for ddraw. */
6877 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6880 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6881 IWineD3D_Release(device->wined3d);
6884 device->ddraw_width = mode.Width;
6885 device->ddraw_height = mode.Height;
6886 device->ddraw_format = mode.Format;
6888 /* Save the creation parameters. */
6889 device->createParms.AdapterOrdinal = adapter_idx;
6890 device->createParms.DeviceType = device_type;
6891 device->createParms.hFocusWindow = focus_window;
6892 device->createParms.BehaviorFlags = flags;
6894 device->devType = device_type;
6895 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6897 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6898 device->shader_backend = adapter->shader_backend;
6900 if (device->shader_backend)
6902 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6903 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6904 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6905 device->vs_clipping = shader_caps.VSClipping;
6907 fragment_pipeline = adapter->fragment_pipe;
6908 device->frag_pipe = fragment_pipeline;
6909 if (fragment_pipeline)
6911 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6912 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6914 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6915 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6918 ERR("Failed to compile state table, hr %#x.\n", hr);
6919 IWineD3D_Release(device->wined3d);
6923 device->blitter = adapter->blitter;
6929 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6930 DWORD rep = This->StateTable[state].representative;
6931 struct wined3d_context *context;
6936 for(i = 0; i < This->numContexts; i++) {
6937 context = This->contexts[i];
6938 if(isStateDirty(context, rep)) continue;
6940 context->dirtyArray[context->numDirtyEntries++] = rep;
6941 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6942 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6943 context->isStateDirty[idx] |= (1 << shift);
6947 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6949 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6950 *width = context->current_rt->pow2Width;
6951 *height = context->current_rt->pow2Height;
6954 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6956 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6957 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6958 * current context's drawable, which is the size of the back buffer of the swapchain
6959 * the active context belongs to. */
6960 *width = swapchain->presentParms.BackBufferWidth;
6961 *height = swapchain->presentParms.BackBufferHeight;
6964 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6965 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6967 if (device->filter_messages)
6969 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6970 window, message, wparam, lparam);
6971 return DefWindowProcW(window, message, wparam, lparam);
6974 if (message == WM_DESTROY)
6976 TRACE("unregister window %p.\n", window);
6977 wined3d_unregister_window(window);
6979 if (device->focus_window == window) device->focus_window = NULL;
6980 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6983 return CallWindowProcW(proc, window, message, wparam, lparam);