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 == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
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 GLuint buffer_object = 0;
195 const BYTE *data = NULL;
200 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201 element, i + 1, declaration->element_count);
203 if (!This->stateBlock->streamSource[element->input_slot]) continue;
205 stride = This->stateBlock->streamStride[element->input_slot];
206 if (This->stateBlock->streamIsUP)
208 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
215 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot],
216 &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((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot],
228 &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->streamIsUP)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
319 struct wined3d_event_query *query;
321 if (!(map & 1)) continue;
323 element = &stream_info->elements[i];
324 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
325 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
327 /* If PreLoad dropped the buffer object, update the stream info. */
328 if (buffer->buffer_object != element->buffer_object)
330 element->buffer_object = 0;
331 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 query = ((struct wined3d_buffer *) buffer)->query;
337 This->buffer_queries[This->num_buffer_queries++] = query;
343 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
344 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
346 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
347 e->format_desc = format_desc;
348 e->stride = strided->dwStride;
349 e->data = strided->lpData;
351 e->buffer_object = 0;
354 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
355 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
359 memset(stream_info, 0, sizeof(*stream_info));
361 if (strided->position.lpData)
362 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
363 if (strided->normal.lpData)
364 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
365 if (strided->diffuse.lpData)
366 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
367 if (strided->specular.lpData)
368 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
370 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
372 if (strided->texCoords[i].lpData)
373 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
374 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
377 stream_info->position_transformed = strided->position_transformed;
379 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
381 if (!stream_info->elements[i].format_desc) continue;
383 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
384 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
386 stream_info->swizzle_map |= 1 << i;
388 stream_info->use_map |= 1 << i;
392 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
394 TRACE("Strided Data:\n");
395 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
412 /* Context activation is done by the caller. */
413 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
415 struct wined3d_stream_info *stream_info = &device->strided_streams;
416 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
417 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
420 if (device->up_strided)
422 /* Note: this is a ddraw fixed-function code path. */
423 TRACE("=============================== Strided Input ================================\n");
424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
429 TRACE("============================= Vertex Declaration =============================\n");
430 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
433 if (vs && !stream_info->position_transformed)
435 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
438 device->useDrawStridedSlow = TRUE;
442 device->useDrawStridedSlow = FALSE;
447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
453 device->useDrawStridedSlow = TRUE;
457 device->useDrawStridedSlow = FALSE;
462 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
464 IWineD3DBaseTextureImpl *texture;
465 enum WINED3DSRGB srgb;
467 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
468 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
469 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
472 void device_preload_textures(IWineD3DDeviceImpl *device)
474 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
477 if (use_vs(stateblock))
479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
486 if (use_ps(stateblock))
488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
490 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
491 device_preload_texture(stateblock, i);
496 WORD ffu_map = device->fixed_function_usage_map;
498 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
501 device_preload_texture(stateblock, i);
506 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
508 struct wined3d_context **new_array;
510 TRACE("Adding context %p.\n", context);
512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
517 ERR("Failed to grow the context array.\n");
521 new_array[device->numContexts++] = context;
522 device->contexts = new_array;
526 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
528 struct wined3d_context **new_array;
532 TRACE("Removing context %p.\n", context);
534 for (i = 0; i < device->numContexts; ++i)
536 if (device->contexts[i] == context)
545 ERR("Context %p doesn't exist in context array.\n", context);
549 if (!--device->numContexts)
551 HeapFree(GetProcessHeap(), 0, device->contexts);
552 device->contexts = NULL;
556 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
557 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
560 ERR("Failed to shrink context array. Oh well.\n");
564 device->contexts = new_array;
567 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
569 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
570 WINED3DVIEWPORT *vp = &stateblock->viewport;
572 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
574 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
576 IntersectRect(rect, rect, &stateblock->scissorRect);
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
597 /* partial draw rect */
598 if (draw_rect->left || draw_rect->top
599 || draw_rect->right < target->currentDesc.Width
600 || draw_rect->bottom < target->currentDesc.Height)
603 /* partial clear rect */
604 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
605 || clear_rect->right < target->currentDesc.Width
606 || clear_rect->bottom < target->currentDesc.Height))
612 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
613 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
615 RECT current_rect, r;
617 if (ds->Flags & location)
618 SetRect(¤t_rect, 0, 0,
619 ds->ds_current_size.cx,
620 ds->ds_current_size.cy);
622 SetRectEmpty(¤t_rect);
624 IntersectRect(&r, draw_rect, ¤t_rect);
625 if (EqualRect(&r, draw_rect))
627 /* current_rect ⊇ draw_rect, modify only. */
628 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
632 if (EqualRect(&r, ¤t_rect))
634 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
638 /* Full clear, modify only. */
639 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 IntersectRect(&r, draw_rect, clear_rect);
644 if (EqualRect(&r, draw_rect))
646 /* clear_rect ⊇ draw_rect, modify only. */
647 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
653 surface_load_ds_location(ds, context, location);
654 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
657 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
658 UINT rect_count, const WINED3DRECT *rects, DWORD flags, const WINED3DCOLORVALUE *color,
659 float depth, DWORD stencil)
661 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
662 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
663 IWineD3DSurfaceImpl *target = rts[0];
664 UINT drawable_width, drawable_height;
665 struct wined3d_context *context;
666 GLbitfield clear_mask = 0;
670 device_get_draw_rect(device, &draw_rect);
672 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
673 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
674 * for the cleared parts, and the untouched parts.
676 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
677 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
678 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
679 * checking all this if the dest surface is in the drawable anyway. */
680 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, &draw_rect, clear_rect))
682 for (i = 0; i < rt_count; ++i)
684 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
688 context = context_acquire(device, target);
691 context_release(context);
692 WARN("Invalid context, skipping clear.\n");
696 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
698 target->get_drawable_size(context, &drawable_width, &drawable_height);
702 /* Only set the values up once, as they are not changing. */
703 if (flags & WINED3DCLEAR_STENCIL)
705 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
707 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
708 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
711 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
712 glClearStencil(stencil);
713 checkGLcall("glClearStencil");
714 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
717 if (flags & WINED3DCLEAR_ZBUFFER)
719 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
721 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
723 prepare_ds_clear(depth_stencil, context, location, &draw_rect, rect_count, clear_rect);
724 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
726 glDepthMask(GL_TRUE);
727 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
729 checkGLcall("glClearDepth");
730 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
733 if (flags & WINED3DCLEAR_TARGET)
735 for (i = 0; i < rt_count; ++i)
737 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
740 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
745 glClearColor(color->r, color->g, color->b, color->a);
746 checkGLcall("glClearColor");
747 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
752 if (context->render_offscreen)
754 glScissor(draw_rect.left, draw_rect.top,
755 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
759 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
760 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
762 checkGLcall("glScissor");
764 checkGLcall("glClear");
770 /* Now process each rect in turn. */
771 for (i = 0; i < rect_count; ++i)
773 /* Note that GL uses lower left, width/height. */
774 IntersectRect(¤t_rect, &draw_rect, &clear_rect[i]);
776 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
777 wine_dbgstr_rect(&clear_rect[i]),
778 wine_dbgstr_rect(¤t_rect));
780 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
781 * The rectangle is not cleared, no error is returned, but further rectanlges are
782 * still cleared if they are valid. */
783 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
785 TRACE("Rectangle with negative dimensions, ignoring.\n");
789 if (context->render_offscreen)
791 glScissor(current_rect.left, current_rect.top,
792 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 glScissor(current_rect.left, drawable_height - current_rect.bottom,
797 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
799 checkGLcall("glScissor");
802 checkGLcall("glClear");
808 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
809 && target->container.u.swapchain->front_buffer == target))
810 wglFlush(); /* Flush to ensure ordering across contexts. */
812 context_release(context);
818 /**********************************************************
819 * IUnknown parts follows
820 **********************************************************/
822 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
826 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
827 if (IsEqualGUID(riid, &IID_IUnknown)
828 || IsEqualGUID(riid, &IID_IWineD3DBase)
829 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
830 IUnknown_AddRef(iface);
835 return E_NOINTERFACE;
838 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
840 ULONG refCount = InterlockedIncrement(&This->ref);
842 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
846 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 ULONG refCount = InterlockedDecrement(&This->ref);
850 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
855 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
856 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
857 This->multistate_funcs[i] = NULL;
860 /* TODO: Clean up all the surfaces and textures! */
861 /* NOTE: You must release the parent if the object was created via a callback
862 ** ***************************/
864 if (!list_empty(&This->resources))
866 IWineD3DResourceImpl *resource;
867 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
869 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
871 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
872 FIXME("Leftover resource %p with type %s (%#x).\n",
873 resource, debug_d3dresourcetype(type), type);
877 if(This->contexts) ERR("Context array not freed!\n");
878 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
879 This->haveHardwareCursor = FALSE;
881 IWineD3D_Release(This->wined3d);
882 This->wined3d = NULL;
883 HeapFree(GetProcessHeap(), 0, This);
884 TRACE("Freed device %p\n", This);
890 /**********************************************************
891 * IWineD3DDevice implementation follows
892 **********************************************************/
893 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
895 *pParent = This->parent;
896 IUnknown_AddRef(This->parent);
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
901 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
904 struct wined3d_buffer *object;
907 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
909 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
912 ERR("Failed to allocate memory\n");
913 return E_OUTOFMEMORY;
916 FIXME("Ignoring access flags (pool)\n");
918 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
919 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
922 WARN("Failed to initialize buffer, hr %#x.\n", hr);
923 HeapFree(GetProcessHeap(), 0, object);
926 object->desc = *desc;
928 TRACE("Created buffer %p.\n", object);
930 *buffer = (IWineD3DBuffer *)object;
935 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
936 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
937 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
940 struct wined3d_buffer *object;
943 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
944 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
946 if (Pool == WINED3DPOOL_SCRATCH)
948 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
949 * anyway, SCRATCH vertex buffers aren't usable anywhere
951 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
952 *ppVertexBuffer = NULL;
953 return WINED3DERR_INVALIDCALL;
956 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
959 ERR("Out of memory\n");
960 *ppVertexBuffer = NULL;
961 return WINED3DERR_OUTOFVIDEOMEMORY;
964 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
965 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
968 WARN("Failed to initialize buffer, hr %#x.\n", hr);
969 HeapFree(GetProcessHeap(), 0, object);
973 TRACE("Created buffer %p.\n", object);
974 *ppVertexBuffer = (IWineD3DBuffer *)object;
979 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
980 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
981 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
984 struct wined3d_buffer *object;
987 TRACE("(%p) Creating index buffer\n", This);
989 /* Allocate the storage for the device */
990 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
993 ERR("Out of memory\n");
994 *ppIndexBuffer = NULL;
995 return WINED3DERR_OUTOFVIDEOMEMORY;
998 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
999 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1000 parent, parent_ops);
1003 WARN("Failed to initialize buffer, hr %#x\n", hr);
1004 HeapFree(GetProcessHeap(), 0, object);
1008 TRACE("Created buffer %p.\n", object);
1010 *ppIndexBuffer = (IWineD3DBuffer *) object;
1015 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1016 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1019 IWineD3DStateBlockImpl *object;
1022 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1025 ERR("Failed to allocate stateblock memory.\n");
1026 return E_OUTOFMEMORY;
1029 hr = stateblock_init(object, This, type);
1032 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1033 HeapFree(GetProcessHeap(), 0, object);
1037 TRACE("Created stateblock %p.\n", object);
1038 *stateblock = (IWineD3DStateBlock *)object;
1043 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1044 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **surface,
1045 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
1046 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1049 IWineD3DSurfaceImpl *object;
1052 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1053 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1054 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1055 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1056 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1058 if (Impl == SURFACE_OPENGL && !This->adapter)
1060 ERR("OpenGL surfaces are not available without OpenGL.\n");
1061 return WINED3DERR_NOTAVAILABLE;
1064 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1067 ERR("Failed to allocate surface memory.\n");
1068 return WINED3DERR_OUTOFVIDEOMEMORY;
1071 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1072 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1075 WARN("Failed to initialize surface, returning %#x.\n", hr);
1076 HeapFree(GetProcessHeap(), 0, object);
1080 TRACE("(%p) : Created surface %p\n", This, object);
1082 *surface = (IWineD3DSurface *)object;
1087 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1088 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1090 struct wined3d_rendertarget_view *object;
1092 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1093 iface, resource, parent, rendertarget_view);
1095 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1098 ERR("Failed to allocate memory\n");
1099 return E_OUTOFMEMORY;
1102 wined3d_rendertarget_view_init(object, resource, parent);
1104 TRACE("Created render target view %p.\n", object);
1105 *rendertarget_view = (IWineD3DRendertargetView *)object;
1110 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1111 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1112 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1115 IWineD3DTextureImpl *object;
1118 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1119 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1120 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1122 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1125 ERR("Out of memory\n");
1127 return WINED3DERR_OUTOFVIDEOMEMORY;
1130 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1133 WARN("Failed to initialize texture, returning %#x\n", hr);
1134 HeapFree(GetProcessHeap(), 0, object);
1139 *ppTexture = (IWineD3DTexture *)object;
1141 TRACE("(%p) : Created texture %p\n", This, object);
1146 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1147 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1148 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1151 IWineD3DVolumeTextureImpl *object;
1154 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1155 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1157 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1160 ERR("Out of memory\n");
1161 *ppVolumeTexture = NULL;
1162 return WINED3DERR_OUTOFVIDEOMEMORY;
1165 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1168 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1169 HeapFree(GetProcessHeap(), 0, object);
1170 *ppVolumeTexture = NULL;
1174 TRACE("(%p) : Created volume texture %p.\n", This, object);
1175 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1180 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1181 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1182 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1185 IWineD3DVolumeImpl *object;
1188 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1189 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1191 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1194 ERR("Out of memory\n");
1196 return WINED3DERR_OUTOFVIDEOMEMORY;
1199 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1202 WARN("Failed to initialize volume, returning %#x.\n", hr);
1203 HeapFree(GetProcessHeap(), 0, object);
1207 TRACE("(%p) : Created volume %p.\n", This, object);
1208 *ppVolume = (IWineD3DVolume *)object;
1213 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1214 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1215 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1218 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1221 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1224 ERR("Out of memory\n");
1225 *ppCubeTexture = NULL;
1226 return WINED3DERR_OUTOFVIDEOMEMORY;
1229 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1232 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1233 HeapFree(GetProcessHeap(), 0, object);
1234 *ppCubeTexture = NULL;
1238 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1239 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1244 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1245 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1248 IWineD3DQueryImpl *object;
1251 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1253 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1256 ERR("Failed to allocate query memory.\n");
1257 return E_OUTOFMEMORY;
1260 hr = query_init(object, This, type, parent);
1263 WARN("Failed to initialize query, hr %#x.\n", hr);
1264 HeapFree(GetProcessHeap(), 0, object);
1268 TRACE("Created query %p.\n", object);
1269 *query = (IWineD3DQuery *)object;
1274 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1275 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1276 IUnknown *parent, WINED3DSURFTYPE surface_type)
1278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1279 IWineD3DSwapChainImpl *object;
1282 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1283 iface, present_parameters, swapchain, parent, surface_type);
1285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1288 ERR("Failed to allocate swapchain memory.\n");
1289 return E_OUTOFMEMORY;
1292 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1295 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1296 HeapFree(GetProcessHeap(), 0, object);
1300 TRACE("Created swapchain %p.\n", object);
1301 *swapchain = (IWineD3DSwapChain *)object;
1306 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1307 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 TRACE("(%p)\n", This);
1311 return This->NumberOfSwapChains;
1314 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1316 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1318 if(iSwapChain < This->NumberOfSwapChains) {
1319 *pSwapChain = This->swapchains[iSwapChain];
1320 IWineD3DSwapChain_AddRef(*pSwapChain);
1321 TRACE("(%p) returning %p\n", This, *pSwapChain);
1324 TRACE("Swapchain out of range\n");
1326 return WINED3DERR_INVALIDCALL;
1330 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1331 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1332 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1335 IWineD3DVertexDeclarationImpl *object = NULL;
1338 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1339 iface, declaration, parent, elements, element_count);
1341 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1344 ERR("Failed to allocate vertex declaration memory.\n");
1345 return E_OUTOFMEMORY;
1348 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1351 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1352 HeapFree(GetProcessHeap(), 0, object);
1356 TRACE("Created vertex declaration %p.\n", object);
1357 *declaration = (IWineD3DVertexDeclaration *)object;
1362 struct wined3d_fvf_convert_state
1364 const struct wined3d_gl_info *gl_info;
1365 WINED3DVERTEXELEMENT *elements;
1370 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1371 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1373 WINED3DVERTEXELEMENT *elements = state->elements;
1374 const struct wined3d_format_desc *format_desc;
1375 UINT offset = state->offset;
1376 UINT idx = state->idx;
1378 elements[idx].format = format;
1379 elements[idx].input_slot = 0;
1380 elements[idx].offset = offset;
1381 elements[idx].output_slot = 0;
1382 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1383 elements[idx].usage = usage;
1384 elements[idx].usage_idx = usage_idx;
1386 format_desc = getFormatDescEntry(format, state->gl_info);
1387 state->offset += format_desc->component_count * format_desc->component_size;
1391 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1392 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1394 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1395 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1396 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1397 BOOL has_blend_idx = has_blend &&
1398 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1399 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1400 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1401 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1402 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1403 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1404 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1406 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1407 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1408 struct wined3d_fvf_convert_state state;
1411 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1412 if (has_blend_idx) num_blends--;
1414 /* Compute declaration size */
1415 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1416 has_psize + has_diffuse + has_specular + num_textures;
1418 state.gl_info = gl_info;
1419 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1420 if (!state.elements) return ~0U;
1426 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1427 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1428 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1429 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1431 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1434 if (has_blend && (num_blends > 0))
1436 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1437 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1452 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1455 ERR("Unexpected amount of blend values: %u\n", num_blends);
1462 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1463 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1464 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1466 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1468 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1471 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1472 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1473 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1474 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1476 for (idx = 0; idx < num_textures; ++idx)
1478 switch ((texcoords >> (idx * 2)) & 0x03)
1480 case WINED3DFVF_TEXTUREFORMAT1:
1481 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1483 case WINED3DFVF_TEXTUREFORMAT2:
1484 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1486 case WINED3DFVF_TEXTUREFORMAT3:
1487 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1489 case WINED3DFVF_TEXTUREFORMAT4:
1490 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1495 *ppVertexElements = state.elements;
1499 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1500 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1501 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1504 WINED3DVERTEXELEMENT *elements;
1508 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1510 size = ConvertFvfToDeclaration(This, fvf, &elements);
1511 if (size == ~0U) return E_OUTOFMEMORY;
1513 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1514 HeapFree(GetProcessHeap(), 0, elements);
1518 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1519 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1520 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1521 const struct wined3d_parent_ops *parent_ops)
1523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1524 IWineD3DVertexShaderImpl *object;
1527 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1530 ERR("Failed to allocate shader memory.\n");
1531 return E_OUTOFMEMORY;
1534 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1537 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1538 HeapFree(GetProcessHeap(), 0, object);
1542 TRACE("Created vertex shader %p.\n", object);
1543 *ppVertexShader = (IWineD3DVertexShader *)object;
1548 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1549 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1550 IWineD3DGeometryShader **shader, IUnknown *parent,
1551 const struct wined3d_parent_ops *parent_ops)
1553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 struct wined3d_geometryshader *object;
1557 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1560 ERR("Failed to allocate shader memory.\n");
1561 return E_OUTOFMEMORY;
1564 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1567 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1568 HeapFree(GetProcessHeap(), 0, object);
1572 TRACE("Created geometry shader %p.\n", object);
1573 *shader = (IWineD3DGeometryShader *)object;
1578 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1579 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1580 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1581 const struct wined3d_parent_ops *parent_ops)
1583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1584 IWineD3DPixelShaderImpl *object;
1587 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1590 ERR("Failed to allocate shader memory.\n");
1591 return E_OUTOFMEMORY;
1594 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1597 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1598 HeapFree(GetProcessHeap(), 0, object);
1602 TRACE("Created pixel shader %p.\n", object);
1603 *ppPixelShader = (IWineD3DPixelShader *)object;
1608 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1609 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1612 IWineD3DPaletteImpl *object;
1615 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1616 iface, Flags, PalEnt, Palette, Parent);
1618 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1621 ERR("Failed to allocate palette memory.\n");
1622 return E_OUTOFMEMORY;
1625 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1628 WARN("Failed to initialize palette, hr %#x.\n", hr);
1629 HeapFree(GetProcessHeap(), 0, object);
1633 TRACE("Created palette %p.\n", object);
1634 *Palette = (IWineD3DPalette *)object;
1639 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1643 HDC dcb = NULL, dcs = NULL;
1644 WINEDDCOLORKEY colorkey;
1646 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1649 GetObjectA(hbm, sizeof(BITMAP), &bm);
1650 dcb = CreateCompatibleDC(NULL);
1652 SelectObject(dcb, hbm);
1656 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1657 * couldn't be loaded
1659 memset(&bm, 0, sizeof(bm));
1664 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1665 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1666 NULL, &wined3d_null_parent_ops);
1668 ERR("Wine logo requested, but failed to create surface\n");
1673 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1674 if(FAILED(hr)) goto out;
1675 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1676 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1678 colorkey.dwColorSpaceLowValue = 0;
1679 colorkey.dwColorSpaceHighValue = 0;
1680 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1755 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1757 if (!wined3d_register_window(window, device))
1759 ERR("Failed to register window %p.\n", window);
1763 device->focus_window = window;
1764 SetForegroundWindow(window);
1769 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1771 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1773 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1774 device->focus_window = NULL;
1777 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1778 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1781 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1782 IWineD3DSwapChainImpl *swapchain = NULL;
1783 struct wined3d_context *context;
1788 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1790 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1791 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1793 TRACE("(%p) : Creating stateblock\n", This);
1794 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1797 WARN("Failed to create stateblock\n");
1800 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1801 This->updateStateBlock = This->stateBlock;
1802 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1804 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1805 sizeof(*This->render_targets) * gl_info->limits.buffers);
1807 This->NumberOfPalettes = 1;
1808 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1809 if (!This->palettes || !This->render_targets)
1811 ERR("Out of memory!\n");
1815 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1816 if(!This->palettes[0]) {
1817 ERR("Out of memory!\n");
1821 for (i = 0; i < 256; ++i) {
1822 This->palettes[0][i].peRed = 0xFF;
1823 This->palettes[0][i].peGreen = 0xFF;
1824 This->palettes[0][i].peBlue = 0xFF;
1825 This->palettes[0][i].peFlags = 0xFF;
1827 This->currentPalette = 0;
1829 /* Initialize the texture unit mapping to a 1:1 mapping */
1830 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1832 if (state < gl_info->limits.fragment_samplers)
1834 This->texUnitMap[state] = state;
1835 This->rev_tex_unit_map[state] = state;
1837 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1838 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1842 /* Setup the implicit swapchain. This also initializes a context. */
1843 TRACE("Creating implicit swapchain\n");
1844 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1845 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1848 WARN("Failed to create implicit swapchain\n");
1852 This->NumberOfSwapChains = 1;
1853 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1854 if(!This->swapchains) {
1855 ERR("Out of memory!\n");
1858 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1860 if (swapchain->back_buffers && swapchain->back_buffers[0])
1862 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1863 This->render_targets[0] = swapchain->back_buffers[0];
1867 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1868 This->render_targets[0] = swapchain->front_buffer;
1870 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1872 /* Depth Stencil support */
1873 This->depth_stencil = This->auto_depth_stencil;
1874 if (This->depth_stencil)
1875 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1877 hr = This->shader_backend->shader_alloc_private(iface);
1879 TRACE("Shader private data couldn't be allocated\n");
1882 hr = This->frag_pipe->alloc_private(iface);
1884 TRACE("Fragment pipeline private data couldn't be allocated\n");
1887 hr = This->blitter->alloc_private(iface);
1889 TRACE("Blitter private data couldn't be allocated\n");
1893 /* Set up some starting GL setup */
1895 /* Setup all the devices defaults */
1896 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1898 context = context_acquire(This, swapchain->front_buffer);
1900 create_dummy_textures(This);
1904 /* Initialize the current view state */
1905 This->view_ident = 1;
1906 This->contexts[0]->last_was_rhw = 0;
1907 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1908 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1910 switch(wined3d_settings.offscreen_rendering_mode) {
1912 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1915 case ORM_BACKBUFFER:
1917 if (context_get_current()->aux_buffers > 0)
1919 TRACE("Using auxilliary buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_AUX0;
1922 TRACE("Using back buffer for offscreen rendering\n");
1923 This->offscreenBuffer = GL_BACK;
1928 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1931 context_release(context);
1933 /* Clear the screen */
1934 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1935 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1938 This->d3d_initialized = TRUE;
1940 if(wined3d_settings.logo) {
1941 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1943 This->highest_dirty_ps_const = 0;
1944 This->highest_dirty_vs_const = 0;
1948 HeapFree(GetProcessHeap(), 0, This->render_targets);
1949 HeapFree(GetProcessHeap(), 0, This->swapchains);
1950 This->NumberOfSwapChains = 0;
1951 if(This->palettes) {
1952 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1953 HeapFree(GetProcessHeap(), 0, This->palettes);
1955 This->NumberOfPalettes = 0;
1957 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1959 if(This->stateBlock) {
1960 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1961 This->stateBlock = NULL;
1963 if (This->blit_priv) {
1964 This->blitter->free_private(iface);
1966 if (This->fragment_priv) {
1967 This->frag_pipe->free_private(iface);
1969 if (This->shader_priv) {
1970 This->shader_backend->shader_free_private(iface);
1975 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1976 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1979 IWineD3DSwapChainImpl *swapchain = NULL;
1982 /* Setup the implicit swapchain */
1983 TRACE("Creating implicit swapchain\n");
1984 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1985 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1988 WARN("Failed to create implicit swapchain\n");
1992 This->NumberOfSwapChains = 1;
1993 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1994 if(!This->swapchains) {
1995 ERR("Out of memory!\n");
1998 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2002 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2006 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2008 IWineD3DResource_UnLoad(resource);
2009 IWineD3DResource_Release(resource);
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2014 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 const struct wined3d_gl_info *gl_info;
2018 struct wined3d_context *context;
2021 TRACE("(%p)\n", This);
2023 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2025 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2026 * it was created. Thus make sure a context is active for the glDelete* calls
2028 context = context_acquire(This, NULL);
2029 gl_info = context->gl_info;
2031 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2033 /* Unload resources */
2034 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2036 TRACE("Deleting high order patches\n");
2037 for(i = 0; i < PATCHMAP_SIZE; i++) {
2038 struct list *e1, *e2;
2039 struct WineD3DRectPatch *patch;
2040 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2041 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2042 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2046 /* Delete the mouse cursor texture */
2047 if(This->cursorTexture) {
2049 glDeleteTextures(1, &This->cursorTexture);
2051 This->cursorTexture = 0;
2054 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2055 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2057 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2058 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2061 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2062 * private data, it might contain opengl pointers
2064 if(This->depth_blt_texture) {
2066 glDeleteTextures(1, &This->depth_blt_texture);
2068 This->depth_blt_texture = 0;
2070 if (This->depth_blt_rb) {
2072 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2074 This->depth_blt_rb = 0;
2075 This->depth_blt_rb_w = 0;
2076 This->depth_blt_rb_h = 0;
2079 /* Release the update stateblock */
2080 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2081 if(This->updateStateBlock != This->stateBlock)
2082 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2084 This->updateStateBlock = NULL;
2086 { /* because were not doing proper internal refcounts releasing the primary state block
2087 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2088 to set this->stateBlock = NULL; first */
2089 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2090 This->stateBlock = NULL;
2092 /* Release the stateblock */
2093 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2094 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2098 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2099 This->blitter->free_private(iface);
2100 This->frag_pipe->free_private(iface);
2101 This->shader_backend->shader_free_private(iface);
2103 /* Release the buffers (with sanity checks)*/
2104 if (This->onscreen_depth_stencil)
2106 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2107 This->onscreen_depth_stencil = NULL;
2110 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2111 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2113 if (This->auto_depth_stencil != This->depth_stencil)
2114 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2116 This->depth_stencil = NULL;
2118 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2119 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2121 TRACE("Setting rendertarget to NULL\n");
2122 This->render_targets[0] = NULL;
2124 if (This->auto_depth_stencil)
2126 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2128 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2130 This->auto_depth_stencil = NULL;
2133 context_release(context);
2135 for(i=0; i < This->NumberOfSwapChains; i++) {
2136 TRACE("Releasing the implicit swapchain %d\n", i);
2137 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2138 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2142 HeapFree(GetProcessHeap(), 0, This->swapchains);
2143 This->swapchains = NULL;
2144 This->NumberOfSwapChains = 0;
2146 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2147 HeapFree(GetProcessHeap(), 0, This->palettes);
2148 This->palettes = NULL;
2149 This->NumberOfPalettes = 0;
2151 HeapFree(GetProcessHeap(), 0, This->render_targets);
2152 This->render_targets = NULL;
2154 This->d3d_initialized = FALSE;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2163 for(i=0; i < This->NumberOfSwapChains; i++) {
2164 TRACE("Releasing the implicit swapchain %d\n", i);
2165 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2170 HeapFree(GetProcessHeap(), 0, This->swapchains);
2171 This->swapchains = NULL;
2172 This->NumberOfSwapChains = 0;
2176 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2177 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2178 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2180 * There is no way to deactivate thread safety once it is enabled.
2182 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2185 /*For now just store the flag(needed in case of ddraw) */
2186 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2189 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2190 const WINED3DDISPLAYMODE* pMode) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2193 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2197 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2199 /* Resize the screen even without a window:
2200 * The app could have unset it with SetCooperativeLevel, but not called
2201 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2202 * but we don't have any hwnd
2205 memset(&devmode, 0, sizeof(devmode));
2206 devmode.dmSize = sizeof(devmode);
2207 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2208 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2209 devmode.dmPelsWidth = pMode->Width;
2210 devmode.dmPelsHeight = pMode->Height;
2212 devmode.dmDisplayFrequency = pMode->RefreshRate;
2213 if (pMode->RefreshRate != 0) {
2214 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2217 /* Only change the mode if necessary */
2218 if( (This->ddraw_width == pMode->Width) &&
2219 (This->ddraw_height == pMode->Height) &&
2220 (This->ddraw_format == pMode->Format) &&
2221 (pMode->RefreshRate == 0) ) {
2225 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2226 if (ret != DISP_CHANGE_SUCCESSFUL) {
2227 if(devmode.dmDisplayFrequency != 0) {
2228 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2229 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2230 devmode.dmDisplayFrequency = 0;
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2233 if(ret != DISP_CHANGE_SUCCESSFUL) {
2234 return WINED3DERR_NOTAVAILABLE;
2238 /* Store the new values */
2239 This->ddraw_width = pMode->Width;
2240 This->ddraw_height = pMode->Height;
2241 This->ddraw_format = pMode->Format;
2243 /* And finally clip mouse to our screen */
2244 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2245 ClipCursor(&clip_rc);
2250 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 *ppD3D = This->wined3d;
2253 TRACE("Returning %p.\n", *ppD3D);
2254 IWineD3D_AddRef(*ppD3D);
2258 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2261 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2262 (This->adapter->TextureRam/(1024*1024)),
2263 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2264 /* return simulated texture memory left */
2265 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2269 * Get / Set Stream Source
2271 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2272 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2275 IWineD3DBuffer *oldSrc;
2277 if (StreamNumber >= MAX_STREAMS) {
2278 WARN("Stream out of range %d\n", StreamNumber);
2279 return WINED3DERR_INVALIDCALL;
2280 } else if(OffsetInBytes & 0x3) {
2281 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2282 return WINED3DERR_INVALIDCALL;
2285 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2286 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2288 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2290 if(oldSrc == pStreamData &&
2291 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2292 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2293 TRACE("Application is setting the old values over, nothing to do\n");
2297 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2299 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2300 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2303 /* Handle recording of state blocks */
2304 if (This->isRecordingState) {
2305 TRACE("Recording... not performing anything\n");
2306 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2307 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2311 if (pStreamData != NULL) {
2312 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2313 IWineD3DBuffer_AddRef(pStreamData);
2315 if (oldSrc != NULL) {
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;
2330 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2331 This->stateBlock->streamSource[StreamNumber],
2332 This->stateBlock->streamOffset[StreamNumber],
2333 This->stateBlock->streamStride[StreamNumber]);
2335 if (StreamNumber >= MAX_STREAMS) {
2336 WARN("Stream out of range %d\n", StreamNumber);
2337 return WINED3DERR_INVALIDCALL;
2339 *pStream = This->stateBlock->streamSource[StreamNumber];
2340 *pStride = This->stateBlock->streamStride[StreamNumber];
2342 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2345 if (*pStream != NULL) {
2346 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2351 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2354 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2356 /* Verify input at least in d3d9 this is invalid*/
2357 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2358 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2359 return WINED3DERR_INVALIDCALL;
2361 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2362 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2363 return WINED3DERR_INVALIDCALL;
2366 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2367 return WINED3DERR_INVALIDCALL;
2370 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2371 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2373 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2374 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2376 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2377 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2384 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2387 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2388 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2390 TRACE("(%p) : returning %d\n", This, *Divider);
2396 * Get / Set & Multiply Transform
2398 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 /* Most of this routine, comments included copied from ddraw tree initially: */
2402 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2404 /* Handle recording of state blocks */
2405 if (This->isRecordingState) {
2406 TRACE("Recording... not performing anything\n");
2407 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2408 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2413 * If the new matrix is the same as the current one,
2414 * we cut off any further processing. this seems to be a reasonable
2415 * optimization because as was noticed, some apps (warcraft3 for example)
2416 * tend towards setting the same matrix repeatedly for some reason.
2418 * From here on we assume that the new matrix is different, wherever it matters.
2420 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2421 TRACE("The app is setting the same matrix over again\n");
2424 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2428 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2429 where ViewMat = Camera space, WorldMat = world space.
2431 In OpenGL, camera and world space is combined into GL_MODELVIEW
2432 matrix. The Projection matrix stay projection matrix.
2435 /* Capture the times we can just ignore the change for now */
2436 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2437 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2438 /* Handled by the state manager */
2441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2445 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2448 *pMatrix = This->stateBlock->transforms[State];
2452 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2453 const WINED3DMATRIX *mat = NULL;
2456 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2457 * below means it will be recorded in a state block change, but it
2458 * works regardless where it is recorded.
2459 * If this is found to be wrong, change to StateBlock.
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2464 if (State <= HIGHEST_TRANSFORMSTATE)
2466 mat = &This->updateStateBlock->transforms[State];
2468 FIXME("Unhandled transform state!!\n");
2471 multiply_matrix(&temp, mat, pMatrix);
2473 /* Apply change via set transform - will reapply to eg. lights this way */
2474 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2480 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2481 you can reference any indexes you want as long as that number max are enabled at any
2482 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2483 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2484 but when recording, just build a chain pretty much of commands to be replayed. */
2486 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2488 struct wined3d_light_info *object = NULL;
2489 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2493 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2495 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2499 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2500 return WINED3DERR_INVALIDCALL;
2503 switch(pLight->Type) {
2504 case WINED3DLIGHT_POINT:
2505 case WINED3DLIGHT_SPOT:
2506 case WINED3DLIGHT_PARALLELPOINT:
2507 case WINED3DLIGHT_GLSPOT:
2508 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2511 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2513 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2514 return WINED3DERR_INVALIDCALL;
2518 case WINED3DLIGHT_DIRECTIONAL:
2519 /* Ignores attenuation */
2523 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2524 return WINED3DERR_INVALIDCALL;
2527 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2529 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2530 if(object->OriginalIndex == Index) break;
2535 TRACE("Adding new light\n");
2536 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2538 ERR("Out of memory error when allocating a light\n");
2539 return E_OUTOFMEMORY;
2541 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2542 object->glIndex = -1;
2543 object->OriginalIndex = Index;
2546 /* Initialize the object */
2547 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,
2548 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2549 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2550 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2551 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2552 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2553 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2555 /* Save away the information */
2556 object->OriginalParms = *pLight;
2558 switch (pLight->Type) {
2559 case WINED3DLIGHT_POINT:
2561 object->lightPosn[0] = pLight->Position.x;
2562 object->lightPosn[1] = pLight->Position.y;
2563 object->lightPosn[2] = pLight->Position.z;
2564 object->lightPosn[3] = 1.0f;
2565 object->cutoff = 180.0f;
2569 case WINED3DLIGHT_DIRECTIONAL:
2571 object->lightPosn[0] = -pLight->Direction.x;
2572 object->lightPosn[1] = -pLight->Direction.y;
2573 object->lightPosn[2] = -pLight->Direction.z;
2574 object->lightPosn[3] = 0.0f;
2575 object->exponent = 0.0f;
2576 object->cutoff = 180.0f;
2579 case WINED3DLIGHT_SPOT:
2581 object->lightPosn[0] = pLight->Position.x;
2582 object->lightPosn[1] = pLight->Position.y;
2583 object->lightPosn[2] = pLight->Position.z;
2584 object->lightPosn[3] = 1.0f;
2587 object->lightDirn[0] = pLight->Direction.x;
2588 object->lightDirn[1] = pLight->Direction.y;
2589 object->lightDirn[2] = pLight->Direction.z;
2590 object->lightDirn[3] = 1.0f;
2593 * opengl-ish and d3d-ish spot lights use too different models for the
2594 * light "intensity" as a function of the angle towards the main light direction,
2595 * so we only can approximate very roughly.
2596 * however spot lights are rather rarely used in games (if ever used at all).
2597 * furthermore if still used, probably nobody pays attention to such details.
2599 if (pLight->Falloff == 0) {
2600 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2601 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2602 * will always be 1.0 for both of them, and we don't have to care for the
2603 * rest of the rather complex calculation
2605 object->exponent = 0.0f;
2607 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2608 if (rho < 0.0001f) rho = 0.0001f;
2609 object->exponent = -0.3f/logf(cosf(rho/2));
2611 if (object->exponent > 128.0f)
2613 object->exponent = 128.0f;
2615 object->cutoff = (float) (pLight->Phi*90/M_PI);
2621 FIXME("Unrecognized light type %d\n", pLight->Type);
2624 /* Update the live definitions if the light is currently assigned a glIndex */
2625 if (object->glIndex != -1 && !This->isRecordingState) {
2626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2631 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2633 struct wined3d_light_info *lightInfo = NULL;
2634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2635 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2637 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2639 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2641 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2642 if(lightInfo->OriginalIndex == Index) break;
2646 if (lightInfo == NULL) {
2647 TRACE("Light information requested but light not defined\n");
2648 return WINED3DERR_INVALIDCALL;
2651 *pLight = lightInfo->OriginalParms;
2656 * Get / Set Light Enable
2657 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2659 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2661 struct wined3d_light_info *lightInfo = NULL;
2662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2663 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2665 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2667 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2669 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2670 if(lightInfo->OriginalIndex == Index) break;
2673 TRACE("Found light: %p\n", lightInfo);
2675 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2676 if (lightInfo == NULL) {
2678 TRACE("Light enabled requested but light not defined, so defining one!\n");
2679 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2681 /* Search for it again! Should be fairly quick as near head of list */
2682 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2684 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2685 if(lightInfo->OriginalIndex == Index) break;
2688 if (lightInfo == NULL) {
2689 FIXME("Adding default lights has failed dismally\n");
2690 return WINED3DERR_INVALIDCALL;
2695 if(lightInfo->glIndex != -1) {
2696 if(!This->isRecordingState) {
2697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2700 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2701 lightInfo->glIndex = -1;
2703 TRACE("Light already disabled, nothing to do\n");
2705 lightInfo->enabled = FALSE;
2707 lightInfo->enabled = TRUE;
2708 if (lightInfo->glIndex != -1) {
2710 TRACE("Nothing to do as light was enabled\n");
2713 /* Find a free gl light */
2714 for(i = 0; i < This->maxConcurrentLights; i++) {
2715 if(This->updateStateBlock->activeLights[i] == NULL) {
2716 This->updateStateBlock->activeLights[i] = lightInfo;
2717 lightInfo->glIndex = i;
2721 if(lightInfo->glIndex == -1) {
2722 /* Our tests show that Windows returns D3D_OK in this situation, even with
2723 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2724 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2725 * as well for those lights.
2727 * TODO: Test how this affects rendering
2729 WARN("Too many concurrently active lights\n");
2733 /* i == lightInfo->glIndex */
2734 if(!This->isRecordingState) {
2735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2743 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2745 struct wined3d_light_info *lightInfo = NULL;
2746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2749 TRACE("(%p) : for idx(%d)\n", This, Index);
2751 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2753 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2754 if(lightInfo->OriginalIndex == Index) break;
2758 if (lightInfo == NULL) {
2759 TRACE("Light enabled state requested but light not defined\n");
2760 return WINED3DERR_INVALIDCALL;
2762 /* true is 128 according to SetLightEnable */
2763 *pEnable = lightInfo->enabled ? 128 : 0;
2768 * Get / Set Clip Planes
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2774 /* Validate Index */
2775 if (Index >= This->adapter->gl_info.limits.clipplanes)
2777 TRACE("Application has requested clipplane this device doesn't support\n");
2778 return WINED3DERR_INVALIDCALL;
2781 This->updateStateBlock->changed.clipplane |= 1 << Index;
2783 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2784 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2785 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2786 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2787 TRACE("Application is setting old values over, nothing to do\n");
2791 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2792 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2793 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2794 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2796 /* Handle recording of state blocks */
2797 if (This->isRecordingState) {
2798 TRACE("Recording... not performing anything\n");
2802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 TRACE("(%p) : for idx %d\n", This, Index);
2811 /* Validate Index */
2812 if (Index >= This->adapter->gl_info.limits.clipplanes)
2814 TRACE("Application has requested clipplane this device doesn't support\n");
2815 return WINED3DERR_INVALIDCALL;
2818 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2819 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2820 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2821 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2826 * Get / Set Clip Plane Status
2827 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 FIXME("(%p) : stub\n", This);
2832 if (NULL == pClipStatus) {
2833 return WINED3DERR_INVALIDCALL;
2835 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2836 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2840 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 FIXME("(%p) : stub\n", This);
2843 if (NULL == pClipStatus) {
2844 return WINED3DERR_INVALIDCALL;
2846 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2847 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2852 * Get / Set Material
2854 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2857 This->updateStateBlock->changed.material = TRUE;
2858 This->updateStateBlock->material = *pMaterial;
2860 /* Handle recording of state blocks */
2861 if (This->isRecordingState) {
2862 TRACE("Recording... not performing anything\n");
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 *pMaterial = This->updateStateBlock->material;
2873 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2874 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2875 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2876 pMaterial->Ambient.b, pMaterial->Ambient.a);
2877 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2878 pMaterial->Specular.b, pMaterial->Specular.a);
2879 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2880 pMaterial->Emissive.b, pMaterial->Emissive.a);
2881 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2889 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2890 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 IWineD3DBuffer *oldIdxs;
2895 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2896 oldIdxs = This->updateStateBlock->pIndexData;
2898 This->updateStateBlock->changed.indices = TRUE;
2899 This->updateStateBlock->pIndexData = pIndexData;
2900 This->updateStateBlock->IndexFmt = fmt;
2902 /* Handle recording of state blocks */
2903 if (This->isRecordingState) {
2904 TRACE("Recording... not performing anything\n");
2905 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2906 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2910 if(oldIdxs != pIndexData) {
2911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2913 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2914 IWineD3DBuffer_AddRef(pIndexData);
2917 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2918 IWineD3DBuffer_Release(oldIdxs);
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2929 *ppIndexData = This->stateBlock->pIndexData;
2931 /* up ref count on ppindexdata */
2933 IWineD3DBuffer_AddRef(*ppIndexData);
2934 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2936 TRACE("(%p) No index data set\n", This);
2938 TRACE("Returning %p\n", *ppIndexData);
2943 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2944 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 TRACE("(%p)->(%d)\n", This, BaseIndex);
2948 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2949 TRACE("Application is setting the old value over, nothing to do\n");
2953 This->updateStateBlock->baseVertexIndex = BaseIndex;
2955 if (This->isRecordingState) {
2956 TRACE("Recording... not performing anything\n");
2959 /* The base vertex index affects the stream sources */
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2964 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 TRACE("(%p) : base_index %p\n", This, base_index);
2968 *base_index = This->stateBlock->baseVertexIndex;
2970 TRACE("Returning %u\n", *base_index);
2976 * Get / Set Viewports
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 TRACE("(%p)\n", This);
2982 This->updateStateBlock->changed.viewport = TRUE;
2983 This->updateStateBlock->viewport = *pViewport;
2985 /* Handle recording of state blocks */
2986 if (This->isRecordingState) {
2987 TRACE("Recording... not performing anything\n");
2991 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2992 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2999 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 TRACE("(%p)\n", This);
3002 *pViewport = This->stateBlock->viewport;
3007 * Get / Set Render States
3008 * TODO: Verify against dx9 definitions
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 DWORD oldValue = This->stateBlock->renderState[State];
3015 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3017 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3018 This->updateStateBlock->renderState[State] = Value;
3020 /* Handle recording of state blocks */
3021 if (This->isRecordingState) {
3022 TRACE("Recording... not performing anything\n");
3026 /* Compared here and not before the assignment to allow proper stateblock recording */
3027 if(Value == oldValue) {
3028 TRACE("Application is setting the old value over, nothing to do\n");
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3041 *pValue = This->stateBlock->renderState[State];
3046 * Get / Set Sampler States
3047 * TODO: Verify against dx9 definitions
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3055 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3057 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3058 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3061 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3062 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3063 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3066 * SetSampler is designed to allow for more than the standard up to 8 textures
3067 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3068 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3070 * http://developer.nvidia.com/object/General_FAQ.html#t6
3072 * There are two new settings for GForce
3074 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3075 * and the texture one:
3076 * GL_MAX_TEXTURE_COORDS_ARB.
3077 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3080 oldValue = This->stateBlock->samplerState[Sampler][Type];
3081 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3082 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3084 /* Handle recording of state blocks */
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3090 if(oldValue == Value) {
3091 TRACE("Application is setting the old value over, nothing to do\n");
3095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3100 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3104 This, Sampler, debug_d3dsamplerstate(Type), Type);
3106 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3107 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3110 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3111 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3112 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3114 *Value = This->stateBlock->samplerState[Sampler][Type];
3115 TRACE("(%p) : Returning %#x\n", This, *Value);
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 This->updateStateBlock->changed.scissorRect = TRUE;
3124 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3125 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3128 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3130 if(This->isRecordingState) {
3131 TRACE("Recording... not performing anything\n");
3135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3140 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 *pRect = This->updateStateBlock->scissorRect;
3144 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3150 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3152 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3154 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3155 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3157 This->updateStateBlock->vertexDecl = pDecl;
3158 This->updateStateBlock->changed.vertexDecl = TRUE;
3160 if (This->isRecordingState) {
3161 TRACE("Recording... not performing anything\n");
3163 } else if(pDecl == oldDecl) {
3164 /* Checked after the assignment to allow proper stateblock recording */
3165 TRACE("Application is setting the old declaration over, nothing to do\n");
3169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3173 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3178 *ppDecl = This->stateBlock->vertexDecl;
3179 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3187 This->updateStateBlock->vertexShader = pShader;
3188 This->updateStateBlock->changed.vertexShader = TRUE;
3190 if (This->isRecordingState) {
3191 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3192 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3193 TRACE("Recording... not performing anything\n");
3195 } else if(oldShader == pShader) {
3196 /* Checked here to allow proper stateblock recording */
3197 TRACE("App is setting the old shader over, nothing to do\n");
3201 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3202 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3203 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 if (NULL == ppShader) {
3214 return WINED3DERR_INVALIDCALL;
3216 *ppShader = This->stateBlock->vertexShader;
3217 if( NULL != *ppShader)
3218 IWineD3DVertexShader_AddRef(*ppShader);
3220 TRACE("(%p) : returning %p\n", This, *ppShader);
3224 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3225 IWineD3DDevice *iface,
3227 CONST BOOL *srcData,
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3233 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3234 iface, srcData, start, count);
3236 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3238 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3239 for (i = 0; i < cnt; i++)
3240 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3242 for (i = start; i < cnt + start; ++i) {
3243 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3246 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3251 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3252 IWineD3DDevice *iface,
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 int cnt = min(count, MAX_CONST_B - start);
3260 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3261 iface, dstData, start, count);
3263 if (dstData == NULL || cnt < 0)
3264 return WINED3DERR_INVALIDCALL;
3266 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3271 IWineD3DDevice *iface,
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3279 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3280 iface, srcData, start, count);
3282 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3284 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3285 for (i = 0; i < cnt; i++)
3286 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3287 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3289 for (i = start; i < cnt + start; ++i) {
3290 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3293 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3298 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3299 IWineD3DDevice *iface,
3304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3305 int cnt = min(count, MAX_CONST_I - start);
3307 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3308 iface, dstData, start, count);
3310 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3311 return WINED3DERR_INVALIDCALL;
3313 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3317 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3318 IWineD3DDevice *iface,
3320 CONST float *srcData,
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3327 iface, srcData, start, count);
3329 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3330 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3331 return WINED3DERR_INVALIDCALL;
3333 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3335 for (i = 0; i < count; i++)
3336 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3337 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3340 if (!This->isRecordingState)
3342 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3346 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3347 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3353 IWineD3DDevice *iface,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 int cnt = min(count, This->d3d_vshader_constantF - start);
3361 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3362 iface, dstData, start, count);
3364 if (dstData == NULL || cnt < 0)
3365 return WINED3DERR_INVALIDCALL;
3367 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3371 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3373 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3379 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3381 DWORD i = This->rev_tex_unit_map[unit];
3382 DWORD j = This->texUnitMap[stage];
3384 This->texUnitMap[stage] = unit;
3385 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3387 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3390 This->rev_tex_unit_map[unit] = stage;
3391 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3393 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3397 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3400 This->fixed_function_usage_map = 0;
3401 for (i = 0; i < MAX_TEXTURES; ++i) {
3402 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3403 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3404 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3405 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3406 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3407 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3408 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3409 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3411 if (color_op == WINED3DTOP_DISABLE) {
3412 /* Not used, and disable higher stages */
3416 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3417 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3418 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3419 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3420 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3421 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3422 This->fixed_function_usage_map |= (1 << i);
3425 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3426 This->fixed_function_usage_map |= (1 << (i + 1));
3431 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3433 unsigned int i, tex;
3436 device_update_fixed_function_usage_map(This);
3437 ffu_map = This->fixed_function_usage_map;
3439 if (This->max_ffp_textures == gl_info->limits.texture_stages
3440 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3442 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3444 if (!(ffu_map & 1)) continue;
3446 if (This->texUnitMap[i] != i) {
3447 device_map_stage(This, i, i);
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3449 markTextureStagesDirty(This, i);
3455 /* Now work out the mapping */
3457 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3459 if (!(ffu_map & 1)) continue;
3461 if (This->texUnitMap[i] != tex) {
3462 device_map_stage(This, i, tex);
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3464 markTextureStagesDirty(This, i);
3471 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3473 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3474 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3477 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3478 if (sampler_type[i] && This->texUnitMap[i] != i)
3480 device_map_stage(This, i, i);
3481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3482 if (i < gl_info->limits.texture_stages)
3484 markTextureStagesDirty(This, i);
3490 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3491 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3493 DWORD current_mapping = This->rev_tex_unit_map[unit];
3495 /* Not currently used */
3496 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3498 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3499 /* Used by a fragment sampler */
3501 if (!pshader_sampler_tokens) {
3502 /* No pixel shader, check fixed function */
3503 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3506 /* Pixel shader, check the shader's sampler map */
3507 return !pshader_sampler_tokens[current_mapping];
3510 /* Used by a vertex sampler */
3511 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3514 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3516 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3517 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3518 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3519 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3523 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3525 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3526 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3527 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3530 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3531 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3532 if (vshader_sampler_type[i])
3534 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3536 /* Already mapped somewhere */
3540 while (start >= 0) {
3541 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3543 device_map_stage(This, vsampler_idx, start);
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3556 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3558 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3559 BOOL vs = use_vs(This->stateBlock);
3560 BOOL ps = use_ps(This->stateBlock);
3563 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3564 * that would be really messy and require shader recompilation
3565 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3566 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3568 if (ps) device_map_psamplers(This, gl_info);
3569 else device_map_fixed_function_samplers(This, gl_info);
3571 if (vs) device_map_vsamplers(This, ps, gl_info);
3574 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3577 This->updateStateBlock->pixelShader = pShader;
3578 This->updateStateBlock->changed.pixelShader = TRUE;
3580 /* Handle recording of state blocks */
3581 if (This->isRecordingState) {
3582 TRACE("Recording... not performing anything\n");
3585 if (This->isRecordingState) {
3586 TRACE("Recording... not performing anything\n");
3587 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3588 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3592 if(pShader == oldShader) {
3593 TRACE("App is setting the old pixel shader over, nothing to do\n");
3597 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3598 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3600 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 if (NULL == ppShader) {
3610 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3611 return WINED3DERR_INVALIDCALL;
3614 *ppShader = This->stateBlock->pixelShader;
3615 if (NULL != *ppShader) {
3616 IWineD3DPixelShader_AddRef(*ppShader);
3618 TRACE("(%p) : returning %p\n", This, *ppShader);
3622 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3623 IWineD3DDevice *iface,
3625 CONST BOOL *srcData,
3628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3631 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3632 iface, srcData, start, count);
3634 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3636 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3637 for (i = 0; i < cnt; i++)
3638 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3640 for (i = start; i < cnt + start; ++i) {
3641 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3644 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3649 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3650 IWineD3DDevice *iface,
3655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3656 int cnt = min(count, MAX_CONST_B - start);
3658 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3659 iface, dstData, start, count);
3661 if (dstData == NULL || cnt < 0)
3662 return WINED3DERR_INVALIDCALL;
3664 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3668 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3669 IWineD3DDevice *iface,
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3677 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3678 iface, srcData, start, count);
3680 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3682 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3683 for (i = 0; i < cnt; i++)
3684 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3685 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3687 for (i = start; i < cnt + start; ++i) {
3688 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3691 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3696 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3697 IWineD3DDevice *iface,
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 int cnt = min(count, MAX_CONST_I - start);
3705 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3706 iface, dstData, start, count);
3708 if (dstData == NULL || cnt < 0)
3709 return WINED3DERR_INVALIDCALL;
3711 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3715 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3716 IWineD3DDevice *iface,
3718 CONST float *srcData,
3721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3724 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3725 iface, srcData, start, count);
3727 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3728 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3729 return WINED3DERR_INVALIDCALL;
3731 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3733 for (i = 0; i < count; i++)
3734 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3735 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3738 if (!This->isRecordingState)
3740 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3744 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3745 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3750 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3751 IWineD3DDevice *iface,
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 int cnt = min(count, This->d3d_pshader_constantF - start);
3759 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3760 iface, dstData, start, count);
3762 if (dstData == NULL || cnt < 0)
3763 return WINED3DERR_INVALIDCALL;
3765 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3769 /* Context activation is done by the caller. */
3770 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3771 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3772 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3776 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3779 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3783 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3785 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3788 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3790 ERR("Source has no position mask\n");
3791 return WINED3DERR_INVALIDCALL;
3794 /* We might access VBOs from this code, so hold the lock */
3797 if (!dest->resource.allocatedMemory)
3798 buffer_get_sysmem(dest, gl_info);
3800 /* Get a pointer into the destination vbo(create one if none exists) and
3801 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3803 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3805 dest->flags |= WINED3D_BUFFER_CREATEBO;
3806 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3809 if (dest->buffer_object)
3811 unsigned char extrabytes = 0;
3812 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3813 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3814 * this may write 4 extra bytes beyond the area that should be written
3816 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3817 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3818 if(!dest_conv_addr) {
3819 ERR("Out of memory\n");
3820 /* Continue without storing converted vertices */
3822 dest_conv = dest_conv_addr;
3826 * a) WINED3DRS_CLIPPING is enabled
3827 * b) WINED3DVOP_CLIP is passed
3829 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3830 static BOOL warned = FALSE;
3832 * The clipping code is not quite correct. Some things need
3833 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3834 * so disable clipping for now.
3835 * (The graphics in Half-Life are broken, and my processvertices
3836 * test crashes with IDirect3DDevice3)
3842 FIXME("Clipping is broken and disabled for now\n");
3844 } else doClip = FALSE;
3845 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3847 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3850 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3851 WINED3DTS_PROJECTION,
3853 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3854 WINED3DTS_WORLDMATRIX(0),
3857 TRACE("View mat:\n");
3858 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);
3859 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);
3860 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);
3861 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);
3863 TRACE("Proj mat:\n");
3864 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);
3865 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);
3866 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);
3867 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);
3869 TRACE("World mat:\n");
3870 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);
3871 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);
3872 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);
3873 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);
3875 /* Get the viewport */
3876 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3877 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3878 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3880 multiply_matrix(&mat,&view_mat,&world_mat);
3881 multiply_matrix(&mat,&proj_mat,&mat);
3883 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3885 for (i = 0; i < dwCount; i+= 1) {
3886 unsigned int tex_index;
3888 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3889 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3890 /* The position first */
3891 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3892 const float *p = (const float *)(element->data + i * element->stride);
3894 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3896 /* Multiplication with world, view and projection matrix */
3897 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);
3898 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);
3899 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);
3900 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);
3902 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3904 /* WARNING: The following things are taken from d3d7 and were not yet checked
3905 * against d3d8 or d3d9!
3908 /* Clipping conditions: From msdn
3910 * A vertex is clipped if it does not match the following requirements
3914 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3916 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3917 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3922 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3923 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3926 /* "Normal" viewport transformation (not clipped)
3927 * 1) The values are divided by rhw
3928 * 2) The y axis is negative, so multiply it with -1
3929 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3930 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3931 * 4) Multiply x with Width/2 and add Width/2
3932 * 5) The same for the height
3933 * 6) Add the viewpoint X and Y to the 2D coordinates and
3934 * The minimum Z value to z
3935 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3937 * Well, basically it's simply a linear transformation into viewport
3949 z *= vp.MaxZ - vp.MinZ;
3951 x += vp.Width / 2 + vp.X;
3952 y += vp.Height / 2 + vp.Y;
3957 /* That vertex got clipped
3958 * Contrary to OpenGL it is not dropped completely, it just
3959 * undergoes a different calculation.
3961 TRACE("Vertex got clipped\n");
3968 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3969 * outside of the main vertex buffer memory. That needs some more
3974 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3977 ( (float *) dest_ptr)[0] = x;
3978 ( (float *) dest_ptr)[1] = y;
3979 ( (float *) dest_ptr)[2] = z;
3980 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3982 dest_ptr += 3 * sizeof(float);
3984 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3985 dest_ptr += sizeof(float);
3990 ( (float *) dest_conv)[0] = x * w;
3991 ( (float *) dest_conv)[1] = y * w;
3992 ( (float *) dest_conv)[2] = z * w;
3993 ( (float *) dest_conv)[3] = w;
3995 dest_conv += 3 * sizeof(float);
3997 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3998 dest_conv += sizeof(float);
4002 if (DestFVF & WINED3DFVF_PSIZE) {
4003 dest_ptr += sizeof(DWORD);
4004 if(dest_conv) dest_conv += sizeof(DWORD);
4006 if (DestFVF & WINED3DFVF_NORMAL) {
4007 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4008 const float *normal = (const float *)(element->data + i * element->stride);
4009 /* AFAIK this should go into the lighting information */
4010 FIXME("Didn't expect the destination to have a normal\n");
4011 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4013 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4017 if (DestFVF & WINED3DFVF_DIFFUSE) {
4018 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4019 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4020 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4022 static BOOL warned = FALSE;
4025 ERR("No diffuse color in source, but destination has one\n");
4029 *( (DWORD *) dest_ptr) = 0xffffffff;
4030 dest_ptr += sizeof(DWORD);
4033 *( (DWORD *) dest_conv) = 0xffffffff;
4034 dest_conv += sizeof(DWORD);
4038 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4040 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4041 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4042 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4043 dest_conv += sizeof(DWORD);
4048 if (DestFVF & WINED3DFVF_SPECULAR)
4050 /* What's the color value in the feedback buffer? */
4051 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4052 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4053 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4055 static BOOL warned = FALSE;
4058 ERR("No specular color in source, but destination has one\n");
4062 *( (DWORD *) dest_ptr) = 0xFF000000;
4063 dest_ptr += sizeof(DWORD);
4066 *( (DWORD *) dest_conv) = 0xFF000000;
4067 dest_conv += sizeof(DWORD);
4071 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4073 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4074 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4075 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4076 dest_conv += sizeof(DWORD);
4081 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4082 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4083 const float *tex_coord = (const float *)(element->data + i * element->stride);
4084 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4086 ERR("No source texture, but destination requests one\n");
4087 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4088 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4091 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4093 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4100 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4101 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4102 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4103 dwCount * get_flexible_vertex_size(DestFVF),
4105 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4106 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4113 #undef copy_and_next
4115 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4116 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 struct wined3d_stream_info stream_info;
4121 const struct wined3d_gl_info *gl_info;
4122 struct wined3d_context *context;
4123 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4126 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4129 ERR("Output vertex declaration not implemented yet\n");
4132 /* Need any context to write to the vbo. */
4133 context = context_acquire(This, NULL);
4134 gl_info = context->gl_info;
4136 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4137 * control the streamIsUP flag, thus restore it afterwards.
4139 This->stateBlock->streamIsUP = FALSE;
4140 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4141 This->stateBlock->streamIsUP = streamWasUP;
4143 if(vbo || SrcStartIndex) {
4145 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4146 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4148 * Also get the start index in, but only loop over all elements if there's something to add at all.
4150 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4152 struct wined3d_stream_info_element *e;
4154 if (!(stream_info.use_map & (1 << i))) continue;
4156 e = &stream_info.elements[i];
4157 if (e->buffer_object)
4159 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4160 e->buffer_object = 0;
4161 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4163 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4164 vb->buffer_object = 0;
4167 if (e->data) e->data += e->stride * SrcStartIndex;
4171 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4172 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4174 context_release(context);
4180 * Get / Set Texture Stage States
4181 * TODO: Verify against dx9 definitions
4183 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4185 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4186 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4188 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4190 if (Stage >= gl_info->limits.texture_stages)
4192 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4193 Stage, gl_info->limits.texture_stages - 1);
4197 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4198 This->updateStateBlock->textureState[Stage][Type] = Value;
4200 if (This->isRecordingState) {
4201 TRACE("Recording... not performing anything\n");
4205 /* Checked after the assignments to allow proper stateblock recording */
4206 if(oldValue == Value) {
4207 TRACE("App is setting the old value over, nothing to do\n");
4211 if(Stage > This->stateBlock->lowest_disabled_stage &&
4212 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4213 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4214 * Changes in other states are important on disabled stages too
4219 if(Type == WINED3DTSS_COLOROP) {
4222 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4223 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4224 * they have to be disabled
4226 * The current stage is dirtified below.
4228 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4229 TRACE("Additionally dirtifying stage %u\n", i);
4230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4232 This->stateBlock->lowest_disabled_stage = Stage;
4233 TRACE("New lowest disabled: %u\n", Stage);
4234 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4235 /* Previously disabled stage enabled. Stages above it may need enabling
4236 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4237 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4239 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4242 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4244 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4247 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4250 This->stateBlock->lowest_disabled_stage = i;
4251 TRACE("New lowest disabled: %u\n", i);
4255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4263 *pValue = This->updateStateBlock->textureState[Stage][Type];
4270 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4271 DWORD stage, IWineD3DBaseTexture *texture)
4273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4274 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4275 IWineD3DBaseTexture *prev;
4277 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4279 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4280 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4282 /* Windows accepts overflowing this array... we do not. */
4283 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4285 WARN("Ignoring invalid stage %u.\n", stage);
4289 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4290 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4292 WARN("Rejecting attempt to set scratch texture.\n");
4293 return WINED3DERR_INVALIDCALL;
4296 This->updateStateBlock->changed.textures |= 1 << stage;
4298 prev = This->updateStateBlock->textures[stage];
4299 TRACE("Previous texture %p.\n", prev);
4301 if (texture == prev)
4303 TRACE("App is setting the same texture again, nothing to do.\n");
4307 TRACE("Setting new texture to %p.\n", texture);
4308 This->updateStateBlock->textures[stage] = texture;
4310 if (This->isRecordingState)
4312 TRACE("Recording... not performing anything\n");
4314 if (texture) IWineD3DBaseTexture_AddRef(texture);
4315 if (prev) IWineD3DBaseTexture_Release(prev);
4322 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4323 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4324 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4326 IWineD3DBaseTexture_AddRef(texture);
4328 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4333 if (!prev && stage < gl_info->limits.texture_stages)
4335 /* The source arguments for color and alpha ops have different
4336 * meanings when a NULL texture is bound, so the COLOROP and
4337 * ALPHAOP have to be dirtified. */
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4342 if (bind_count == 1) t->baseTexture.sampler = stage;
4347 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4348 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4350 IWineD3DBaseTexture_Release(prev);
4352 if (!texture && stage < gl_info->limits.texture_stages)
4354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4358 if (bind_count && t->baseTexture.sampler == stage)
4362 /* Search for other stages the texture is bound to. Shouldn't
4363 * happen if applications bind textures to a single stage only. */
4364 TRACE("Searching for other stages the texture is bound to.\n");
4365 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4367 if (This->updateStateBlock->textures[i] == prev)
4369 TRACE("Texture is also bound to stage %u.\n", i);
4370 t->baseTexture.sampler = i;
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4382 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4385 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4387 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4388 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4391 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4392 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4393 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4396 *ppTexture=This->stateBlock->textures[Stage];
4398 IWineD3DBaseTexture_AddRef(*ppTexture);
4400 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4408 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4409 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4411 IWineD3DSwapChain *swapchain;
4414 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4415 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4417 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4420 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4424 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4425 IWineD3DSwapChain_Release(swapchain);
4428 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4435 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 WARN("(%p) : stub, calling idirect3d for now\n", This);
4438 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4441 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4443 IWineD3DSwapChain *swapChain;
4446 if(iSwapChain > 0) {
4447 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4448 if (hr == WINED3D_OK) {
4449 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4450 IWineD3DSwapChain_Release(swapChain);
4452 FIXME("(%p) Error getting display mode\n", This);
4455 /* Don't read the real display mode,
4456 but return the stored mode instead. X11 can't change the color
4457 depth, and some apps are pretty angry if they SetDisplayMode from
4458 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4460 Also don't relay to the swapchain because with ddraw it's possible
4461 that there isn't a swapchain at all */
4462 pMode->Width = This->ddraw_width;
4463 pMode->Height = This->ddraw_height;
4464 pMode->Format = This->ddraw_format;
4465 pMode->RefreshRate = 0;
4473 * Stateblock related functions
4476 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 IWineD3DStateBlock *stateblock;
4481 TRACE("(%p)\n", This);
4483 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4485 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4486 if (FAILED(hr)) return hr;
4488 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4489 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4490 This->isRecordingState = TRUE;
4492 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4497 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4501 if (!This->isRecordingState) {
4502 WARN("(%p) not recording! returning error\n", This);
4503 *ppStateBlock = NULL;
4504 return WINED3DERR_INVALIDCALL;
4507 stateblock_init_contained_states(object);
4509 *ppStateBlock = (IWineD3DStateBlock*) object;
4510 This->isRecordingState = FALSE;
4511 This->updateStateBlock = This->stateBlock;
4512 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4513 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4514 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4519 * Scene related functions
4521 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4522 /* At the moment we have no need for any functionality at the beginning
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 TRACE("(%p)\n", This);
4528 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4529 return WINED3DERR_INVALIDCALL;
4531 This->inScene = TRUE;
4535 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 struct wined3d_context *context;
4540 TRACE("(%p)\n", This);
4542 if(!This->inScene) {
4543 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4544 return WINED3DERR_INVALIDCALL;
4547 context = context_acquire(This, NULL);
4548 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4550 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4552 context_release(context);
4554 This->inScene = FALSE;
4558 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4559 const RECT *pSourceRect, const RECT *pDestRect,
4560 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4562 IWineD3DSwapChain *swapChain = NULL;
4564 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4566 TRACE("iface %p.\n", iface);
4568 for(i = 0 ; i < swapchains ; i ++) {
4570 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4571 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4572 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4573 IWineD3DSwapChain_Release(swapChain);
4579 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4580 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR color, float Z, DWORD Stencil)
4582 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), color (0x%08x), Z (%f), Stencil (%d)\n", This,
4586 Count, pRects, Flags, color, Z, Stencil);
4588 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4590 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4591 /* TODO: What about depth stencil buffers without stencil bits? */
4592 return WINED3DERR_INVALIDCALL;
4595 return device_clear_render_targets(This, This->adapter->gl_info.limits.buffers,
4596 This->render_targets, Count, pRects, Flags, &c, Z, Stencil);
4603 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4604 WINED3DPRIMITIVETYPE primitive_type)
4606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4610 This->updateStateBlock->changed.primitive_type = TRUE;
4611 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4614 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4615 WINED3DPRIMITIVETYPE *primitive_type)
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4621 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4623 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4626 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4632 if(!This->stateBlock->vertexDecl) {
4633 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4634 return WINED3DERR_INVALIDCALL;
4637 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4638 if(This->stateBlock->streamIsUP) {
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4640 This->stateBlock->streamIsUP = FALSE;
4643 if(This->stateBlock->loadBaseVertexIndex != 0) {
4644 This->stateBlock->loadBaseVertexIndex = 0;
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4647 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4648 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4652 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 IWineD3DBuffer *pIB;
4659 pIB = This->stateBlock->pIndexData;
4661 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4662 * without an index buffer set. (The first time at least...)
4663 * D3D8 simply dies, but I doubt it can do much harm to return
4664 * D3DERR_INVALIDCALL there as well. */
4665 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4666 return WINED3DERR_INVALIDCALL;
4669 if(!This->stateBlock->vertexDecl) {
4670 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4671 return WINED3DERR_INVALIDCALL;
4674 if(This->stateBlock->streamIsUP) {
4675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4676 This->stateBlock->streamIsUP = FALSE;
4678 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4680 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4682 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4688 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4689 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4693 drawPrimitive(iface, index_count, startIndex, idxStride,
4694 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4699 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4700 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4705 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4706 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4708 if(!This->stateBlock->vertexDecl) {
4709 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4710 return WINED3DERR_INVALIDCALL;
4713 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4714 vb = This->stateBlock->streamSource[0];
4715 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4716 if (vb) IWineD3DBuffer_Release(vb);
4717 This->stateBlock->streamOffset[0] = 0;
4718 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4719 This->stateBlock->streamIsUP = TRUE;
4720 This->stateBlock->loadBaseVertexIndex = 0;
4722 /* TODO: Only mark dirty if drawing from a different UP address */
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4725 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4727 /* MSDN specifies stream zero settings must be set to NULL */
4728 This->stateBlock->streamStride[0] = 0;
4729 This->stateBlock->streamSource[0] = NULL;
4731 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4732 * the new stream sources or use UP drawing again
4737 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4738 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4739 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4746 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4747 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4749 if(!This->stateBlock->vertexDecl) {
4750 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4751 return WINED3DERR_INVALIDCALL;
4754 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4760 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4761 vb = This->stateBlock->streamSource[0];
4762 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4763 if (vb) IWineD3DBuffer_Release(vb);
4764 This->stateBlock->streamIsUP = TRUE;
4765 This->stateBlock->streamOffset[0] = 0;
4766 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4768 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4769 This->stateBlock->baseVertexIndex = 0;
4770 This->stateBlock->loadBaseVertexIndex = 0;
4771 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4775 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4777 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4778 This->stateBlock->streamSource[0] = NULL;
4779 This->stateBlock->streamStride[0] = 0;
4780 ib = This->stateBlock->pIndexData;
4782 IWineD3DBuffer_Release(ib);
4783 This->stateBlock->pIndexData = NULL;
4785 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4786 * SetStreamSource to specify a vertex buffer
4792 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4793 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4797 /* Mark the state dirty until we have nicer tracking
4798 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4803 This->stateBlock->baseVertexIndex = 0;
4804 This->up_strided = DrawPrimStrideData;
4805 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4806 This->up_strided = NULL;
4810 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4811 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4812 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4815 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4817 /* Mark the state dirty until we have nicer tracking
4818 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4823 This->stateBlock->streamIsUP = TRUE;
4824 This->stateBlock->baseVertexIndex = 0;
4825 This->up_strided = DrawPrimStrideData;
4826 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4827 This->up_strided = NULL;
4831 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4832 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4833 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4835 WINED3DLOCKED_BOX src;
4836 WINED3DLOCKED_BOX dst;
4839 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4840 iface, pSourceVolume, pDestinationVolume);
4842 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4843 * dirtification to improve loading performance.
4845 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4846 if(FAILED(hr)) return hr;
4847 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4849 IWineD3DVolume_UnlockBox(pSourceVolume);
4853 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4855 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4857 IWineD3DVolume_UnlockBox(pSourceVolume);
4859 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4864 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4865 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4867 unsigned int level_count, i;
4868 WINED3DRESOURCETYPE type;
4871 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4873 /* Verify that the source and destination textures are non-NULL. */
4874 if (!src_texture || !dst_texture)
4876 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4877 return WINED3DERR_INVALIDCALL;
4880 if (src_texture == dst_texture)
4882 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4883 return WINED3DERR_INVALIDCALL;
4886 /* Verify that the source and destination textures are the same type. */
4887 type = IWineD3DBaseTexture_GetType(src_texture);
4888 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4890 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4891 return WINED3DERR_INVALIDCALL;
4894 /* Check that both textures have the identical numbers of levels. */
4895 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4896 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4898 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4899 return WINED3DERR_INVALIDCALL;
4902 /* Make sure that the destination texture is loaded. */
4903 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4905 /* Update every surface level of the texture. */
4908 case WINED3DRTYPE_TEXTURE:
4910 IWineD3DSurface *src_surface;
4911 IWineD3DSurface *dst_surface;
4913 for (i = 0; i < level_count; ++i)
4915 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4916 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4917 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4918 IWineD3DSurface_Release(dst_surface);
4919 IWineD3DSurface_Release(src_surface);
4922 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4929 case WINED3DRTYPE_CUBETEXTURE:
4931 IWineD3DSurface *src_surface;
4932 IWineD3DSurface *dst_surface;
4933 WINED3DCUBEMAP_FACES face;
4935 for (i = 0; i < level_count; ++i)
4937 /* Update each cube face. */
4938 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4940 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4941 face, i, &src_surface);
4942 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4943 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4944 face, i, &dst_surface);
4945 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4946 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4947 IWineD3DSurface_Release(dst_surface);
4948 IWineD3DSurface_Release(src_surface);
4951 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4959 case WINED3DRTYPE_VOLUMETEXTURE:
4961 IWineD3DVolume *src_volume;
4962 IWineD3DVolume *dst_volume;
4964 for (i = 0; i < level_count; ++i)
4966 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4967 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4968 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4969 IWineD3DVolume_Release(dst_volume);
4970 IWineD3DVolume_Release(src_volume);
4973 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4981 FIXME("Unsupported texture type %#x.\n", type);
4982 return WINED3DERR_INVALIDCALL;
4988 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4989 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4991 IWineD3DSwapChain *swapchain;
4994 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
4996 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4997 if (FAILED(hr)) return hr;
4999 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5000 IWineD3DSwapChain_Release(swapchain);
5005 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5007 IWineD3DBaseTextureImpl *texture;
5010 TRACE("(%p) : %p\n", This, pNumPasses);
5012 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5013 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5014 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5015 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5017 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5018 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5019 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5022 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5023 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5025 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5026 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5029 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5030 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5033 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5034 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5035 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5040 /* return a sensible default */
5043 TRACE("returning D3D_OK\n");
5047 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5051 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5053 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5054 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5055 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5057 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5062 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5066 PALETTEENTRY **palettes;
5068 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5070 if (PaletteNumber >= MAX_PALETTES) {
5071 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5072 return WINED3DERR_INVALIDCALL;
5075 if (PaletteNumber >= This->NumberOfPalettes) {
5076 NewSize = This->NumberOfPalettes;
5079 } while(PaletteNumber >= NewSize);
5080 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5082 ERR("Out of memory!\n");
5083 return E_OUTOFMEMORY;
5085 This->palettes = palettes;
5086 This->NumberOfPalettes = NewSize;
5089 if (!This->palettes[PaletteNumber]) {
5090 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5091 if (!This->palettes[PaletteNumber]) {
5092 ERR("Out of memory!\n");
5093 return E_OUTOFMEMORY;
5097 for (j = 0; j < 256; ++j) {
5098 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5099 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5100 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5101 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5103 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5104 TRACE("(%p) : returning\n", This);
5108 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5112 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5113 /* What happens in such situation isn't documented; Native seems to silently abort
5114 on such conditions. Return Invalid Call. */
5115 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5116 return WINED3DERR_INVALIDCALL;
5118 for (j = 0; j < 256; ++j) {
5119 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5120 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5121 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5122 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5124 TRACE("(%p) : returning\n", This);
5128 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5131 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5132 (tested with reference rasterizer). Return Invalid Call. */
5133 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5134 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5135 return WINED3DERR_INVALIDCALL;
5137 /*TODO: stateblocks */
5138 if (This->currentPalette != PaletteNumber) {
5139 This->currentPalette = PaletteNumber;
5140 dirtify_p8_texture_samplers(This);
5142 TRACE("(%p) : returning\n", This);
5146 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 if (PaletteNumber == NULL) {
5149 WARN("(%p) : returning Invalid Call\n", This);
5150 return WINED3DERR_INVALIDCALL;
5152 /*TODO: stateblocks */
5153 *PaletteNumber = This->currentPalette;
5154 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5158 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 FIXME("(%p) : stub\n", This);
5167 This->softwareVertexProcessing = bSoftware;
5172 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5177 FIXME("(%p) : stub\n", This);
5180 return This->softwareVertexProcessing;
5183 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5184 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5186 IWineD3DSwapChain *swapchain;
5189 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5190 iface, swapchain_idx, raster_status);
5192 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5195 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5199 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5200 IWineD3DSwapChain_Release(swapchain);
5203 WARN("Failed to get raster status, hr %#x.\n", hr);
5210 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5213 if(nSegments != 0.0f) {
5216 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5223 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5228 FIXME("iface %p stub!\n", iface);
5234 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5235 IWineD3DSurface *src_surface, const RECT *src_rect,
5236 IWineD3DSurface *dst_surface, const POINT *dst_point)
5238 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5239 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5241 const struct wined3d_format_desc *src_format;
5242 const struct wined3d_format_desc *dst_format;
5243 const struct wined3d_gl_info *gl_info;
5244 struct wined3d_context *context;
5245 const unsigned char *data;
5246 UINT update_w, update_h;
5247 CONVERT_TYPES convert;
5251 struct wined3d_format_desc desc;
5253 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5254 iface, src_surface, wine_dbgstr_rect(src_rect),
5255 dst_surface, wine_dbgstr_point(dst_point));
5257 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5259 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5260 src_surface, dst_surface);
5261 return WINED3DERR_INVALIDCALL;
5264 src_format = src_impl->resource.format_desc;
5265 dst_format = dst_impl->resource.format_desc;
5267 if (src_format->format != dst_format->format)
5269 WARN("Source and destination surfaces should have the same format.\n");
5270 return WINED3DERR_INVALIDCALL;
5273 dst_x = dst_point ? dst_point->x : 0;
5274 dst_y = dst_point ? dst_point->y : 0;
5276 /* This call loads the OpenGL surface directly, instead of copying the
5277 * surface to the destination's sysmem copy. If surface conversion is
5278 * needed, use BltFast instead to copy in sysmem and use regular surface
5280 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5281 if (convert != NO_CONVERSION || desc.convert)
5282 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5284 context = context_acquire(This, NULL);
5285 gl_info = context->gl_info;
5288 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5289 checkGLcall("glActiveTextureARB");
5292 /* Make sure the surface is loaded and up to date */
5293 surface_internal_preload(dst_impl, SRGB_RGB);
5294 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5296 src_w = src_impl->currentDesc.Width;
5297 src_h = src_impl->currentDesc.Height;
5298 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5299 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5301 data = IWineD3DSurface_GetData(src_surface);
5302 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5306 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5308 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5309 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5310 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5314 data += (src_rect->top / src_format->block_height) * src_pitch;
5315 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5318 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5319 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5320 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5322 if (row_length == src_pitch)
5324 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5325 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5331 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5332 * can't use the unpack row length like below. */
5333 for (row = 0, y = dst_y; row < row_count; ++row)
5335 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5336 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5337 y += src_format->block_height;
5341 checkGLcall("glCompressedTexSubImage2DARB");
5347 data += src_rect->top * src_w * src_format->byte_count;
5348 data += src_rect->left * src_format->byte_count;
5351 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5352 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5353 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5355 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5356 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5357 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5358 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5359 checkGLcall("glTexSubImage2D");
5363 context_release(context);
5365 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5366 sampler = This->rev_tex_unit_map[0];
5367 if (sampler != WINED3D_UNMAPPED_STAGE)
5369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5375 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5377 struct WineD3DRectPatch *patch;
5378 GLenum old_primitive_type;
5382 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5384 if(!(Handle || pRectPatchInfo)) {
5385 /* TODO: Write a test for the return value, thus the FIXME */
5386 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5387 return WINED3DERR_INVALIDCALL;
5391 i = PATCHMAP_HASHFUNC(Handle);
5393 LIST_FOR_EACH(e, &This->patches[i]) {
5394 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5395 if(patch->Handle == Handle) {
5402 TRACE("Patch does not exist. Creating a new one\n");
5403 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5404 patch->Handle = Handle;
5405 list_add_head(&This->patches[i], &patch->entry);
5407 TRACE("Found existing patch %p\n", patch);
5410 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5411 * attributes we have to tesselate, read back, and draw. This needs a patch
5412 * management structure instance. Create one.
5414 * A possible improvement is to check if a vertex shader is used, and if not directly
5417 FIXME("Drawing an uncached patch. This is slow\n");
5418 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5421 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5422 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5423 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5425 TRACE("Tesselation density or patch info changed, retesselating\n");
5427 if(pRectPatchInfo) {
5428 patch->RectPatchInfo = *pRectPatchInfo;
5430 patch->numSegs[0] = pNumSegs[0];
5431 patch->numSegs[1] = pNumSegs[1];
5432 patch->numSegs[2] = pNumSegs[2];
5433 patch->numSegs[3] = pNumSegs[3];
5435 hr = tesselate_rectpatch(This, patch);
5437 WARN("Patch tesselation failed\n");
5439 /* Do not release the handle to store the params of the patch */
5441 HeapFree(GetProcessHeap(), 0, patch);
5447 This->currentPatch = patch;
5448 old_primitive_type = This->stateBlock->gl_primitive_type;
5449 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5450 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5451 This->stateBlock->gl_primitive_type = old_primitive_type;
5452 This->currentPatch = NULL;
5454 /* Destroy uncached patches */
5456 HeapFree(GetProcessHeap(), 0, patch->mem);
5457 HeapFree(GetProcessHeap(), 0, patch);
5462 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5463 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5465 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5466 iface, handle, segment_count, patch_info);
5471 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 struct WineD3DRectPatch *patch;
5476 TRACE("(%p) Handle(%d)\n", This, Handle);
5478 i = PATCHMAP_HASHFUNC(Handle);
5479 LIST_FOR_EACH(e, &This->patches[i]) {
5480 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5481 if(patch->Handle == Handle) {
5482 TRACE("Deleting patch %p\n", patch);
5483 list_remove(&patch->entry);
5484 HeapFree(GetProcessHeap(), 0, patch->mem);
5485 HeapFree(GetProcessHeap(), 0, patch);
5490 /* TODO: Write a test for the return value */
5491 FIXME("Attempt to destroy nonexistent patch\n");
5492 return WINED3DERR_INVALIDCALL;
5495 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5496 IWineD3DSurface *surface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5498 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5501 TRACE("iface %p, surface %p, rect %s, color 0x%08x.\n",
5502 iface, surface, wine_dbgstr_rect((const RECT *)pRect), color);
5504 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5506 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5507 return WINED3DERR_INVALIDCALL;
5510 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5512 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5514 return device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &s,
5515 !!pRect, pRect, WINED3DCLEAR_TARGET, &c, 0.0f, 0);
5519 /* Just forward this to the DirectDraw blitting engine */
5520 memset(&BltFx, 0, sizeof(BltFx));
5521 BltFx.dwSize = sizeof(BltFx);
5522 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, s->resource.format_desc->format);
5523 return IWineD3DSurface_Blt(surface, (const RECT *)pRect, NULL, NULL,
5524 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5528 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5529 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5531 IWineD3DResource *resource;
5532 IWineD3DSurfaceImpl *surface;
5535 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5538 ERR("Failed to get resource, hr %#x\n", hr);
5542 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5544 FIXME("Only supported on surface resources\n");
5545 IWineD3DResource_Release(resource);
5549 surface = (IWineD3DSurfaceImpl *)resource;
5551 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5553 device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &surface,
5554 0, NULL, WINED3DCLEAR_TARGET, color, 0.0f, 0);
5561 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5563 c = ((DWORD)(color->b * 255.0f));
5564 c |= ((DWORD)(color->g * 255.0f)) << 8;
5565 c |= ((DWORD)(color->r * 255.0f)) << 16;
5566 c |= ((DWORD)(color->a * 255.0f)) << 24;
5568 /* Just forward this to the DirectDraw blitting engine */
5569 memset(&BltFx, 0, sizeof(BltFx));
5570 BltFx.dwSize = sizeof(BltFx);
5571 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5572 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5573 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5576 ERR("Blt failed, hr %#x\n", hr);
5580 IWineD3DResource_Release(resource);
5583 /* rendertarget and depth stencil functions */
5584 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5585 DWORD render_target_idx, IWineD3DSurface **render_target)
5587 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5589 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5590 iface, render_target_idx, render_target);
5592 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5594 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5595 return WINED3DERR_INVALIDCALL;
5598 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5599 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5601 TRACE("Returning render target %p.\n", *render_target);
5606 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5607 IWineD3DSurface *front, IWineD3DSurface *back)
5609 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5610 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5611 IWineD3DSwapChainImpl *swapchain;
5614 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5616 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5618 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5622 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5624 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5625 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5626 return WINED3DERR_INVALIDCALL;
5631 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5633 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5634 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5635 return WINED3DERR_INVALIDCALL;
5638 if (!swapchain->back_buffers)
5640 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5641 if (!swapchain->back_buffers)
5643 ERR("Failed to allocate back buffer array memory.\n");
5644 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5645 return E_OUTOFMEMORY;
5650 if (swapchain->front_buffer != front_impl)
5652 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5654 if (swapchain->front_buffer)
5655 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5656 swapchain->front_buffer = front_impl;
5659 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5662 if (swapchain->back_buffers[0] != back_impl)
5664 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5666 if (swapchain->back_buffers[0])
5667 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_TEXTURE, NULL);
5668 swapchain->back_buffers[0] = back_impl;
5672 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5673 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5674 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5675 swapchain->presentParms.BackBufferCount = 1;
5677 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5681 swapchain->presentParms.BackBufferCount = 0;
5682 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5683 swapchain->back_buffers = NULL;
5687 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5691 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5693 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5695 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5697 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5698 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5699 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5700 IWineD3DSurface_AddRef(*depth_stencil);
5705 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5706 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5708 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5709 IWineD3DSurfaceImpl *prev;
5711 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5712 iface, render_target_idx, render_target, set_viewport);
5714 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5716 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5717 return WINED3DERR_INVALIDCALL;
5720 prev = device->render_targets[render_target_idx];
5721 if (render_target == (IWineD3DSurface *)prev)
5723 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5727 /* Render target 0 can't be set to NULL. */
5728 if (!render_target && !render_target_idx)
5730 WARN("Trying to set render target 0 to NULL.\n");
5731 return WINED3DERR_INVALIDCALL;
5734 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5736 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5737 return WINED3DERR_INVALIDCALL;
5740 if (render_target) IWineD3DSurface_AddRef(render_target);
5741 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5742 /* Release after the assignment, to prevent device_resource_released()
5743 * from seeing the surface as still in use. */
5744 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5746 /* Render target 0 is special. */
5747 if (!render_target_idx && set_viewport)
5749 /* Set the viewport and scissor rectangles, if requested. Tests show
5750 * that stateblock recording is ignored, the change goes directly
5751 * into the primary stateblock. */
5752 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5753 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5754 device->stateBlock->viewport.X = 0;
5755 device->stateBlock->viewport.Y = 0;
5756 device->stateBlock->viewport.MaxZ = 1.0f;
5757 device->stateBlock->viewport.MinZ = 0.0f;
5758 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5760 device->stateBlock->scissorRect.top = 0;
5761 device->stateBlock->scissorRect.left = 0;
5762 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5763 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5764 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5770 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5773 IWineD3DSurfaceImpl *tmp;
5775 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5777 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5779 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5783 if (This->depth_stencil)
5785 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5786 || This->depth_stencil->Flags & SFLAG_DISCARD)
5788 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5789 This->depth_stencil->currentDesc.Width,
5790 This->depth_stencil->currentDesc.Height);
5791 if (This->depth_stencil == This->onscreen_depth_stencil)
5793 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5794 This->onscreen_depth_stencil = NULL;
5799 tmp = This->depth_stencil;
5800 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5801 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5802 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5804 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5806 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5815 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5816 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5819 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5820 WINED3DLOCKED_RECT lockedRect;
5822 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5823 iface, XHotSpot, YHotSpot, cursor_image);
5825 /* some basic validation checks */
5826 if (This->cursorTexture)
5828 struct wined3d_context *context = context_acquire(This, NULL);
5830 glDeleteTextures(1, &This->cursorTexture);
5832 context_release(context);
5833 This->cursorTexture = 0;
5836 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5837 This->haveHardwareCursor = TRUE;
5839 This->haveHardwareCursor = FALSE;
5843 WINED3DLOCKED_RECT rect;
5845 /* MSDN: Cursor must be A8R8G8B8 */
5846 if (s->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5848 WARN("surface %p has an invalid format.\n", cursor_image);
5849 return WINED3DERR_INVALIDCALL;
5852 /* MSDN: Cursor must be smaller than the display mode */
5853 if (s->currentDesc.Width > This->ddraw_width
5854 || s->currentDesc.Height > This->ddraw_height)
5856 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5857 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5858 return WINED3DERR_INVALIDCALL;
5861 if (!This->haveHardwareCursor) {
5862 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5864 /* Do not store the surface's pointer because the application may
5865 * release it after setting the cursor image. Windows doesn't
5866 * addref the set surface, so we can't do this either without
5867 * creating circular refcount dependencies. Copy out the gl texture
5870 This->cursorWidth = s->currentDesc.Width;
5871 This->cursorHeight = s->currentDesc.Height;
5872 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5874 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5875 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5876 struct wined3d_context *context;
5877 char *mem, *bits = rect.pBits;
5878 GLint intfmt = format_desc->glInternal;
5879 GLint format = format_desc->glFormat;
5880 GLint type = format_desc->glType;
5881 INT height = This->cursorHeight;
5882 INT width = This->cursorWidth;
5883 INT bpp = format_desc->byte_count;
5887 /* Reformat the texture memory (pitch and width can be
5889 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5890 for(i = 0; i < height; i++)
5891 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5892 IWineD3DSurface_UnlockRect(cursor_image);
5894 context = context_acquire(This, NULL);
5898 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5900 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5901 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5904 /* Make sure that a proper texture unit is selected */
5905 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5906 checkGLcall("glActiveTextureARB");
5907 sampler = This->rev_tex_unit_map[0];
5908 if (sampler != WINED3D_UNMAPPED_STAGE)
5910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5912 /* Create a new cursor texture */
5913 glGenTextures(1, &This->cursorTexture);
5914 checkGLcall("glGenTextures");
5915 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5916 checkGLcall("glBindTexture");
5917 /* Copy the bitmap memory into the cursor texture */
5918 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5919 HeapFree(GetProcessHeap(), 0, mem);
5920 checkGLcall("glTexImage2D");
5922 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5924 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5925 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5930 context_release(context);
5934 FIXME("A cursor texture was not returned.\n");
5935 This->cursorTexture = 0;
5940 /* Draw a hardware cursor */
5941 ICONINFO cursorInfo;
5943 /* Create and clear maskBits because it is not needed for
5944 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5946 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5947 (s->currentDesc.Width * s->currentDesc.Height / 8));
5948 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5949 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5950 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5952 cursorInfo.fIcon = FALSE;
5953 cursorInfo.xHotspot = XHotSpot;
5954 cursorInfo.yHotspot = YHotSpot;
5955 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5956 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5957 IWineD3DSurface_UnlockRect(cursor_image);
5958 /* Create our cursor and clean up. */
5959 cursor = CreateIconIndirect(&cursorInfo);
5961 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5962 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5963 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5964 This->hardwareCursor = cursor;
5965 HeapFree(GetProcessHeap(), 0, maskBits);
5969 This->xHotSpot = XHotSpot;
5970 This->yHotSpot = YHotSpot;
5974 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5976 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5978 This->xScreenSpace = XScreenSpace;
5979 This->yScreenSpace = YScreenSpace;
5985 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5987 BOOL oldVisible = This->bCursorVisible;
5990 TRACE("(%p) : visible(%d)\n", This, bShow);
5993 * When ShowCursor is first called it should make the cursor appear at the OS's last
5994 * known cursor position. Because of this, some applications just repetitively call
5995 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5998 This->xScreenSpace = pt.x;
5999 This->yScreenSpace = pt.y;
6001 if (This->haveHardwareCursor) {
6002 This->bCursorVisible = bShow;
6004 SetCursor(This->hardwareCursor);
6010 if (This->cursorTexture)
6011 This->bCursorVisible = bShow;
6017 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6018 TRACE("checking resource %p for eviction\n", resource);
6019 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6020 TRACE("Evicting %p\n", resource);
6021 IWineD3DResource_UnLoad(resource);
6023 IWineD3DResource_Release(resource);
6027 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6029 TRACE("iface %p.\n", iface);
6031 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6032 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6033 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6038 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6040 IWineD3DDeviceImpl *device = surface->resource.device;
6041 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6043 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6044 if(surface->Flags & SFLAG_DIBSECTION) {
6045 /* Release the DC */
6046 SelectObject(surface->hDC, surface->dib.holdbitmap);
6047 DeleteDC(surface->hDC);
6048 /* Release the DIB section */
6049 DeleteObject(surface->dib.DIBsection);
6050 surface->dib.bitmap_data = NULL;
6051 surface->resource.allocatedMemory = NULL;
6052 surface->Flags &= ~SFLAG_DIBSECTION;
6054 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6055 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6056 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6057 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6059 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6060 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6062 surface->pow2Width = surface->pow2Height = 1;
6063 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6064 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6067 if (surface->texture_name)
6069 struct wined3d_context *context = context_acquire(device, NULL);
6071 glDeleteTextures(1, &surface->texture_name);
6073 context_release(context);
6074 surface->texture_name = 0;
6075 surface->Flags &= ~SFLAG_CLIENT;
6077 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6078 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6079 surface->Flags |= SFLAG_NONPOW2;
6081 surface->Flags &= ~SFLAG_NONPOW2;
6083 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6084 surface->resource.allocatedMemory = NULL;
6085 surface->resource.heapMemory = NULL;
6086 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6088 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6090 if (!surface_init_sysmem(surface))
6092 return E_OUTOFMEMORY;
6097 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6098 TRACE("Unloading resource %p\n", resource);
6099 IWineD3DResource_UnLoad(resource);
6100 IWineD3DResource_Release(resource);
6104 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6107 WINED3DDISPLAYMODE m;
6110 /* All Windowed modes are supported, as is leaving the current mode */
6111 if(pp->Windowed) return TRUE;
6112 if(!pp->BackBufferWidth) return TRUE;
6113 if(!pp->BackBufferHeight) return TRUE;
6115 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6116 for(i = 0; i < count; i++) {
6117 memset(&m, 0, sizeof(m));
6118 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6120 ERR("EnumAdapterModes failed\n");
6122 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6123 /* Mode found, it is supported */
6127 /* Mode not found -> not supported */
6131 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6134 const struct wined3d_gl_info *gl_info;
6135 struct wined3d_context *context;
6136 IWineD3DBaseShaderImpl *shader;
6138 context = context_acquire(This, NULL);
6139 gl_info = context->gl_info;
6141 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6142 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6143 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6147 if(This->depth_blt_texture) {
6148 glDeleteTextures(1, &This->depth_blt_texture);
6149 This->depth_blt_texture = 0;
6151 if (This->depth_blt_rb) {
6152 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6153 This->depth_blt_rb = 0;
6154 This->depth_blt_rb_w = 0;
6155 This->depth_blt_rb_h = 0;
6159 This->blitter->free_private(iface);
6160 This->frag_pipe->free_private(iface);
6161 This->shader_backend->shader_free_private(iface);
6162 destroy_dummy_textures(This, gl_info);
6164 context_release(context);
6166 while (This->numContexts)
6168 context_destroy(This, This->contexts[0]);
6170 HeapFree(GetProcessHeap(), 0, swapchain->context);
6171 swapchain->context = NULL;
6172 swapchain->num_contexts = 0;
6175 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6178 struct wined3d_context *context;
6180 IWineD3DSurfaceImpl *target;
6182 /* Recreate the primary swapchain's context */
6183 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6184 if (!swapchain->context)
6186 ERR("Failed to allocate memory for swapchain context array.\n");
6187 return E_OUTOFMEMORY;
6190 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6191 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6193 WARN("Failed to create context.\n");
6194 HeapFree(GetProcessHeap(), 0, swapchain->context);
6198 swapchain->context[0] = context;
6199 swapchain->num_contexts = 1;
6200 create_dummy_textures(This);
6201 context_release(context);
6203 hr = This->shader_backend->shader_alloc_private(iface);
6206 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6210 hr = This->frag_pipe->alloc_private(iface);
6213 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6214 This->shader_backend->shader_free_private(iface);
6218 hr = This->blitter->alloc_private(iface);
6221 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6222 This->frag_pipe->free_private(iface);
6223 This->shader_backend->shader_free_private(iface);
6230 context_acquire(This, NULL);
6231 destroy_dummy_textures(This, context->gl_info);
6232 context_release(context);
6233 context_destroy(This, context);
6234 HeapFree(GetProcessHeap(), 0, swapchain->context);
6235 swapchain->num_contexts = 0;
6239 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6241 IWineD3DSwapChainImpl *swapchain;
6243 BOOL DisplayModeChanged = FALSE;
6244 WINED3DDISPLAYMODE mode;
6245 TRACE("(%p)\n", This);
6247 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6249 ERR("Failed to get the first implicit swapchain\n");
6253 if(!is_display_mode_supported(This, pPresentationParameters)) {
6254 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6255 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6256 pPresentationParameters->BackBufferHeight);
6257 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6258 return WINED3DERR_INVALIDCALL;
6261 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6262 * on an existing gl context, so there's no real need for recreation.
6264 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6266 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6268 TRACE("New params:\n");
6269 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6270 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6271 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6272 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6273 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6274 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6275 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6276 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6277 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6278 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6279 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6280 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6281 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6283 /* No special treatment of these parameters. Just store them */
6284 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6285 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6286 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6287 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6289 /* What to do about these? */
6290 if(pPresentationParameters->BackBufferCount != 0 &&
6291 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6292 ERR("Cannot change the back buffer count yet\n");
6294 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6295 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6296 ERR("Cannot change the back buffer format yet\n");
6298 if(pPresentationParameters->hDeviceWindow != NULL &&
6299 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6300 ERR("Cannot change the device window yet\n");
6302 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6306 TRACE("Creating the depth stencil buffer\n");
6308 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6310 pPresentationParameters->BackBufferWidth,
6311 pPresentationParameters->BackBufferHeight,
6312 pPresentationParameters->AutoDepthStencilFormat,
6313 pPresentationParameters->MultiSampleType,
6314 pPresentationParameters->MultiSampleQuality,
6316 (IWineD3DSurface **)&This->auto_depth_stencil);
6319 ERR("Failed to create the depth stencil buffer\n");
6320 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6321 return WINED3DERR_INVALIDCALL;
6325 if (This->onscreen_depth_stencil)
6327 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6328 This->onscreen_depth_stencil = NULL;
6331 /* Reset the depth stencil */
6332 if (pPresentationParameters->EnableAutoDepthStencil)
6333 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6335 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6337 TRACE("Resetting stateblock\n");
6338 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6339 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6341 delete_opengl_contexts(iface, swapchain);
6343 if(pPresentationParameters->Windowed) {
6344 mode.Width = swapchain->orig_width;
6345 mode.Height = swapchain->orig_height;
6346 mode.RefreshRate = 0;
6347 mode.Format = swapchain->presentParms.BackBufferFormat;
6349 mode.Width = pPresentationParameters->BackBufferWidth;
6350 mode.Height = pPresentationParameters->BackBufferHeight;
6351 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6352 mode.Format = swapchain->presentParms.BackBufferFormat;
6355 /* Should Width == 800 && Height == 0 set 800x600? */
6356 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6357 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6358 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6362 if(!pPresentationParameters->Windowed) {
6363 DisplayModeChanged = TRUE;
6365 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6366 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6368 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6371 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6375 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6377 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6380 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6384 if (This->auto_depth_stencil)
6386 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6389 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6395 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6396 || DisplayModeChanged)
6398 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6400 if (!pPresentationParameters->Windowed)
6402 if(swapchain->presentParms.Windowed) {
6403 /* switch from windowed to fs */
6404 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6405 pPresentationParameters->BackBufferHeight);
6407 /* Fullscreen -> fullscreen mode change */
6408 MoveWindow(swapchain->device_window, 0, 0,
6409 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6413 else if (!swapchain->presentParms.Windowed)
6415 /* Fullscreen -> windowed switch */
6416 swapchain_restore_fullscreen_window(swapchain);
6418 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6419 } else if(!pPresentationParameters->Windowed) {
6420 DWORD style = This->style, exStyle = This->exStyle;
6421 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6422 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6423 * Reset to clear up their mess. Guild Wars also loses the device during that.
6427 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6428 pPresentationParameters->BackBufferHeight);
6429 This->style = style;
6430 This->exStyle = exStyle;
6433 /* Note: No parent needed for initial internal stateblock */
6434 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6435 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6436 else TRACE("Created stateblock %p\n", This->stateBlock);
6437 This->updateStateBlock = This->stateBlock;
6438 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6440 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6442 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6445 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6448 GetClientRect(swapchain->win_handle, &client_rect);
6450 if(!swapchain->presentParms.BackBufferCount)
6452 TRACE("Single buffered rendering\n");
6453 swapchain->render_to_fbo = FALSE;
6455 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6456 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6458 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6459 swapchain->presentParms.BackBufferWidth,
6460 swapchain->presentParms.BackBufferHeight,
6461 client_rect.right, client_rect.bottom);
6462 swapchain->render_to_fbo = TRUE;
6466 TRACE("Rendering directly to GL_BACK\n");
6467 swapchain->render_to_fbo = FALSE;
6471 hr = create_primary_opengl_context(iface, swapchain);
6472 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6474 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6480 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6482 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6484 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6490 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6492 TRACE("(%p) : pParameters %p\n", This, pParameters);
6494 *pParameters = This->createParms;
6498 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6499 IWineD3DSwapChain *swapchain;
6501 TRACE("Relaying to swapchain\n");
6503 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6504 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6505 IWineD3DSwapChain_Release(swapchain);
6509 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6510 IWineD3DSwapChain *swapchain;
6512 TRACE("Relaying to swapchain\n");
6514 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6515 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6516 IWineD3DSwapChain_Release(swapchain);
6521 /** ********************************************************
6522 * Notification functions
6523 ** ********************************************************/
6524 /** This function must be called in the release of a resource when ref == 0,
6525 * the contents of resource must still be correct,
6526 * any handles to other resource held by the caller must be closed
6527 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6528 *****************************************************/
6529 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6531 TRACE("(%p) : Adding resource %p\n", This, resource);
6533 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6536 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6538 TRACE("(%p) : Removing resource %p\n", This, resource);
6540 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6543 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6545 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6548 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6550 context_resource_released(device, resource, type);
6554 case WINED3DRTYPE_SURFACE:
6555 if (!device->d3d_initialized) break;
6557 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6559 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6561 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6562 device->render_targets[i] = NULL;
6566 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6568 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6569 device->depth_stencil = NULL;
6573 case WINED3DRTYPE_TEXTURE:
6574 case WINED3DRTYPE_CUBETEXTURE:
6575 case WINED3DRTYPE_VOLUMETEXTURE:
6576 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6578 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6580 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6581 resource, device->stateBlock, i);
6582 device->stateBlock->textures[i] = NULL;
6585 if (device->updateStateBlock != device->stateBlock
6586 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6588 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6589 resource, device->updateStateBlock, i);
6590 device->updateStateBlock->textures[i] = NULL;
6595 case WINED3DRTYPE_BUFFER:
6596 for (i = 0; i < MAX_STREAMS; ++i)
6598 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6600 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6601 resource, device->stateBlock, i);
6602 device->stateBlock->streamSource[i] = NULL;
6605 if (device->updateStateBlock != device->stateBlock
6606 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6608 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6609 resource, device->updateStateBlock, i);
6610 device->updateStateBlock->streamSource[i] = NULL;
6615 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6617 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6618 resource, device->stateBlock);
6619 device->stateBlock->pIndexData = NULL;
6622 if (device->updateStateBlock != device->stateBlock
6623 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6625 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6626 resource, device->updateStateBlock);
6627 device->updateStateBlock->pIndexData = NULL;
6635 /* Remove the resource from the resourceStore */
6636 device_resource_remove(device, resource);
6638 TRACE("Resource released.\n");
6641 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6643 IWineD3DResourceImpl *resource, *cursor;
6645 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6647 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6648 TRACE("enumerating resource %p\n", resource);
6649 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6650 ret = pCallback((IWineD3DResource *) resource, pData);
6651 if(ret == S_FALSE) {
6652 TRACE("Canceling enumeration\n");
6659 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6662 IWineD3DResourceImpl *resource;
6664 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6666 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6667 if (type == WINED3DRTYPE_SURFACE)
6669 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6671 TRACE("Found surface %p for dc %p.\n", resource, dc);
6672 *surface = (IWineD3DSurface *)resource;
6678 return WINED3DERR_INVALIDCALL;
6681 /**********************************************************
6682 * IWineD3DDevice VTbl follows
6683 **********************************************************/
6685 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6687 /*** IUnknown methods ***/
6688 IWineD3DDeviceImpl_QueryInterface,
6689 IWineD3DDeviceImpl_AddRef,
6690 IWineD3DDeviceImpl_Release,
6691 /*** IWineD3DDevice methods ***/
6692 IWineD3DDeviceImpl_GetParent,
6693 /*** Creation methods**/
6694 IWineD3DDeviceImpl_CreateBuffer,
6695 IWineD3DDeviceImpl_CreateVertexBuffer,
6696 IWineD3DDeviceImpl_CreateIndexBuffer,
6697 IWineD3DDeviceImpl_CreateStateBlock,
6698 IWineD3DDeviceImpl_CreateSurface,
6699 IWineD3DDeviceImpl_CreateRendertargetView,
6700 IWineD3DDeviceImpl_CreateTexture,
6701 IWineD3DDeviceImpl_CreateVolumeTexture,
6702 IWineD3DDeviceImpl_CreateVolume,
6703 IWineD3DDeviceImpl_CreateCubeTexture,
6704 IWineD3DDeviceImpl_CreateQuery,
6705 IWineD3DDeviceImpl_CreateSwapChain,
6706 IWineD3DDeviceImpl_CreateVertexDeclaration,
6707 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6708 IWineD3DDeviceImpl_CreateVertexShader,
6709 IWineD3DDeviceImpl_CreateGeometryShader,
6710 IWineD3DDeviceImpl_CreatePixelShader,
6711 IWineD3DDeviceImpl_CreatePalette,
6712 /*** Odd functions **/
6713 IWineD3DDeviceImpl_Init3D,
6714 IWineD3DDeviceImpl_InitGDI,
6715 IWineD3DDeviceImpl_Uninit3D,
6716 IWineD3DDeviceImpl_UninitGDI,
6717 IWineD3DDeviceImpl_SetMultithreaded,
6718 IWineD3DDeviceImpl_EvictManagedResources,
6719 IWineD3DDeviceImpl_GetAvailableTextureMem,
6720 IWineD3DDeviceImpl_GetBackBuffer,
6721 IWineD3DDeviceImpl_GetCreationParameters,
6722 IWineD3DDeviceImpl_GetDeviceCaps,
6723 IWineD3DDeviceImpl_GetDirect3D,
6724 IWineD3DDeviceImpl_GetDisplayMode,
6725 IWineD3DDeviceImpl_SetDisplayMode,
6726 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6727 IWineD3DDeviceImpl_GetRasterStatus,
6728 IWineD3DDeviceImpl_GetSwapChain,
6729 IWineD3DDeviceImpl_Reset,
6730 IWineD3DDeviceImpl_SetDialogBoxMode,
6731 IWineD3DDeviceImpl_SetCursorProperties,
6732 IWineD3DDeviceImpl_SetCursorPosition,
6733 IWineD3DDeviceImpl_ShowCursor,
6734 /*** Getters and setters **/
6735 IWineD3DDeviceImpl_SetClipPlane,
6736 IWineD3DDeviceImpl_GetClipPlane,
6737 IWineD3DDeviceImpl_SetClipStatus,
6738 IWineD3DDeviceImpl_GetClipStatus,
6739 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6740 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6741 IWineD3DDeviceImpl_SetDepthStencilSurface,
6742 IWineD3DDeviceImpl_GetDepthStencilSurface,
6743 IWineD3DDeviceImpl_SetGammaRamp,
6744 IWineD3DDeviceImpl_GetGammaRamp,
6745 IWineD3DDeviceImpl_SetIndexBuffer,
6746 IWineD3DDeviceImpl_GetIndexBuffer,
6747 IWineD3DDeviceImpl_SetBaseVertexIndex,
6748 IWineD3DDeviceImpl_GetBaseVertexIndex,
6749 IWineD3DDeviceImpl_SetLight,
6750 IWineD3DDeviceImpl_GetLight,
6751 IWineD3DDeviceImpl_SetLightEnable,
6752 IWineD3DDeviceImpl_GetLightEnable,
6753 IWineD3DDeviceImpl_SetMaterial,
6754 IWineD3DDeviceImpl_GetMaterial,
6755 IWineD3DDeviceImpl_SetNPatchMode,
6756 IWineD3DDeviceImpl_GetNPatchMode,
6757 IWineD3DDeviceImpl_SetPaletteEntries,
6758 IWineD3DDeviceImpl_GetPaletteEntries,
6759 IWineD3DDeviceImpl_SetPixelShader,
6760 IWineD3DDeviceImpl_GetPixelShader,
6761 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6762 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6763 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6764 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6765 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6766 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6767 IWineD3DDeviceImpl_SetRenderState,
6768 IWineD3DDeviceImpl_GetRenderState,
6769 IWineD3DDeviceImpl_SetRenderTarget,
6770 IWineD3DDeviceImpl_GetRenderTarget,
6771 IWineD3DDeviceImpl_SetFrontBackBuffers,
6772 IWineD3DDeviceImpl_SetSamplerState,
6773 IWineD3DDeviceImpl_GetSamplerState,
6774 IWineD3DDeviceImpl_SetScissorRect,
6775 IWineD3DDeviceImpl_GetScissorRect,
6776 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6777 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6778 IWineD3DDeviceImpl_SetStreamSource,
6779 IWineD3DDeviceImpl_GetStreamSource,
6780 IWineD3DDeviceImpl_SetStreamSourceFreq,
6781 IWineD3DDeviceImpl_GetStreamSourceFreq,
6782 IWineD3DDeviceImpl_SetTexture,
6783 IWineD3DDeviceImpl_GetTexture,
6784 IWineD3DDeviceImpl_SetTextureStageState,
6785 IWineD3DDeviceImpl_GetTextureStageState,
6786 IWineD3DDeviceImpl_SetTransform,
6787 IWineD3DDeviceImpl_GetTransform,
6788 IWineD3DDeviceImpl_SetVertexDeclaration,
6789 IWineD3DDeviceImpl_GetVertexDeclaration,
6790 IWineD3DDeviceImpl_SetVertexShader,
6791 IWineD3DDeviceImpl_GetVertexShader,
6792 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6793 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6794 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6795 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6796 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6797 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6798 IWineD3DDeviceImpl_SetViewport,
6799 IWineD3DDeviceImpl_GetViewport,
6800 IWineD3DDeviceImpl_MultiplyTransform,
6801 IWineD3DDeviceImpl_ValidateDevice,
6802 IWineD3DDeviceImpl_ProcessVertices,
6803 /*** State block ***/
6804 IWineD3DDeviceImpl_BeginStateBlock,
6805 IWineD3DDeviceImpl_EndStateBlock,
6806 /*** Scene management ***/
6807 IWineD3DDeviceImpl_BeginScene,
6808 IWineD3DDeviceImpl_EndScene,
6809 IWineD3DDeviceImpl_Present,
6810 IWineD3DDeviceImpl_Clear,
6811 IWineD3DDeviceImpl_ClearRendertargetView,
6813 IWineD3DDeviceImpl_SetPrimitiveType,
6814 IWineD3DDeviceImpl_GetPrimitiveType,
6815 IWineD3DDeviceImpl_DrawPrimitive,
6816 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6817 IWineD3DDeviceImpl_DrawPrimitiveUP,
6818 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6819 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6820 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6821 IWineD3DDeviceImpl_DrawRectPatch,
6822 IWineD3DDeviceImpl_DrawTriPatch,
6823 IWineD3DDeviceImpl_DeletePatch,
6824 IWineD3DDeviceImpl_ColorFill,
6825 IWineD3DDeviceImpl_UpdateTexture,
6826 IWineD3DDeviceImpl_UpdateSurface,
6827 IWineD3DDeviceImpl_GetFrontBufferData,
6828 /*** object tracking ***/
6829 IWineD3DDeviceImpl_EnumResources,
6830 IWineD3DDeviceImpl_GetSurfaceFromDC,
6831 IWineD3DDeviceImpl_AcquireFocusWindow,
6832 IWineD3DDeviceImpl_ReleaseFocusWindow,
6835 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6836 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6837 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6839 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6840 const struct fragment_pipeline *fragment_pipeline;
6841 struct shader_caps shader_caps;
6842 struct fragment_caps ffp_caps;
6843 WINED3DDISPLAYMODE mode;
6847 device->lpVtbl = &IWineD3DDevice_Vtbl;
6849 device->wined3d = (IWineD3D *)wined3d;
6850 IWineD3D_AddRef(device->wined3d);
6851 device->adapter = wined3d->adapter_count ? adapter : NULL;
6852 device->parent = parent;
6853 device->device_parent = device_parent;
6854 list_init(&device->resources);
6855 list_init(&device->shaders);
6857 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6858 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6860 /* Get the initial screen setup for ddraw. */
6861 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6864 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6865 IWineD3D_Release(device->wined3d);
6868 device->ddraw_width = mode.Width;
6869 device->ddraw_height = mode.Height;
6870 device->ddraw_format = mode.Format;
6872 /* Save the creation parameters. */
6873 device->createParms.AdapterOrdinal = adapter_idx;
6874 device->createParms.DeviceType = device_type;
6875 device->createParms.hFocusWindow = focus_window;
6876 device->createParms.BehaviorFlags = flags;
6878 device->devType = device_type;
6879 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6881 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6882 device->shader_backend = adapter->shader_backend;
6884 if (device->shader_backend)
6886 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6887 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6888 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6889 device->vs_clipping = shader_caps.VSClipping;
6891 fragment_pipeline = adapter->fragment_pipe;
6892 device->frag_pipe = fragment_pipeline;
6893 if (fragment_pipeline)
6895 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6896 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6898 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6899 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6902 ERR("Failed to compile state table, hr %#x.\n", hr);
6903 IWineD3D_Release(device->wined3d);
6907 device->blitter = adapter->blitter;
6913 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6914 DWORD rep = This->StateTable[state].representative;
6915 struct wined3d_context *context;
6920 for(i = 0; i < This->numContexts; i++) {
6921 context = This->contexts[i];
6922 if(isStateDirty(context, rep)) continue;
6924 context->dirtyArray[context->numDirtyEntries++] = rep;
6925 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6926 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6927 context->isStateDirty[idx] |= (1 << shift);
6931 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6933 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6934 *width = context->current_rt->pow2Width;
6935 *height = context->current_rt->pow2Height;
6938 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6940 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6941 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6942 * current context's drawable, which is the size of the back buffer of the swapchain
6943 * the active context belongs to. */
6944 *width = swapchain->presentParms.BackBufferWidth;
6945 *height = swapchain->presentParms.BackBufferHeight;
6948 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6949 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6951 if (device->filter_messages)
6953 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6954 window, message, wparam, lparam);
6955 return DefWindowProcW(window, message, wparam, lparam);
6958 if (message == WM_DESTROY)
6960 TRACE("unregister window %p.\n", window);
6961 wined3d_unregister_window(window);
6963 if (device->focus_window == window) device->focus_window = NULL;
6964 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6967 return CallWindowProcW(proc, window, message, wparam, lparam);