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 RECT *rects, const RECT *draw_rect, DWORD flags,
659 const WINED3DCOLORVALUE *color, 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;
669 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
670 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
671 * for the cleared parts, and the untouched parts.
673 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
674 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
675 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
676 * checking all this if the dest surface is in the drawable anyway. */
677 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
679 for (i = 0; i < rt_count; ++i)
681 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
685 context = context_acquire(device, target);
688 context_release(context);
689 WARN("Invalid context, skipping clear.\n");
693 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
695 target->get_drawable_size(context, &drawable_width, &drawable_height);
699 /* Only set the values up once, as they are not changing. */
700 if (flags & WINED3DCLEAR_STENCIL)
702 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
704 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
705 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
708 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
709 glClearStencil(stencil);
710 checkGLcall("glClearStencil");
711 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
714 if (flags & WINED3DCLEAR_ZBUFFER)
716 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
718 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
719 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
823 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
824 if (IsEqualGUID(riid, &IID_IUnknown)
825 || IsEqualGUID(riid, &IID_IWineD3DBase)
826 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
827 IUnknown_AddRef(iface);
832 return E_NOINTERFACE;
835 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
837 ULONG refCount = InterlockedIncrement(&This->ref);
839 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
843 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
845 ULONG refCount = InterlockedDecrement(&This->ref);
847 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
852 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
853 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
854 This->multistate_funcs[i] = NULL;
857 /* TODO: Clean up all the surfaces and textures! */
858 /* NOTE: You must release the parent if the object was created via a callback
859 ** ***************************/
861 if (!list_empty(&This->resources))
863 IWineD3DResourceImpl *resource;
864 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
866 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
868 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
869 FIXME("Leftover resource %p with type %s (%#x).\n",
870 resource, debug_d3dresourcetype(type), type);
874 if(This->contexts) ERR("Context array not freed!\n");
875 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
876 This->haveHardwareCursor = FALSE;
878 IWineD3D_Release(This->wined3d);
879 This->wined3d = NULL;
880 HeapFree(GetProcessHeap(), 0, This);
881 TRACE("Freed device %p\n", This);
887 /**********************************************************
888 * IWineD3DDevice implementation follows
889 **********************************************************/
890 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
892 *pParent = This->parent;
893 IUnknown_AddRef(This->parent);
897 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
898 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 struct wined3d_buffer *object;
904 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
906 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
909 ERR("Failed to allocate memory\n");
910 return E_OUTOFMEMORY;
913 FIXME("Ignoring access flags (pool)\n");
915 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
916 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
919 WARN("Failed to initialize buffer, hr %#x.\n", hr);
920 HeapFree(GetProcessHeap(), 0, object);
923 object->desc = *desc;
925 TRACE("Created buffer %p.\n", object);
927 *buffer = (IWineD3DBuffer *)object;
932 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
933 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
934 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
937 struct wined3d_buffer *object;
940 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
941 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
943 if (Pool == WINED3DPOOL_SCRATCH)
945 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
946 * anyway, SCRATCH vertex buffers aren't usable anywhere
948 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_INVALIDCALL;
953 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
956 ERR("Out of memory\n");
957 *ppVertexBuffer = NULL;
958 return WINED3DERR_OUTOFVIDEOMEMORY;
961 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
962 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
965 WARN("Failed to initialize buffer, hr %#x.\n", hr);
966 HeapFree(GetProcessHeap(), 0, object);
970 TRACE("Created buffer %p.\n", object);
971 *ppVertexBuffer = (IWineD3DBuffer *)object;
976 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
977 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
978 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
981 struct wined3d_buffer *object;
984 TRACE("(%p) Creating index buffer\n", This);
986 /* Allocate the storage for the device */
987 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
990 ERR("Out of memory\n");
991 *ppIndexBuffer = NULL;
992 return WINED3DERR_OUTOFVIDEOMEMORY;
995 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
996 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1000 WARN("Failed to initialize buffer, hr %#x\n", hr);
1001 HeapFree(GetProcessHeap(), 0, object);
1005 TRACE("Created buffer %p.\n", object);
1007 *ppIndexBuffer = (IWineD3DBuffer *) object;
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1013 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1016 IWineD3DStateBlockImpl *object;
1019 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1022 ERR("Failed to allocate stateblock memory.\n");
1023 return E_OUTOFMEMORY;
1026 hr = stateblock_init(object, This, type);
1029 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1030 HeapFree(GetProcessHeap(), 0, object);
1034 TRACE("Created stateblock %p.\n", object);
1035 *stateblock = (IWineD3DStateBlock *)object;
1040 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1041 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **surface,
1042 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
1043 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1046 IWineD3DSurfaceImpl *object;
1049 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1050 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1051 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1052 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1053 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1055 if (Impl == SURFACE_OPENGL && !This->adapter)
1057 ERR("OpenGL surfaces are not available without OpenGL.\n");
1058 return WINED3DERR_NOTAVAILABLE;
1061 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 ERR("Failed to allocate surface memory.\n");
1065 return WINED3DERR_OUTOFVIDEOMEMORY;
1068 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1069 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1072 WARN("Failed to initialize surface, returning %#x.\n", hr);
1073 HeapFree(GetProcessHeap(), 0, object);
1077 TRACE("(%p) : Created surface %p\n", This, object);
1079 *surface = (IWineD3DSurface *)object;
1084 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1085 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1087 struct wined3d_rendertarget_view *object;
1089 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1090 iface, resource, parent, rendertarget_view);
1092 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1095 ERR("Failed to allocate memory\n");
1096 return E_OUTOFMEMORY;
1099 wined3d_rendertarget_view_init(object, resource, parent);
1101 TRACE("Created render target view %p.\n", object);
1102 *rendertarget_view = (IWineD3DRendertargetView *)object;
1107 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1108 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1109 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1112 IWineD3DTextureImpl *object;
1115 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1116 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1117 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1119 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1122 ERR("Out of memory\n");
1124 return WINED3DERR_OUTOFVIDEOMEMORY;
1127 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1130 WARN("Failed to initialize texture, returning %#x\n", hr);
1131 HeapFree(GetProcessHeap(), 0, object);
1136 *ppTexture = (IWineD3DTexture *)object;
1138 TRACE("(%p) : Created texture %p\n", This, object);
1143 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1144 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1145 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1148 IWineD3DVolumeTextureImpl *object;
1151 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1152 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1154 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1157 ERR("Out of memory\n");
1158 *ppVolumeTexture = NULL;
1159 return WINED3DERR_OUTOFVIDEOMEMORY;
1162 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1165 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1166 HeapFree(GetProcessHeap(), 0, object);
1167 *ppVolumeTexture = NULL;
1171 TRACE("(%p) : Created volume texture %p.\n", This, object);
1172 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1177 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1178 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1179 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1182 IWineD3DVolumeImpl *object;
1185 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1186 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1188 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1191 ERR("Out of memory\n");
1193 return WINED3DERR_OUTOFVIDEOMEMORY;
1196 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1199 WARN("Failed to initialize volume, returning %#x.\n", hr);
1200 HeapFree(GetProcessHeap(), 0, object);
1204 TRACE("(%p) : Created volume %p.\n", This, object);
1205 *ppVolume = (IWineD3DVolume *)object;
1210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1211 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1212 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1215 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1218 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1221 ERR("Out of memory\n");
1222 *ppCubeTexture = NULL;
1223 return WINED3DERR_OUTOFVIDEOMEMORY;
1226 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1229 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1230 HeapFree(GetProcessHeap(), 0, object);
1231 *ppCubeTexture = NULL;
1235 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1236 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1241 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1242 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 IWineD3DQueryImpl *object;
1248 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1250 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1253 ERR("Failed to allocate query memory.\n");
1254 return E_OUTOFMEMORY;
1257 hr = query_init(object, This, type, parent);
1260 WARN("Failed to initialize query, hr %#x.\n", hr);
1261 HeapFree(GetProcessHeap(), 0, object);
1265 TRACE("Created query %p.\n", object);
1266 *query = (IWineD3DQuery *)object;
1271 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1272 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1273 IUnknown *parent, WINED3DSURFTYPE surface_type)
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1276 IWineD3DSwapChainImpl *object;
1279 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1280 iface, present_parameters, swapchain, parent, surface_type);
1282 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1285 ERR("Failed to allocate swapchain memory.\n");
1286 return E_OUTOFMEMORY;
1289 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1292 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1293 HeapFree(GetProcessHeap(), 0, object);
1297 TRACE("Created swapchain %p.\n", object);
1298 *swapchain = (IWineD3DSwapChain *)object;
1303 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1304 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p)\n", This);
1308 return This->NumberOfSwapChains;
1311 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1315 if(iSwapChain < This->NumberOfSwapChains) {
1316 *pSwapChain = This->swapchains[iSwapChain];
1317 IWineD3DSwapChain_AddRef(*pSwapChain);
1318 TRACE("(%p) returning %p\n", This, *pSwapChain);
1321 TRACE("Swapchain out of range\n");
1323 return WINED3DERR_INVALIDCALL;
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1328 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1329 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 IWineD3DVertexDeclarationImpl *object = NULL;
1335 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1336 iface, declaration, parent, elements, element_count);
1338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1341 ERR("Failed to allocate vertex declaration memory.\n");
1342 return E_OUTOFMEMORY;
1345 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1348 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1349 HeapFree(GetProcessHeap(), 0, object);
1353 TRACE("Created vertex declaration %p.\n", object);
1354 *declaration = (IWineD3DVertexDeclaration *)object;
1359 struct wined3d_fvf_convert_state
1361 const struct wined3d_gl_info *gl_info;
1362 WINED3DVERTEXELEMENT *elements;
1367 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1368 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1370 WINED3DVERTEXELEMENT *elements = state->elements;
1371 const struct wined3d_format_desc *format_desc;
1372 UINT offset = state->offset;
1373 UINT idx = state->idx;
1375 elements[idx].format = format;
1376 elements[idx].input_slot = 0;
1377 elements[idx].offset = offset;
1378 elements[idx].output_slot = 0;
1379 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1380 elements[idx].usage = usage;
1381 elements[idx].usage_idx = usage_idx;
1383 format_desc = getFormatDescEntry(format, state->gl_info);
1384 state->offset += format_desc->component_count * format_desc->component_size;
1388 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1389 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1391 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1392 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1393 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1394 BOOL has_blend_idx = has_blend &&
1395 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1396 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1397 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1398 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1399 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1400 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1401 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1403 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1404 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1405 struct wined3d_fvf_convert_state state;
1408 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1409 if (has_blend_idx) num_blends--;
1411 /* Compute declaration size */
1412 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1413 has_psize + has_diffuse + has_specular + num_textures;
1415 state.gl_info = gl_info;
1416 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1417 if (!state.elements) return ~0U;
1423 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1424 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1425 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1426 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1428 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1431 if (has_blend && (num_blends > 0))
1433 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1434 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1452 ERR("Unexpected amount of blend values: %u\n", num_blends);
1459 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1460 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1461 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1463 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1468 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1469 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1470 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1471 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1473 for (idx = 0; idx < num_textures; ++idx)
1475 switch ((texcoords >> (idx * 2)) & 0x03)
1477 case WINED3DFVF_TEXTUREFORMAT1:
1478 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1480 case WINED3DFVF_TEXTUREFORMAT2:
1481 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1483 case WINED3DFVF_TEXTUREFORMAT3:
1484 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1486 case WINED3DFVF_TEXTUREFORMAT4:
1487 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1492 *ppVertexElements = state.elements;
1496 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1497 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1498 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1501 WINED3DVERTEXELEMENT *elements;
1505 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1507 size = ConvertFvfToDeclaration(This, fvf, &elements);
1508 if (size == ~0U) return E_OUTOFMEMORY;
1510 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1511 HeapFree(GetProcessHeap(), 0, elements);
1515 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1516 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1517 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1518 const struct wined3d_parent_ops *parent_ops)
1520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1521 IWineD3DVertexShaderImpl *object;
1524 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1527 ERR("Failed to allocate shader memory.\n");
1528 return E_OUTOFMEMORY;
1531 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1534 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1535 HeapFree(GetProcessHeap(), 0, object);
1539 TRACE("Created vertex shader %p.\n", object);
1540 *ppVertexShader = (IWineD3DVertexShader *)object;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1546 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1547 IWineD3DGeometryShader **shader, IUnknown *parent,
1548 const struct wined3d_parent_ops *parent_ops)
1550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1551 struct wined3d_geometryshader *object;
1554 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1557 ERR("Failed to allocate shader memory.\n");
1558 return E_OUTOFMEMORY;
1561 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1564 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1565 HeapFree(GetProcessHeap(), 0, object);
1569 TRACE("Created geometry shader %p.\n", object);
1570 *shader = (IWineD3DGeometryShader *)object;
1575 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1576 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1577 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1578 const struct wined3d_parent_ops *parent_ops)
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 IWineD3DPixelShaderImpl *object;
1584 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1587 ERR("Failed to allocate shader memory.\n");
1588 return E_OUTOFMEMORY;
1591 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1594 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1595 HeapFree(GetProcessHeap(), 0, object);
1599 TRACE("Created pixel shader %p.\n", object);
1600 *ppPixelShader = (IWineD3DPixelShader *)object;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1606 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1609 IWineD3DPaletteImpl *object;
1612 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1613 iface, Flags, PalEnt, Palette, Parent);
1615 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1618 ERR("Failed to allocate palette memory.\n");
1619 return E_OUTOFMEMORY;
1622 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1625 WARN("Failed to initialize palette, hr %#x.\n", hr);
1626 HeapFree(GetProcessHeap(), 0, object);
1630 TRACE("Created palette %p.\n", object);
1631 *Palette = (IWineD3DPalette *)object;
1636 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1640 HDC dcb = NULL, dcs = NULL;
1641 WINEDDCOLORKEY colorkey;
1643 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1646 GetObjectA(hbm, sizeof(BITMAP), &bm);
1647 dcb = CreateCompatibleDC(NULL);
1649 SelectObject(dcb, hbm);
1653 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1654 * couldn't be loaded
1656 memset(&bm, 0, sizeof(bm));
1661 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1662 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1663 NULL, &wined3d_null_parent_ops);
1665 ERR("Wine logo requested, but failed to create surface\n");
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1679 /* Fill the surface with a white color to show that wined3d is there */
1680 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1684 if (dcb) DeleteDC(dcb);
1685 if (hbm) DeleteObject(hbm);
1688 /* Context activation is done by the caller. */
1689 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1691 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1693 /* Under DirectX you can have texture stage operations even if no texture is
1694 bound, whereas opengl will only do texture operations when a valid texture is
1695 bound. We emulate this by creating dummy textures and binding them to each
1696 texture stage, but disable all stages by default. Hence if a stage is enabled
1697 then the default texture will kick in until replaced by a SetTexture call */
1700 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1702 /* The dummy texture does not have client storage backing */
1703 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1704 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1707 for (i = 0; i < gl_info->limits.textures; ++i)
1709 GLubyte white = 255;
1711 /* Make appropriate texture active */
1712 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1713 checkGLcall("glActiveTextureARB");
1715 /* Generate an opengl texture name */
1716 glGenTextures(1, &This->dummyTextureName[i]);
1717 checkGLcall("glGenTextures");
1718 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1720 /* Generate a dummy 2d texture (not using 1d because they cause many
1721 * DRI drivers fall back to sw) */
1722 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1723 checkGLcall("glBindTexture");
1725 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1726 checkGLcall("glTexImage2D");
1729 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1731 /* Reenable because if supported it is enabled by default */
1732 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1733 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1739 /* Context activation is done by the caller. */
1740 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1743 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1744 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1747 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1750 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1752 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1754 if (!wined3d_register_window(window, device))
1756 ERR("Failed to register window %p.\n", window);
1760 device->focus_window = window;
1761 SetForegroundWindow(window);
1766 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1768 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1770 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1771 device->focus_window = NULL;
1774 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1775 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1778 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1779 IWineD3DSwapChainImpl *swapchain = NULL;
1780 struct wined3d_context *context;
1785 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1787 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1788 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1790 TRACE("(%p) : Creating stateblock\n", This);
1791 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1794 WARN("Failed to create stateblock\n");
1797 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1798 This->updateStateBlock = This->stateBlock;
1799 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1801 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1802 sizeof(*This->render_targets) * gl_info->limits.buffers);
1804 This->NumberOfPalettes = 1;
1805 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1806 if (!This->palettes || !This->render_targets)
1808 ERR("Out of memory!\n");
1812 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1813 if(!This->palettes[0]) {
1814 ERR("Out of memory!\n");
1818 for (i = 0; i < 256; ++i) {
1819 This->palettes[0][i].peRed = 0xFF;
1820 This->palettes[0][i].peGreen = 0xFF;
1821 This->palettes[0][i].peBlue = 0xFF;
1822 This->palettes[0][i].peFlags = 0xFF;
1824 This->currentPalette = 0;
1826 /* Initialize the texture unit mapping to a 1:1 mapping */
1827 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1829 if (state < gl_info->limits.fragment_samplers)
1831 This->texUnitMap[state] = state;
1832 This->rev_tex_unit_map[state] = state;
1834 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1835 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1839 /* Setup the implicit swapchain. This also initializes a context. */
1840 TRACE("Creating implicit swapchain\n");
1841 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1842 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1845 WARN("Failed to create implicit swapchain\n");
1849 This->NumberOfSwapChains = 1;
1850 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1851 if(!This->swapchains) {
1852 ERR("Out of memory!\n");
1855 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1857 if (swapchain->back_buffers && swapchain->back_buffers[0])
1859 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1860 This->render_targets[0] = swapchain->back_buffers[0];
1864 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1865 This->render_targets[0] = swapchain->front_buffer;
1867 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1869 /* Depth Stencil support */
1870 This->depth_stencil = This->auto_depth_stencil;
1871 if (This->depth_stencil)
1872 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1874 hr = This->shader_backend->shader_alloc_private(iface);
1876 TRACE("Shader private data couldn't be allocated\n");
1879 hr = This->frag_pipe->alloc_private(iface);
1881 TRACE("Fragment pipeline private data couldn't be allocated\n");
1884 hr = This->blitter->alloc_private(iface);
1886 TRACE("Blitter private data couldn't be allocated\n");
1890 /* Set up some starting GL setup */
1892 /* Setup all the devices defaults */
1893 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1895 context = context_acquire(This, swapchain->front_buffer);
1897 create_dummy_textures(This);
1901 /* Initialize the current view state */
1902 This->view_ident = 1;
1903 This->contexts[0]->last_was_rhw = 0;
1904 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1905 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1907 switch(wined3d_settings.offscreen_rendering_mode) {
1909 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1912 case ORM_BACKBUFFER:
1914 if (context_get_current()->aux_buffers > 0)
1916 TRACE("Using auxilliary buffer for offscreen rendering\n");
1917 This->offscreenBuffer = GL_AUX0;
1919 TRACE("Using back buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_BACK;
1925 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1928 context_release(context);
1930 /* Clear the screen */
1931 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1932 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1935 This->d3d_initialized = TRUE;
1937 if(wined3d_settings.logo) {
1938 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1940 This->highest_dirty_ps_const = 0;
1941 This->highest_dirty_vs_const = 0;
1945 HeapFree(GetProcessHeap(), 0, This->render_targets);
1946 HeapFree(GetProcessHeap(), 0, This->swapchains);
1947 This->NumberOfSwapChains = 0;
1948 if(This->palettes) {
1949 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1950 HeapFree(GetProcessHeap(), 0, This->palettes);
1952 This->NumberOfPalettes = 0;
1954 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1956 if(This->stateBlock) {
1957 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1958 This->stateBlock = NULL;
1960 if (This->blit_priv) {
1961 This->blitter->free_private(iface);
1963 if (This->fragment_priv) {
1964 This->frag_pipe->free_private(iface);
1966 if (This->shader_priv) {
1967 This->shader_backend->shader_free_private(iface);
1972 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1973 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1976 IWineD3DSwapChainImpl *swapchain = NULL;
1979 /* Setup the implicit swapchain */
1980 TRACE("Creating implicit swapchain\n");
1981 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1982 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1985 WARN("Failed to create implicit swapchain\n");
1989 This->NumberOfSwapChains = 1;
1990 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1991 if(!This->swapchains) {
1992 ERR("Out of memory!\n");
1995 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1999 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2003 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2005 IWineD3DResource_UnLoad(resource);
2006 IWineD3DResource_Release(resource);
2010 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2011 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2014 const struct wined3d_gl_info *gl_info;
2015 struct wined3d_context *context;
2018 TRACE("(%p)\n", This);
2020 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2022 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2023 * it was created. Thus make sure a context is active for the glDelete* calls
2025 context = context_acquire(This, NULL);
2026 gl_info = context->gl_info;
2028 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2030 /* Unload resources */
2031 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2033 TRACE("Deleting high order patches\n");
2034 for(i = 0; i < PATCHMAP_SIZE; i++) {
2035 struct list *e1, *e2;
2036 struct WineD3DRectPatch *patch;
2037 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2038 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2039 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2043 /* Delete the mouse cursor texture */
2044 if(This->cursorTexture) {
2046 glDeleteTextures(1, &This->cursorTexture);
2048 This->cursorTexture = 0;
2051 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2052 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2054 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2055 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2058 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2059 * private data, it might contain opengl pointers
2061 if(This->depth_blt_texture) {
2063 glDeleteTextures(1, &This->depth_blt_texture);
2065 This->depth_blt_texture = 0;
2067 if (This->depth_blt_rb) {
2069 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2071 This->depth_blt_rb = 0;
2072 This->depth_blt_rb_w = 0;
2073 This->depth_blt_rb_h = 0;
2076 /* Release the update stateblock */
2077 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2078 if(This->updateStateBlock != This->stateBlock)
2079 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2081 This->updateStateBlock = NULL;
2083 { /* because were not doing proper internal refcounts releasing the primary state block
2084 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2085 to set this->stateBlock = NULL; first */
2086 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2087 This->stateBlock = NULL;
2089 /* Release the stateblock */
2090 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2091 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2095 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2096 This->blitter->free_private(iface);
2097 This->frag_pipe->free_private(iface);
2098 This->shader_backend->shader_free_private(iface);
2100 /* Release the buffers (with sanity checks)*/
2101 if (This->onscreen_depth_stencil)
2103 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2104 This->onscreen_depth_stencil = NULL;
2107 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2108 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2110 if (This->auto_depth_stencil != This->depth_stencil)
2111 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2113 This->depth_stencil = NULL;
2115 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2116 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2118 TRACE("Setting rendertarget to NULL\n");
2119 This->render_targets[0] = NULL;
2121 if (This->auto_depth_stencil)
2123 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2125 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2127 This->auto_depth_stencil = NULL;
2130 context_release(context);
2132 for(i=0; i < This->NumberOfSwapChains; i++) {
2133 TRACE("Releasing the implicit swapchain %d\n", i);
2134 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2135 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2139 HeapFree(GetProcessHeap(), 0, This->swapchains);
2140 This->swapchains = NULL;
2141 This->NumberOfSwapChains = 0;
2143 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2144 HeapFree(GetProcessHeap(), 0, This->palettes);
2145 This->palettes = NULL;
2146 This->NumberOfPalettes = 0;
2148 HeapFree(GetProcessHeap(), 0, This->render_targets);
2149 This->render_targets = NULL;
2151 This->d3d_initialized = FALSE;
2156 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2160 for(i=0; i < This->NumberOfSwapChains; i++) {
2161 TRACE("Releasing the implicit swapchain %d\n", i);
2162 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2163 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2167 HeapFree(GetProcessHeap(), 0, This->swapchains);
2168 This->swapchains = NULL;
2169 This->NumberOfSwapChains = 0;
2173 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2174 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2175 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2177 * There is no way to deactivate thread safety once it is enabled.
2179 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2182 /*For now just store the flag(needed in case of ddraw) */
2183 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2186 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2187 const WINED3DDISPLAYMODE* pMode) {
2189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2190 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2194 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2196 /* Resize the screen even without a window:
2197 * The app could have unset it with SetCooperativeLevel, but not called
2198 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2199 * but we don't have any hwnd
2202 memset(&devmode, 0, sizeof(devmode));
2203 devmode.dmSize = sizeof(devmode);
2204 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2205 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2206 devmode.dmPelsWidth = pMode->Width;
2207 devmode.dmPelsHeight = pMode->Height;
2209 devmode.dmDisplayFrequency = pMode->RefreshRate;
2210 if (pMode->RefreshRate != 0) {
2211 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2214 /* Only change the mode if necessary */
2215 if( (This->ddraw_width == pMode->Width) &&
2216 (This->ddraw_height == pMode->Height) &&
2217 (This->ddraw_format == pMode->Format) &&
2218 (pMode->RefreshRate == 0) ) {
2222 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2223 if (ret != DISP_CHANGE_SUCCESSFUL) {
2224 if(devmode.dmDisplayFrequency != 0) {
2225 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2226 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2227 devmode.dmDisplayFrequency = 0;
2228 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2230 if(ret != DISP_CHANGE_SUCCESSFUL) {
2231 return WINED3DERR_NOTAVAILABLE;
2235 /* Store the new values */
2236 This->ddraw_width = pMode->Width;
2237 This->ddraw_height = pMode->Height;
2238 This->ddraw_format = pMode->Format;
2240 /* And finally clip mouse to our screen */
2241 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2242 ClipCursor(&clip_rc);
2247 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2249 *ppD3D = This->wined3d;
2250 TRACE("Returning %p.\n", *ppD3D);
2251 IWineD3D_AddRef(*ppD3D);
2255 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2258 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2259 (This->adapter->TextureRam/(1024*1024)),
2260 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2261 /* return simulated texture memory left */
2262 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2266 * Get / Set Stream Source
2268 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2269 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2272 IWineD3DBuffer *oldSrc;
2274 if (StreamNumber >= MAX_STREAMS) {
2275 WARN("Stream out of range %d\n", StreamNumber);
2276 return WINED3DERR_INVALIDCALL;
2277 } else if(OffsetInBytes & 0x3) {
2278 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2279 return WINED3DERR_INVALIDCALL;
2282 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2283 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2285 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2287 if(oldSrc == pStreamData &&
2288 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2289 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2290 TRACE("Application is setting the old values over, nothing to do\n");
2294 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2296 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2297 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2300 /* Handle recording of state blocks */
2301 if (This->isRecordingState) {
2302 TRACE("Recording... not performing anything\n");
2303 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2304 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2308 if (pStreamData != NULL) {
2309 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2310 IWineD3DBuffer_AddRef(pStreamData);
2312 if (oldSrc != NULL) {
2313 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2314 IWineD3DBuffer_Release(oldSrc);
2317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2322 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2323 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2327 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2328 This->stateBlock->streamSource[StreamNumber],
2329 This->stateBlock->streamOffset[StreamNumber],
2330 This->stateBlock->streamStride[StreamNumber]);
2332 if (StreamNumber >= MAX_STREAMS) {
2333 WARN("Stream out of range %d\n", StreamNumber);
2334 return WINED3DERR_INVALIDCALL;
2336 *pStream = This->stateBlock->streamSource[StreamNumber];
2337 *pStride = This->stateBlock->streamStride[StreamNumber];
2339 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2342 if (*pStream != NULL) {
2343 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2348 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2350 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2351 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2353 /* Verify input at least in d3d9 this is invalid*/
2354 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2355 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2356 return WINED3DERR_INVALIDCALL;
2358 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2359 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2360 return WINED3DERR_INVALIDCALL;
2363 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2364 return WINED3DERR_INVALIDCALL;
2367 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2368 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2370 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2371 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2373 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2374 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2381 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2385 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2387 TRACE("(%p) : returning %d\n", This, *Divider);
2393 * Get / Set & Multiply Transform
2395 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398 /* Most of this routine, comments included copied from ddraw tree initially: */
2399 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2401 /* Handle recording of state blocks */
2402 if (This->isRecordingState) {
2403 TRACE("Recording... not performing anything\n");
2404 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2405 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2410 * If the new matrix is the same as the current one,
2411 * we cut off any further processing. this seems to be a reasonable
2412 * optimization because as was noticed, some apps (warcraft3 for example)
2413 * tend towards setting the same matrix repeatedly for some reason.
2415 * From here on we assume that the new matrix is different, wherever it matters.
2417 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2418 TRACE("The app is setting the same matrix over again\n");
2421 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2425 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2426 where ViewMat = Camera space, WorldMat = world space.
2428 In OpenGL, camera and world space is combined into GL_MODELVIEW
2429 matrix. The Projection matrix stay projection matrix.
2432 /* Capture the times we can just ignore the change for now */
2433 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2434 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2435 /* Handled by the state manager */
2438 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2442 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2445 *pMatrix = This->stateBlock->transforms[State];
2449 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2450 const WINED3DMATRIX *mat = NULL;
2453 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2454 * below means it will be recorded in a state block change, but it
2455 * works regardless where it is recorded.
2456 * If this is found to be wrong, change to StateBlock.
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2461 if (State <= HIGHEST_TRANSFORMSTATE)
2463 mat = &This->updateStateBlock->transforms[State];
2465 FIXME("Unhandled transform state!!\n");
2468 multiply_matrix(&temp, mat, pMatrix);
2470 /* Apply change via set transform - will reapply to eg. lights this way */
2471 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2477 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2478 you can reference any indexes you want as long as that number max are enabled at any
2479 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2480 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2481 but when recording, just build a chain pretty much of commands to be replayed. */
2483 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2485 struct wined3d_light_info *object = NULL;
2486 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2492 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2496 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2497 return WINED3DERR_INVALIDCALL;
2500 switch(pLight->Type) {
2501 case WINED3DLIGHT_POINT:
2502 case WINED3DLIGHT_SPOT:
2503 case WINED3DLIGHT_PARALLELPOINT:
2504 case WINED3DLIGHT_GLSPOT:
2505 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2508 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2510 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2511 return WINED3DERR_INVALIDCALL;
2515 case WINED3DLIGHT_DIRECTIONAL:
2516 /* Ignores attenuation */
2520 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2521 return WINED3DERR_INVALIDCALL;
2524 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2526 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2527 if(object->OriginalIndex == Index) break;
2532 TRACE("Adding new light\n");
2533 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2535 ERR("Out of memory error when allocating a light\n");
2536 return E_OUTOFMEMORY;
2538 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2539 object->glIndex = -1;
2540 object->OriginalIndex = Index;
2543 /* Initialize the object */
2544 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,
2545 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2546 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2547 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2548 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2549 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2550 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2552 /* Save away the information */
2553 object->OriginalParms = *pLight;
2555 switch (pLight->Type) {
2556 case WINED3DLIGHT_POINT:
2558 object->lightPosn[0] = pLight->Position.x;
2559 object->lightPosn[1] = pLight->Position.y;
2560 object->lightPosn[2] = pLight->Position.z;
2561 object->lightPosn[3] = 1.0f;
2562 object->cutoff = 180.0f;
2566 case WINED3DLIGHT_DIRECTIONAL:
2568 object->lightPosn[0] = -pLight->Direction.x;
2569 object->lightPosn[1] = -pLight->Direction.y;
2570 object->lightPosn[2] = -pLight->Direction.z;
2571 object->lightPosn[3] = 0.0f;
2572 object->exponent = 0.0f;
2573 object->cutoff = 180.0f;
2576 case WINED3DLIGHT_SPOT:
2578 object->lightPosn[0] = pLight->Position.x;
2579 object->lightPosn[1] = pLight->Position.y;
2580 object->lightPosn[2] = pLight->Position.z;
2581 object->lightPosn[3] = 1.0f;
2584 object->lightDirn[0] = pLight->Direction.x;
2585 object->lightDirn[1] = pLight->Direction.y;
2586 object->lightDirn[2] = pLight->Direction.z;
2587 object->lightDirn[3] = 1.0f;
2590 * opengl-ish and d3d-ish spot lights use too different models for the
2591 * light "intensity" as a function of the angle towards the main light direction,
2592 * so we only can approximate very roughly.
2593 * however spot lights are rather rarely used in games (if ever used at all).
2594 * furthermore if still used, probably nobody pays attention to such details.
2596 if (pLight->Falloff == 0) {
2597 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2598 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2599 * will always be 1.0 for both of them, and we don't have to care for the
2600 * rest of the rather complex calculation
2602 object->exponent = 0.0f;
2604 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2605 if (rho < 0.0001f) rho = 0.0001f;
2606 object->exponent = -0.3f/logf(cosf(rho/2));
2608 if (object->exponent > 128.0f)
2610 object->exponent = 128.0f;
2612 object->cutoff = (float) (pLight->Phi*90/M_PI);
2618 FIXME("Unrecognized light type %d\n", pLight->Type);
2621 /* Update the live definitions if the light is currently assigned a glIndex */
2622 if (object->glIndex != -1 && !This->isRecordingState) {
2623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2628 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2630 struct wined3d_light_info *lightInfo = NULL;
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2634 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2636 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2638 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2639 if(lightInfo->OriginalIndex == Index) break;
2643 if (lightInfo == NULL) {
2644 TRACE("Light information requested but light not defined\n");
2645 return WINED3DERR_INVALIDCALL;
2648 *pLight = lightInfo->OriginalParms;
2653 * Get / Set Light Enable
2654 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2656 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2658 struct wined3d_light_info *lightInfo = NULL;
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2660 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2662 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2664 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2666 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2667 if(lightInfo->OriginalIndex == Index) break;
2670 TRACE("Found light: %p\n", lightInfo);
2672 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2673 if (lightInfo == NULL) {
2675 TRACE("Light enabled requested but light not defined, so defining one!\n");
2676 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2678 /* Search for it again! Should be fairly quick as near head of list */
2679 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2681 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2682 if(lightInfo->OriginalIndex == Index) break;
2685 if (lightInfo == NULL) {
2686 FIXME("Adding default lights has failed dismally\n");
2687 return WINED3DERR_INVALIDCALL;
2692 if(lightInfo->glIndex != -1) {
2693 if(!This->isRecordingState) {
2694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2697 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2698 lightInfo->glIndex = -1;
2700 TRACE("Light already disabled, nothing to do\n");
2702 lightInfo->enabled = FALSE;
2704 lightInfo->enabled = TRUE;
2705 if (lightInfo->glIndex != -1) {
2707 TRACE("Nothing to do as light was enabled\n");
2710 /* Find a free gl light */
2711 for(i = 0; i < This->maxConcurrentLights; i++) {
2712 if(This->updateStateBlock->activeLights[i] == NULL) {
2713 This->updateStateBlock->activeLights[i] = lightInfo;
2714 lightInfo->glIndex = i;
2718 if(lightInfo->glIndex == -1) {
2719 /* Our tests show that Windows returns D3D_OK in this situation, even with
2720 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2721 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2722 * as well for those lights.
2724 * TODO: Test how this affects rendering
2726 WARN("Too many concurrently active lights\n");
2730 /* i == lightInfo->glIndex */
2731 if(!This->isRecordingState) {
2732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2740 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2742 struct wined3d_light_info *lightInfo = NULL;
2743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2745 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2746 TRACE("(%p) : for idx(%d)\n", This, Index);
2748 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2750 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2751 if(lightInfo->OriginalIndex == Index) break;
2755 if (lightInfo == NULL) {
2756 TRACE("Light enabled state requested but light not defined\n");
2757 return WINED3DERR_INVALIDCALL;
2759 /* true is 128 according to SetLightEnable */
2760 *pEnable = lightInfo->enabled ? 128 : 0;
2765 * Get / Set Clip Planes
2767 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2771 /* Validate Index */
2772 if (Index >= This->adapter->gl_info.limits.clipplanes)
2774 TRACE("Application has requested clipplane this device doesn't support\n");
2775 return WINED3DERR_INVALIDCALL;
2778 This->updateStateBlock->changed.clipplane |= 1 << Index;
2780 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2781 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2782 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2783 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2784 TRACE("Application is setting old values over, nothing to do\n");
2788 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2789 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2790 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2791 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2793 /* Handle recording of state blocks */
2794 if (This->isRecordingState) {
2795 TRACE("Recording... not performing anything\n");
2799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2804 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 TRACE("(%p) : for idx %d\n", This, Index);
2808 /* Validate Index */
2809 if (Index >= This->adapter->gl_info.limits.clipplanes)
2811 TRACE("Application has requested clipplane this device doesn't support\n");
2812 return WINED3DERR_INVALIDCALL;
2815 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2816 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2817 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2818 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2823 * Get / Set Clip Plane Status
2824 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 FIXME("(%p) : stub\n", This);
2829 if (NULL == pClipStatus) {
2830 return WINED3DERR_INVALIDCALL;
2832 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2833 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2837 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2839 FIXME("(%p) : stub\n", This);
2840 if (NULL == pClipStatus) {
2841 return WINED3DERR_INVALIDCALL;
2843 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2844 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2849 * Get / Set Material
2851 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 This->updateStateBlock->changed.material = TRUE;
2855 This->updateStateBlock->material = *pMaterial;
2857 /* Handle recording of state blocks */
2858 if (This->isRecordingState) {
2859 TRACE("Recording... not performing anything\n");
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 *pMaterial = This->updateStateBlock->material;
2870 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2871 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2872 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2873 pMaterial->Ambient.b, pMaterial->Ambient.a);
2874 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2875 pMaterial->Specular.b, pMaterial->Specular.a);
2876 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2877 pMaterial->Emissive.b, pMaterial->Emissive.a);
2878 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2886 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2887 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 IWineD3DBuffer *oldIdxs;
2892 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2893 oldIdxs = This->updateStateBlock->pIndexData;
2895 This->updateStateBlock->changed.indices = TRUE;
2896 This->updateStateBlock->pIndexData = pIndexData;
2897 This->updateStateBlock->IndexFmt = fmt;
2899 /* Handle recording of state blocks */
2900 if (This->isRecordingState) {
2901 TRACE("Recording... not performing anything\n");
2902 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2903 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2907 if(oldIdxs != pIndexData) {
2908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2910 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2911 IWineD3DBuffer_AddRef(pIndexData);
2914 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2915 IWineD3DBuffer_Release(oldIdxs);
2922 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 *ppIndexData = This->stateBlock->pIndexData;
2928 /* up ref count on ppindexdata */
2930 IWineD3DBuffer_AddRef(*ppIndexData);
2931 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2933 TRACE("(%p) No index data set\n", This);
2935 TRACE("Returning %p\n", *ppIndexData);
2940 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2941 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p)->(%d)\n", This, BaseIndex);
2945 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2946 TRACE("Application is setting the old value over, nothing to do\n");
2950 This->updateStateBlock->baseVertexIndex = BaseIndex;
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2956 /* The base vertex index affects the stream sources */
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2961 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2963 TRACE("(%p) : base_index %p\n", This, base_index);
2965 *base_index = This->stateBlock->baseVertexIndex;
2967 TRACE("Returning %u\n", *base_index);
2973 * Get / Set Viewports
2975 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2978 TRACE("(%p)\n", This);
2979 This->updateStateBlock->changed.viewport = TRUE;
2980 This->updateStateBlock->viewport = *pViewport;
2982 /* Handle recording of state blocks */
2983 if (This->isRecordingState) {
2984 TRACE("Recording... not performing anything\n");
2988 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2989 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 TRACE("(%p)\n", This);
2999 *pViewport = This->stateBlock->viewport;
3004 * Get / Set Render States
3005 * TODO: Verify against dx9 definitions
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 DWORD oldValue = This->stateBlock->renderState[State];
3012 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3014 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3015 This->updateStateBlock->renderState[State] = Value;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3023 /* Compared here and not before the assignment to allow proper stateblock recording */
3024 if(Value == oldValue) {
3025 TRACE("Application is setting the old value over, nothing to do\n");
3027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3033 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3038 *pValue = This->stateBlock->renderState[State];
3043 * Get / Set Sampler States
3044 * TODO: Verify against dx9 definitions
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3052 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3054 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3055 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3058 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3059 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3060 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3063 * SetSampler is designed to allow for more than the standard up to 8 textures
3064 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3065 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3067 * http://developer.nvidia.com/object/General_FAQ.html#t6
3069 * There are two new settings for GForce
3071 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3072 * and the texture one:
3073 * GL_MAX_TEXTURE_COORDS_ARB.
3074 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3077 oldValue = This->stateBlock->samplerState[Sampler][Type];
3078 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3079 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3081 /* Handle recording of state blocks */
3082 if (This->isRecordingState) {
3083 TRACE("Recording... not performing anything\n");
3087 if(oldValue == Value) {
3088 TRACE("Application is setting the old value over, nothing to do\n");
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3097 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3101 This, Sampler, debug_d3dsamplerstate(Type), Type);
3103 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3104 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3107 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3108 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3109 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3111 *Value = This->stateBlock->samplerState[Sampler][Type];
3112 TRACE("(%p) : Returning %#x\n", This, *Value);
3117 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 This->updateStateBlock->changed.scissorRect = TRUE;
3121 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3122 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3125 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3127 if(This->isRecordingState) {
3128 TRACE("Recording... not performing anything\n");
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3137 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 *pRect = This->updateStateBlock->scissorRect;
3141 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3147 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3149 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3151 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3152 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3154 This->updateStateBlock->vertexDecl = pDecl;
3155 This->updateStateBlock->changed.vertexDecl = TRUE;
3157 if (This->isRecordingState) {
3158 TRACE("Recording... not performing anything\n");
3160 } else if(pDecl == oldDecl) {
3161 /* Checked after the assignment to allow proper stateblock recording */
3162 TRACE("Application is setting the old declaration over, nothing to do\n");
3166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3170 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3175 *ppDecl = This->stateBlock->vertexDecl;
3176 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3180 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3184 This->updateStateBlock->vertexShader = pShader;
3185 This->updateStateBlock->changed.vertexShader = TRUE;
3187 if (This->isRecordingState) {
3188 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3189 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3190 TRACE("Recording... not performing anything\n");
3192 } else if(oldShader == pShader) {
3193 /* Checked here to allow proper stateblock recording */
3194 TRACE("App is setting the old shader over, nothing to do\n");
3198 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3199 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3200 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 if (NULL == ppShader) {
3211 return WINED3DERR_INVALIDCALL;
3213 *ppShader = This->stateBlock->vertexShader;
3214 if( NULL != *ppShader)
3215 IWineD3DVertexShader_AddRef(*ppShader);
3217 TRACE("(%p) : returning %p\n", This, *ppShader);
3221 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3222 IWineD3DDevice *iface,
3224 CONST BOOL *srcData,
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3230 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3231 iface, srcData, start, count);
3233 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3235 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3236 for (i = 0; i < cnt; i++)
3237 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3239 for (i = start; i < cnt + start; ++i) {
3240 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3243 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3248 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3249 IWineD3DDevice *iface,
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 int cnt = min(count, MAX_CONST_B - start);
3257 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3258 iface, dstData, start, count);
3260 if (dstData == NULL || cnt < 0)
3261 return WINED3DERR_INVALIDCALL;
3263 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3267 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3268 IWineD3DDevice *iface,
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3276 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3277 iface, srcData, start, count);
3279 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3281 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3282 for (i = 0; i < cnt; i++)
3283 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3284 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3286 for (i = start; i < cnt + start; ++i) {
3287 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3290 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3295 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3296 IWineD3DDevice *iface,
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 int cnt = min(count, MAX_CONST_I - start);
3304 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3305 iface, dstData, start, count);
3307 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3308 return WINED3DERR_INVALIDCALL;
3310 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3314 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3315 IWineD3DDevice *iface,
3317 CONST float *srcData,
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3324 iface, srcData, start, count);
3326 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3327 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3328 return WINED3DERR_INVALIDCALL;
3330 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3332 for (i = 0; i < count; i++)
3333 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3334 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3337 if (!This->isRecordingState)
3339 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3340 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3343 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3344 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3349 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3350 IWineD3DDevice *iface,
3355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 int cnt = min(count, This->d3d_vshader_constantF - start);
3358 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3359 iface, dstData, start, count);
3361 if (dstData == NULL || cnt < 0)
3362 return WINED3DERR_INVALIDCALL;
3364 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3368 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3370 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3376 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3378 DWORD i = This->rev_tex_unit_map[unit];
3379 DWORD j = This->texUnitMap[stage];
3381 This->texUnitMap[stage] = unit;
3382 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3384 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3387 This->rev_tex_unit_map[unit] = stage;
3388 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3390 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3394 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3397 This->fixed_function_usage_map = 0;
3398 for (i = 0; i < MAX_TEXTURES; ++i) {
3399 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3400 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3401 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3402 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3403 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3404 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3405 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3406 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3408 if (color_op == WINED3DTOP_DISABLE) {
3409 /* Not used, and disable higher stages */
3413 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3414 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3415 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3416 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3417 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3418 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3419 This->fixed_function_usage_map |= (1 << i);
3422 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3423 This->fixed_function_usage_map |= (1 << (i + 1));
3428 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3430 unsigned int i, tex;
3433 device_update_fixed_function_usage_map(This);
3434 ffu_map = This->fixed_function_usage_map;
3436 if (This->max_ffp_textures == gl_info->limits.texture_stages
3437 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3439 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3441 if (!(ffu_map & 1)) continue;
3443 if (This->texUnitMap[i] != i) {
3444 device_map_stage(This, i, i);
3445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3446 markTextureStagesDirty(This, i);
3452 /* Now work out the mapping */
3454 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3456 if (!(ffu_map & 1)) continue;
3458 if (This->texUnitMap[i] != tex) {
3459 device_map_stage(This, i, tex);
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3461 markTextureStagesDirty(This, i);
3468 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3470 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3471 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3474 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3475 if (sampler_type[i] && This->texUnitMap[i] != i)
3477 device_map_stage(This, i, i);
3478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3479 if (i < gl_info->limits.texture_stages)
3481 markTextureStagesDirty(This, i);
3487 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3488 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3490 DWORD current_mapping = This->rev_tex_unit_map[unit];
3492 /* Not currently used */
3493 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3495 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3496 /* Used by a fragment sampler */
3498 if (!pshader_sampler_tokens) {
3499 /* No pixel shader, check fixed function */
3500 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3503 /* Pixel shader, check the shader's sampler map */
3504 return !pshader_sampler_tokens[current_mapping];
3507 /* Used by a vertex sampler */
3508 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3511 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3513 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3514 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3515 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3516 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3520 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3522 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3523 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3524 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3527 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3528 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3529 if (vshader_sampler_type[i])
3531 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3533 /* Already mapped somewhere */
3537 while (start >= 0) {
3538 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3540 device_map_stage(This, vsampler_idx, start);
3541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3553 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3555 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3556 BOOL vs = use_vs(This->stateBlock);
3557 BOOL ps = use_ps(This->stateBlock);
3560 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3561 * that would be really messy and require shader recompilation
3562 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3563 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3565 if (ps) device_map_psamplers(This, gl_info);
3566 else device_map_fixed_function_samplers(This, gl_info);
3568 if (vs) device_map_vsamplers(This, ps, gl_info);
3571 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3573 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3574 This->updateStateBlock->pixelShader = pShader;
3575 This->updateStateBlock->changed.pixelShader = TRUE;
3577 /* Handle recording of state blocks */
3578 if (This->isRecordingState) {
3579 TRACE("Recording... not performing anything\n");
3582 if (This->isRecordingState) {
3583 TRACE("Recording... not performing anything\n");
3584 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3585 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3589 if(pShader == oldShader) {
3590 TRACE("App is setting the old pixel shader over, nothing to do\n");
3594 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3595 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3597 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3603 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3606 if (NULL == ppShader) {
3607 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3608 return WINED3DERR_INVALIDCALL;
3611 *ppShader = This->stateBlock->pixelShader;
3612 if (NULL != *ppShader) {
3613 IWineD3DPixelShader_AddRef(*ppShader);
3615 TRACE("(%p) : returning %p\n", This, *ppShader);
3619 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3620 IWineD3DDevice *iface,
3622 CONST BOOL *srcData,
3625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3626 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3628 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3629 iface, srcData, start, count);
3631 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3633 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3634 for (i = 0; i < cnt; i++)
3635 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3637 for (i = start; i < cnt + start; ++i) {
3638 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3641 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3646 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3647 IWineD3DDevice *iface,
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3653 int cnt = min(count, MAX_CONST_B - start);
3655 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3656 iface, dstData, start, count);
3658 if (dstData == NULL || cnt < 0)
3659 return WINED3DERR_INVALIDCALL;
3661 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3665 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3666 IWineD3DDevice *iface,
3671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3672 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3674 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3675 iface, srcData, start, count);
3677 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3679 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3680 for (i = 0; i < cnt; i++)
3681 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3682 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3684 for (i = start; i < cnt + start; ++i) {
3685 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3688 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3693 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3694 IWineD3DDevice *iface,
3699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3700 int cnt = min(count, MAX_CONST_I - start);
3702 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3703 iface, dstData, start, count);
3705 if (dstData == NULL || cnt < 0)
3706 return WINED3DERR_INVALIDCALL;
3708 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3712 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3713 IWineD3DDevice *iface,
3715 CONST float *srcData,
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3721 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3722 iface, srcData, start, count);
3724 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3725 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3726 return WINED3DERR_INVALIDCALL;
3728 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3730 for (i = 0; i < count; i++)
3731 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3732 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3735 if (!This->isRecordingState)
3737 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3741 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3742 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3747 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3748 IWineD3DDevice *iface,
3753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3754 int cnt = min(count, This->d3d_pshader_constantF - start);
3756 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3757 iface, dstData, start, count);
3759 if (dstData == NULL || cnt < 0)
3760 return WINED3DERR_INVALIDCALL;
3762 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3766 /* Context activation is done by the caller. */
3767 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3768 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3769 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3772 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3773 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3776 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3780 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3782 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3785 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3787 ERR("Source has no position mask\n");
3788 return WINED3DERR_INVALIDCALL;
3791 /* We might access VBOs from this code, so hold the lock */
3794 if (!dest->resource.allocatedMemory)
3795 buffer_get_sysmem(dest, gl_info);
3797 /* Get a pointer into the destination vbo(create one if none exists) and
3798 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3800 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3802 dest->flags |= WINED3D_BUFFER_CREATEBO;
3803 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3806 if (dest->buffer_object)
3808 unsigned char extrabytes = 0;
3809 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3810 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3811 * this may write 4 extra bytes beyond the area that should be written
3813 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3814 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3815 if(!dest_conv_addr) {
3816 ERR("Out of memory\n");
3817 /* Continue without storing converted vertices */
3819 dest_conv = dest_conv_addr;
3823 * a) WINED3DRS_CLIPPING is enabled
3824 * b) WINED3DVOP_CLIP is passed
3826 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3827 static BOOL warned = FALSE;
3829 * The clipping code is not quite correct. Some things need
3830 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3831 * so disable clipping for now.
3832 * (The graphics in Half-Life are broken, and my processvertices
3833 * test crashes with IDirect3DDevice3)
3839 FIXME("Clipping is broken and disabled for now\n");
3841 } else doClip = FALSE;
3842 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3844 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3847 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3848 WINED3DTS_PROJECTION,
3850 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3851 WINED3DTS_WORLDMATRIX(0),
3854 TRACE("View mat:\n");
3855 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);
3856 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);
3857 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);
3858 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);
3860 TRACE("Proj mat:\n");
3861 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);
3862 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);
3863 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);
3864 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);
3866 TRACE("World mat:\n");
3867 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);
3868 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);
3869 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);
3870 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);
3872 /* Get the viewport */
3873 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3874 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3875 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3877 multiply_matrix(&mat,&view_mat,&world_mat);
3878 multiply_matrix(&mat,&proj_mat,&mat);
3880 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3882 for (i = 0; i < dwCount; i+= 1) {
3883 unsigned int tex_index;
3885 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3886 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3887 /* The position first */
3888 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3889 const float *p = (const float *)(element->data + i * element->stride);
3891 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3893 /* Multiplication with world, view and projection matrix */
3894 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);
3895 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);
3896 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);
3897 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);
3899 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3901 /* WARNING: The following things are taken from d3d7 and were not yet checked
3902 * against d3d8 or d3d9!
3905 /* Clipping conditions: From msdn
3907 * A vertex is clipped if it does not match the following requirements
3911 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3913 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3914 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3919 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3920 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3923 /* "Normal" viewport transformation (not clipped)
3924 * 1) The values are divided by rhw
3925 * 2) The y axis is negative, so multiply it with -1
3926 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3927 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3928 * 4) Multiply x with Width/2 and add Width/2
3929 * 5) The same for the height
3930 * 6) Add the viewpoint X and Y to the 2D coordinates and
3931 * The minimum Z value to z
3932 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3934 * Well, basically it's simply a linear transformation into viewport
3946 z *= vp.MaxZ - vp.MinZ;
3948 x += vp.Width / 2 + vp.X;
3949 y += vp.Height / 2 + vp.Y;
3954 /* That vertex got clipped
3955 * Contrary to OpenGL it is not dropped completely, it just
3956 * undergoes a different calculation.
3958 TRACE("Vertex got clipped\n");
3965 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3966 * outside of the main vertex buffer memory. That needs some more
3971 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3974 ( (float *) dest_ptr)[0] = x;
3975 ( (float *) dest_ptr)[1] = y;
3976 ( (float *) dest_ptr)[2] = z;
3977 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3979 dest_ptr += 3 * sizeof(float);
3981 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3982 dest_ptr += sizeof(float);
3987 ( (float *) dest_conv)[0] = x * w;
3988 ( (float *) dest_conv)[1] = y * w;
3989 ( (float *) dest_conv)[2] = z * w;
3990 ( (float *) dest_conv)[3] = w;
3992 dest_conv += 3 * sizeof(float);
3994 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3995 dest_conv += sizeof(float);
3999 if (DestFVF & WINED3DFVF_PSIZE) {
4000 dest_ptr += sizeof(DWORD);
4001 if(dest_conv) dest_conv += sizeof(DWORD);
4003 if (DestFVF & WINED3DFVF_NORMAL) {
4004 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4005 const float *normal = (const float *)(element->data + i * element->stride);
4006 /* AFAIK this should go into the lighting information */
4007 FIXME("Didn't expect the destination to have a normal\n");
4008 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4010 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4014 if (DestFVF & WINED3DFVF_DIFFUSE) {
4015 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4016 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4017 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4019 static BOOL warned = FALSE;
4022 ERR("No diffuse color in source, but destination has one\n");
4026 *( (DWORD *) dest_ptr) = 0xffffffff;
4027 dest_ptr += sizeof(DWORD);
4030 *( (DWORD *) dest_conv) = 0xffffffff;
4031 dest_conv += sizeof(DWORD);
4035 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4037 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4038 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4039 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4040 dest_conv += sizeof(DWORD);
4045 if (DestFVF & WINED3DFVF_SPECULAR)
4047 /* What's the color value in the feedback buffer? */
4048 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4049 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4050 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4052 static BOOL warned = FALSE;
4055 ERR("No specular color in source, but destination has one\n");
4059 *( (DWORD *) dest_ptr) = 0xFF000000;
4060 dest_ptr += sizeof(DWORD);
4063 *( (DWORD *) dest_conv) = 0xFF000000;
4064 dest_conv += sizeof(DWORD);
4068 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4070 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4071 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4072 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4073 dest_conv += sizeof(DWORD);
4078 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4079 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4080 const float *tex_coord = (const float *)(element->data + i * element->stride);
4081 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4083 ERR("No source texture, but destination requests one\n");
4084 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4085 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4088 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4090 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4097 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4098 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4099 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4100 dwCount * get_flexible_vertex_size(DestFVF),
4102 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4103 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4110 #undef copy_and_next
4112 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4113 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4117 struct wined3d_stream_info stream_info;
4118 const struct wined3d_gl_info *gl_info;
4119 struct wined3d_context *context;
4120 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4123 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4126 ERR("Output vertex declaration not implemented yet\n");
4129 /* Need any context to write to the vbo. */
4130 context = context_acquire(This, NULL);
4131 gl_info = context->gl_info;
4133 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4134 * control the streamIsUP flag, thus restore it afterwards.
4136 This->stateBlock->streamIsUP = FALSE;
4137 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4138 This->stateBlock->streamIsUP = streamWasUP;
4140 if(vbo || SrcStartIndex) {
4142 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4143 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4145 * Also get the start index in, but only loop over all elements if there's something to add at all.
4147 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4149 struct wined3d_stream_info_element *e;
4151 if (!(stream_info.use_map & (1 << i))) continue;
4153 e = &stream_info.elements[i];
4154 if (e->buffer_object)
4156 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4157 e->buffer_object = 0;
4158 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4160 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4161 vb->buffer_object = 0;
4164 if (e->data) e->data += e->stride * SrcStartIndex;
4168 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4169 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4171 context_release(context);
4177 * Get / Set Texture Stage States
4178 * TODO: Verify against dx9 definitions
4180 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4182 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4183 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4185 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4187 if (Stage >= gl_info->limits.texture_stages)
4189 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4190 Stage, gl_info->limits.texture_stages - 1);
4194 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4195 This->updateStateBlock->textureState[Stage][Type] = Value;
4197 if (This->isRecordingState) {
4198 TRACE("Recording... not performing anything\n");
4202 /* Checked after the assignments to allow proper stateblock recording */
4203 if(oldValue == Value) {
4204 TRACE("App is setting the old value over, nothing to do\n");
4208 if(Stage > This->stateBlock->lowest_disabled_stage &&
4209 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4210 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4211 * Changes in other states are important on disabled stages too
4216 if(Type == WINED3DTSS_COLOROP) {
4219 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4220 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4221 * they have to be disabled
4223 * The current stage is dirtified below.
4225 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4226 TRACE("Additionally dirtifying stage %u\n", i);
4227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4229 This->stateBlock->lowest_disabled_stage = Stage;
4230 TRACE("New lowest disabled: %u\n", Stage);
4231 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4232 /* Previously disabled stage enabled. Stages above it may need enabling
4233 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4234 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4236 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4239 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4241 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4244 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4247 This->stateBlock->lowest_disabled_stage = i;
4248 TRACE("New lowest disabled: %u\n", i);
4252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4257 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4259 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4260 *pValue = This->updateStateBlock->textureState[Stage][Type];
4267 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4268 DWORD stage, IWineD3DBaseTexture *texture)
4270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4271 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4272 IWineD3DBaseTexture *prev;
4274 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4276 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4277 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4279 /* Windows accepts overflowing this array... we do not. */
4280 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4282 WARN("Ignoring invalid stage %u.\n", stage);
4286 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4287 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4289 WARN("Rejecting attempt to set scratch texture.\n");
4290 return WINED3DERR_INVALIDCALL;
4293 This->updateStateBlock->changed.textures |= 1 << stage;
4295 prev = This->updateStateBlock->textures[stage];
4296 TRACE("Previous texture %p.\n", prev);
4298 if (texture == prev)
4300 TRACE("App is setting the same texture again, nothing to do.\n");
4304 TRACE("Setting new texture to %p.\n", texture);
4305 This->updateStateBlock->textures[stage] = texture;
4307 if (This->isRecordingState)
4309 TRACE("Recording... not performing anything\n");
4311 if (texture) IWineD3DBaseTexture_AddRef(texture);
4312 if (prev) IWineD3DBaseTexture_Release(prev);
4319 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4320 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4321 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4323 IWineD3DBaseTexture_AddRef(texture);
4325 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4330 if (!prev && stage < gl_info->limits.texture_stages)
4332 /* The source arguments for color and alpha ops have different
4333 * meanings when a NULL texture is bound, so the COLOROP and
4334 * ALPHAOP have to be dirtified. */
4335 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4339 if (bind_count == 1) t->baseTexture.sampler = stage;
4344 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4345 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4347 IWineD3DBaseTexture_Release(prev);
4349 if (!texture && stage < gl_info->limits.texture_stages)
4351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4355 if (bind_count && t->baseTexture.sampler == stage)
4359 /* Search for other stages the texture is bound to. Shouldn't
4360 * happen if applications bind textures to a single stage only. */
4361 TRACE("Searching for other stages the texture is bound to.\n");
4362 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4364 if (This->updateStateBlock->textures[i] == prev)
4366 TRACE("Texture is also bound to stage %u.\n", i);
4367 t->baseTexture.sampler = i;
4374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4379 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4384 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4385 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4388 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4389 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4390 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4393 *ppTexture=This->stateBlock->textures[Stage];
4395 IWineD3DBaseTexture_AddRef(*ppTexture);
4397 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4405 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4406 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4408 IWineD3DSwapChain *swapchain;
4411 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4412 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4414 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4417 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4421 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4422 IWineD3DSwapChain_Release(swapchain);
4425 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4432 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 WARN("(%p) : stub, calling idirect3d for now\n", This);
4435 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4438 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 IWineD3DSwapChain *swapChain;
4443 if(iSwapChain > 0) {
4444 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4445 if (hr == WINED3D_OK) {
4446 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4447 IWineD3DSwapChain_Release(swapChain);
4449 FIXME("(%p) Error getting display mode\n", This);
4452 /* Don't read the real display mode,
4453 but return the stored mode instead. X11 can't change the color
4454 depth, and some apps are pretty angry if they SetDisplayMode from
4455 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4457 Also don't relay to the swapchain because with ddraw it's possible
4458 that there isn't a swapchain at all */
4459 pMode->Width = This->ddraw_width;
4460 pMode->Height = This->ddraw_height;
4461 pMode->Format = This->ddraw_format;
4462 pMode->RefreshRate = 0;
4470 * Stateblock related functions
4473 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4475 IWineD3DStateBlock *stateblock;
4478 TRACE("(%p)\n", This);
4480 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4482 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4483 if (FAILED(hr)) return hr;
4485 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4486 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4487 This->isRecordingState = TRUE;
4489 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4494 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4498 if (!This->isRecordingState) {
4499 WARN("(%p) not recording! returning error\n", This);
4500 *ppStateBlock = NULL;
4501 return WINED3DERR_INVALIDCALL;
4504 stateblock_init_contained_states(object);
4506 *ppStateBlock = (IWineD3DStateBlock*) object;
4507 This->isRecordingState = FALSE;
4508 This->updateStateBlock = This->stateBlock;
4509 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4510 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4511 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4516 * Scene related functions
4518 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4519 /* At the moment we have no need for any functionality at the beginning
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 TRACE("(%p)\n", This);
4525 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4526 return WINED3DERR_INVALIDCALL;
4528 This->inScene = TRUE;
4532 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4535 struct wined3d_context *context;
4537 TRACE("(%p)\n", This);
4539 if(!This->inScene) {
4540 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4541 return WINED3DERR_INVALIDCALL;
4544 context = context_acquire(This, NULL);
4545 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4547 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4549 context_release(context);
4551 This->inScene = FALSE;
4555 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4556 const RECT *pSourceRect, const RECT *pDestRect,
4557 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4559 IWineD3DSwapChain *swapChain = NULL;
4561 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4563 TRACE("iface %p.\n", iface);
4565 for(i = 0 ; i < swapchains ; i ++) {
4567 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4568 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4569 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4570 IWineD3DSwapChain_Release(swapChain);
4576 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4577 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR color, float Z, DWORD Stencil)
4579 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), color (0x%08x), Z (%f), Stencil (%d)\n", This,
4584 Count, pRects, Flags, color, Z, Stencil);
4586 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4588 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4589 /* TODO: What about depth stencil buffers without stencil bits? */
4590 return WINED3DERR_INVALIDCALL;
4593 device_get_draw_rect(This, &draw_rect);
4595 return device_clear_render_targets(This, This->adapter->gl_info.limits.buffers,
4596 This->render_targets, Count, (const RECT *)pRects, &draw_rect, Flags,
4604 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4605 WINED3DPRIMITIVETYPE primitive_type)
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4609 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4611 This->updateStateBlock->changed.primitive_type = TRUE;
4612 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4615 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4616 WINED3DPRIMITIVETYPE *primitive_type)
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4622 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4624 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4627 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4631 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4633 if(!This->stateBlock->vertexDecl) {
4634 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4635 return WINED3DERR_INVALIDCALL;
4638 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4639 if(This->stateBlock->streamIsUP) {
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4641 This->stateBlock->streamIsUP = FALSE;
4644 if(This->stateBlock->loadBaseVertexIndex != 0) {
4645 This->stateBlock->loadBaseVertexIndex = 0;
4646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4648 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4649 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4653 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 IWineD3DBuffer *pIB;
4660 pIB = This->stateBlock->pIndexData;
4662 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4663 * without an index buffer set. (The first time at least...)
4664 * D3D8 simply dies, but I doubt it can do much harm to return
4665 * D3DERR_INVALIDCALL there as well. */
4666 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4667 return WINED3DERR_INVALIDCALL;
4670 if(!This->stateBlock->vertexDecl) {
4671 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4672 return WINED3DERR_INVALIDCALL;
4675 if(This->stateBlock->streamIsUP) {
4676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4677 This->stateBlock->streamIsUP = FALSE;
4679 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4681 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4683 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4689 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4690 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4691 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4694 drawPrimitive(iface, index_count, startIndex, idxStride,
4695 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4700 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4701 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4707 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4709 if(!This->stateBlock->vertexDecl) {
4710 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4711 return WINED3DERR_INVALIDCALL;
4714 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4715 vb = This->stateBlock->streamSource[0];
4716 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4717 if (vb) IWineD3DBuffer_Release(vb);
4718 This->stateBlock->streamOffset[0] = 0;
4719 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4720 This->stateBlock->streamIsUP = TRUE;
4721 This->stateBlock->loadBaseVertexIndex = 0;
4723 /* TODO: Only mark dirty if drawing from a different UP address */
4724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4726 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4728 /* MSDN specifies stream zero settings must be set to NULL */
4729 This->stateBlock->streamStride[0] = 0;
4730 This->stateBlock->streamSource[0] = NULL;
4732 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4733 * the new stream sources or use UP drawing again
4738 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4739 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4740 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4747 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4748 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4750 if(!This->stateBlock->vertexDecl) {
4751 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4752 return WINED3DERR_INVALIDCALL;
4755 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4761 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4762 vb = This->stateBlock->streamSource[0];
4763 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4764 if (vb) IWineD3DBuffer_Release(vb);
4765 This->stateBlock->streamIsUP = TRUE;
4766 This->stateBlock->streamOffset[0] = 0;
4767 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4769 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4770 This->stateBlock->baseVertexIndex = 0;
4771 This->stateBlock->loadBaseVertexIndex = 0;
4772 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4776 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4778 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4779 This->stateBlock->streamSource[0] = NULL;
4780 This->stateBlock->streamStride[0] = 0;
4781 ib = This->stateBlock->pIndexData;
4783 IWineD3DBuffer_Release(ib);
4784 This->stateBlock->pIndexData = NULL;
4786 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4787 * SetStreamSource to specify a vertex buffer
4793 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4794 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4798 /* Mark the state dirty until we have nicer tracking
4799 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4804 This->stateBlock->baseVertexIndex = 0;
4805 This->up_strided = DrawPrimStrideData;
4806 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4807 This->up_strided = NULL;
4811 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4812 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4813 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4816 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4818 /* Mark the state dirty until we have nicer tracking
4819 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4824 This->stateBlock->streamIsUP = TRUE;
4825 This->stateBlock->baseVertexIndex = 0;
4826 This->up_strided = DrawPrimStrideData;
4827 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4828 This->up_strided = NULL;
4832 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4833 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4834 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4836 WINED3DLOCKED_BOX src;
4837 WINED3DLOCKED_BOX dst;
4840 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4841 iface, pSourceVolume, pDestinationVolume);
4843 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4844 * dirtification to improve loading performance.
4846 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4847 if(FAILED(hr)) return hr;
4848 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4850 IWineD3DVolume_UnlockBox(pSourceVolume);
4854 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4856 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4858 IWineD3DVolume_UnlockBox(pSourceVolume);
4860 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4865 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4866 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4868 unsigned int level_count, i;
4869 WINED3DRESOURCETYPE type;
4872 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4874 /* Verify that the source and destination textures are non-NULL. */
4875 if (!src_texture || !dst_texture)
4877 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4878 return WINED3DERR_INVALIDCALL;
4881 if (src_texture == dst_texture)
4883 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4884 return WINED3DERR_INVALIDCALL;
4887 /* Verify that the source and destination textures are the same type. */
4888 type = IWineD3DBaseTexture_GetType(src_texture);
4889 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4891 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4892 return WINED3DERR_INVALIDCALL;
4895 /* Check that both textures have the identical numbers of levels. */
4896 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4897 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4899 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4900 return WINED3DERR_INVALIDCALL;
4903 /* Make sure that the destination texture is loaded. */
4904 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4906 /* Update every surface level of the texture. */
4909 case WINED3DRTYPE_TEXTURE:
4911 IWineD3DSurface *src_surface;
4912 IWineD3DSurface *dst_surface;
4914 for (i = 0; i < level_count; ++i)
4916 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4917 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4918 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4919 IWineD3DSurface_Release(dst_surface);
4920 IWineD3DSurface_Release(src_surface);
4923 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4930 case WINED3DRTYPE_CUBETEXTURE:
4932 IWineD3DSurface *src_surface;
4933 IWineD3DSurface *dst_surface;
4934 WINED3DCUBEMAP_FACES face;
4936 for (i = 0; i < level_count; ++i)
4938 /* Update each cube face. */
4939 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4941 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4942 face, i, &src_surface);
4943 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4944 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4945 face, i, &dst_surface);
4946 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4947 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4948 IWineD3DSurface_Release(dst_surface);
4949 IWineD3DSurface_Release(src_surface);
4952 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4960 case WINED3DRTYPE_VOLUMETEXTURE:
4962 IWineD3DVolume *src_volume;
4963 IWineD3DVolume *dst_volume;
4965 for (i = 0; i < level_count; ++i)
4967 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4968 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4969 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4970 IWineD3DVolume_Release(dst_volume);
4971 IWineD3DVolume_Release(src_volume);
4974 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4982 FIXME("Unsupported texture type %#x.\n", type);
4983 return WINED3DERR_INVALIDCALL;
4989 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4990 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4992 IWineD3DSwapChain *swapchain;
4995 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
4997 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4998 if (FAILED(hr)) return hr;
5000 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5001 IWineD3DSwapChain_Release(swapchain);
5006 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 IWineD3DBaseTextureImpl *texture;
5011 TRACE("(%p) : %p\n", This, pNumPasses);
5013 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5014 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5015 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5016 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5018 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5019 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5020 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5023 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5024 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5026 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5027 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5030 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5031 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5034 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5035 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5036 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5041 /* return a sensible default */
5044 TRACE("returning D3D_OK\n");
5048 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5052 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5054 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5055 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5056 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5058 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5063 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 PALETTEENTRY **palettes;
5069 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5071 if (PaletteNumber >= MAX_PALETTES) {
5072 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5073 return WINED3DERR_INVALIDCALL;
5076 if (PaletteNumber >= This->NumberOfPalettes) {
5077 NewSize = This->NumberOfPalettes;
5080 } while(PaletteNumber >= NewSize);
5081 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5083 ERR("Out of memory!\n");
5084 return E_OUTOFMEMORY;
5086 This->palettes = palettes;
5087 This->NumberOfPalettes = NewSize;
5090 if (!This->palettes[PaletteNumber]) {
5091 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5092 if (!This->palettes[PaletteNumber]) {
5093 ERR("Out of memory!\n");
5094 return E_OUTOFMEMORY;
5098 for (j = 0; j < 256; ++j) {
5099 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5100 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5101 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5102 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5104 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5105 TRACE("(%p) : returning\n", This);
5109 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5112 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5113 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5114 /* What happens in such situation isn't documented; Native seems to silently abort
5115 on such conditions. Return Invalid Call. */
5116 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5117 return WINED3DERR_INVALIDCALL;
5119 for (j = 0; j < 256; ++j) {
5120 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5121 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5122 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5123 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5125 TRACE("(%p) : returning\n", This);
5129 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5132 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5133 (tested with reference rasterizer). Return Invalid Call. */
5134 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5135 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5136 return WINED3DERR_INVALIDCALL;
5138 /*TODO: stateblocks */
5139 if (This->currentPalette != PaletteNumber) {
5140 This->currentPalette = PaletteNumber;
5141 dirtify_p8_texture_samplers(This);
5143 TRACE("(%p) : returning\n", This);
5147 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 if (PaletteNumber == NULL) {
5150 WARN("(%p) : returning Invalid Call\n", This);
5151 return WINED3DERR_INVALIDCALL;
5153 /*TODO: stateblocks */
5154 *PaletteNumber = This->currentPalette;
5155 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5159 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 FIXME("(%p) : stub\n", This);
5168 This->softwareVertexProcessing = bSoftware;
5173 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5178 FIXME("(%p) : stub\n", This);
5181 return This->softwareVertexProcessing;
5184 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5185 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5187 IWineD3DSwapChain *swapchain;
5190 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5191 iface, swapchain_idx, raster_status);
5193 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5196 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5200 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5201 IWineD3DSwapChain_Release(swapchain);
5204 WARN("Failed to get raster status, hr %#x.\n", hr);
5211 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5214 if(nSegments != 0.0f) {
5217 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5224 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5229 FIXME("iface %p stub!\n", iface);
5235 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5236 IWineD3DSurface *src_surface, const RECT *src_rect,
5237 IWineD3DSurface *dst_surface, const POINT *dst_point)
5239 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5240 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 const struct wined3d_format_desc *src_format;
5243 const struct wined3d_format_desc *dst_format;
5244 const struct wined3d_gl_info *gl_info;
5245 struct wined3d_context *context;
5246 const unsigned char *data;
5247 UINT update_w, update_h;
5248 CONVERT_TYPES convert;
5252 struct wined3d_format_desc desc;
5254 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5255 iface, src_surface, wine_dbgstr_rect(src_rect),
5256 dst_surface, wine_dbgstr_point(dst_point));
5258 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5260 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5261 src_surface, dst_surface);
5262 return WINED3DERR_INVALIDCALL;
5265 src_format = src_impl->resource.format_desc;
5266 dst_format = dst_impl->resource.format_desc;
5268 if (src_format->format != dst_format->format)
5270 WARN("Source and destination surfaces should have the same format.\n");
5271 return WINED3DERR_INVALIDCALL;
5274 dst_x = dst_point ? dst_point->x : 0;
5275 dst_y = dst_point ? dst_point->y : 0;
5277 /* This call loads the OpenGL surface directly, instead of copying the
5278 * surface to the destination's sysmem copy. If surface conversion is
5279 * needed, use BltFast instead to copy in sysmem and use regular surface
5281 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5282 if (convert != NO_CONVERSION || desc.convert)
5283 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5285 context = context_acquire(This, NULL);
5286 gl_info = context->gl_info;
5289 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5290 checkGLcall("glActiveTextureARB");
5293 /* Make sure the surface is loaded and up to date */
5294 surface_internal_preload(dst_impl, SRGB_RGB);
5295 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5297 src_w = src_impl->currentDesc.Width;
5298 src_h = src_impl->currentDesc.Height;
5299 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5300 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5302 data = IWineD3DSurface_GetData(src_surface);
5303 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5307 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5309 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5310 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5311 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5315 data += (src_rect->top / src_format->block_height) * src_pitch;
5316 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5319 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5320 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5321 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5323 if (row_length == src_pitch)
5325 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5326 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5332 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5333 * can't use the unpack row length like below. */
5334 for (row = 0, y = dst_y; row < row_count; ++row)
5336 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5337 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5338 y += src_format->block_height;
5342 checkGLcall("glCompressedTexSubImage2DARB");
5348 data += src_rect->top * src_w * src_format->byte_count;
5349 data += src_rect->left * src_format->byte_count;
5352 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5353 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5354 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5356 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5357 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5358 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5359 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5360 checkGLcall("glTexSubImage2D");
5364 context_release(context);
5366 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5367 sampler = This->rev_tex_unit_map[0];
5368 if (sampler != WINED3D_UNMAPPED_STAGE)
5370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5376 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 struct WineD3DRectPatch *patch;
5379 GLenum old_primitive_type;
5383 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5385 if(!(Handle || pRectPatchInfo)) {
5386 /* TODO: Write a test for the return value, thus the FIXME */
5387 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5388 return WINED3DERR_INVALIDCALL;
5392 i = PATCHMAP_HASHFUNC(Handle);
5394 LIST_FOR_EACH(e, &This->patches[i]) {
5395 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5396 if(patch->Handle == Handle) {
5403 TRACE("Patch does not exist. Creating a new one\n");
5404 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5405 patch->Handle = Handle;
5406 list_add_head(&This->patches[i], &patch->entry);
5408 TRACE("Found existing patch %p\n", patch);
5411 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5412 * attributes we have to tesselate, read back, and draw. This needs a patch
5413 * management structure instance. Create one.
5415 * A possible improvement is to check if a vertex shader is used, and if not directly
5418 FIXME("Drawing an uncached patch. This is slow\n");
5419 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5422 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5423 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5424 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5426 TRACE("Tesselation density or patch info changed, retesselating\n");
5428 if(pRectPatchInfo) {
5429 patch->RectPatchInfo = *pRectPatchInfo;
5431 patch->numSegs[0] = pNumSegs[0];
5432 patch->numSegs[1] = pNumSegs[1];
5433 patch->numSegs[2] = pNumSegs[2];
5434 patch->numSegs[3] = pNumSegs[3];
5436 hr = tesselate_rectpatch(This, patch);
5438 WARN("Patch tesselation failed\n");
5440 /* Do not release the handle to store the params of the patch */
5442 HeapFree(GetProcessHeap(), 0, patch);
5448 This->currentPatch = patch;
5449 old_primitive_type = This->stateBlock->gl_primitive_type;
5450 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5451 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5452 This->stateBlock->gl_primitive_type = old_primitive_type;
5453 This->currentPatch = NULL;
5455 /* Destroy uncached patches */
5457 HeapFree(GetProcessHeap(), 0, patch->mem);
5458 HeapFree(GetProcessHeap(), 0, patch);
5463 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5464 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5466 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5467 iface, handle, segment_count, patch_info);
5472 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5475 struct WineD3DRectPatch *patch;
5477 TRACE("(%p) Handle(%d)\n", This, Handle);
5479 i = PATCHMAP_HASHFUNC(Handle);
5480 LIST_FOR_EACH(e, &This->patches[i]) {
5481 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5482 if(patch->Handle == Handle) {
5483 TRACE("Deleting patch %p\n", patch);
5484 list_remove(&patch->entry);
5485 HeapFree(GetProcessHeap(), 0, patch->mem);
5486 HeapFree(GetProcessHeap(), 0, patch);
5491 /* TODO: Write a test for the return value */
5492 FIXME("Attempt to destroy nonexistent patch\n");
5493 return WINED3DERR_INVALIDCALL;
5496 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5497 IWineD3DSurface *surface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5499 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5500 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5503 TRACE("iface %p, surface %p, rect %s, color 0x%08x.\n",
5504 iface, surface, wine_dbgstr_rect((const RECT *)pRect), color);
5506 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5508 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5509 return WINED3DERR_INVALIDCALL;
5512 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5514 const RECT draw_rect = {0, 0, s->currentDesc.Width, s->currentDesc.Height};
5516 return device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &s,
5517 !!pRect, (const RECT *)pRect, &draw_rect, WINED3DCLEAR_TARGET, &c, 0.0f, 0);
5521 /* Just forward this to the DirectDraw blitting engine */
5522 memset(&BltFx, 0, sizeof(BltFx));
5523 BltFx.dwSize = sizeof(BltFx);
5524 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(s->resource.format_desc, &c);
5525 return IWineD3DSurface_Blt(surface, (const RECT *)pRect, NULL, NULL,
5526 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5530 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5531 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5533 IWineD3DResource *resource;
5534 IWineD3DSurfaceImpl *surface;
5537 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5540 ERR("Failed to get resource, hr %#x\n", hr);
5544 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5546 FIXME("Only supported on surface resources\n");
5547 IWineD3DResource_Release(resource);
5551 surface = (IWineD3DSurfaceImpl *)resource;
5553 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5555 const RECT draw_rect = {0, 0, surface->currentDesc.Width, surface->currentDesc.Height};
5557 device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &surface,
5558 0, NULL, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
5564 /* Just forward this to the DirectDraw blitting engine */
5565 memset(&BltFx, 0, sizeof(BltFx));
5566 BltFx.dwSize = sizeof(BltFx);
5567 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(surface->resource.format_desc, color);
5568 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5569 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5572 ERR("Blt failed, hr %#x\n", hr);
5576 IWineD3DResource_Release(resource);
5579 /* rendertarget and depth stencil functions */
5580 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5581 DWORD render_target_idx, IWineD3DSurface **render_target)
5583 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5585 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5586 iface, render_target_idx, render_target);
5588 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5590 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5591 return WINED3DERR_INVALIDCALL;
5594 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5595 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5597 TRACE("Returning render target %p.\n", *render_target);
5602 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5603 IWineD3DSurface *front, IWineD3DSurface *back)
5605 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5606 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5607 IWineD3DSwapChainImpl *swapchain;
5610 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5612 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5614 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5618 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5620 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5621 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5622 return WINED3DERR_INVALIDCALL;
5627 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5629 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5630 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5631 return WINED3DERR_INVALIDCALL;
5634 if (!swapchain->back_buffers)
5636 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5637 if (!swapchain->back_buffers)
5639 ERR("Failed to allocate back buffer array memory.\n");
5640 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5641 return E_OUTOFMEMORY;
5646 if (swapchain->front_buffer != front_impl)
5648 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5650 if (swapchain->front_buffer)
5651 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5652 swapchain->front_buffer = front_impl;
5655 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5658 if (swapchain->back_buffers[0] != back_impl)
5660 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5662 if (swapchain->back_buffers[0])
5663 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_TEXTURE, NULL);
5664 swapchain->back_buffers[0] = back_impl;
5668 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5669 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5670 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5671 swapchain->presentParms.BackBufferCount = 1;
5673 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5677 swapchain->presentParms.BackBufferCount = 0;
5678 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5679 swapchain->back_buffers = NULL;
5683 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5687 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5689 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5691 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5693 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5694 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5695 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5696 IWineD3DSurface_AddRef(*depth_stencil);
5701 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5702 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5704 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5705 IWineD3DSurfaceImpl *prev;
5707 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5708 iface, render_target_idx, render_target, set_viewport);
5710 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5712 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5713 return WINED3DERR_INVALIDCALL;
5716 prev = device->render_targets[render_target_idx];
5717 if (render_target == (IWineD3DSurface *)prev)
5719 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5723 /* Render target 0 can't be set to NULL. */
5724 if (!render_target && !render_target_idx)
5726 WARN("Trying to set render target 0 to NULL.\n");
5727 return WINED3DERR_INVALIDCALL;
5730 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5732 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5733 return WINED3DERR_INVALIDCALL;
5736 if (render_target) IWineD3DSurface_AddRef(render_target);
5737 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5738 /* Release after the assignment, to prevent device_resource_released()
5739 * from seeing the surface as still in use. */
5740 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5742 /* Render target 0 is special. */
5743 if (!render_target_idx && set_viewport)
5745 /* Set the viewport and scissor rectangles, if requested. Tests show
5746 * that stateblock recording is ignored, the change goes directly
5747 * into the primary stateblock. */
5748 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5749 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5750 device->stateBlock->viewport.X = 0;
5751 device->stateBlock->viewport.Y = 0;
5752 device->stateBlock->viewport.MaxZ = 1.0f;
5753 device->stateBlock->viewport.MinZ = 0.0f;
5754 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5756 device->stateBlock->scissorRect.top = 0;
5757 device->stateBlock->scissorRect.left = 0;
5758 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5759 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5760 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5766 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5769 IWineD3DSurfaceImpl *tmp;
5771 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5773 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5775 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5779 if (This->depth_stencil)
5781 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5782 || This->depth_stencil->Flags & SFLAG_DISCARD)
5784 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5785 This->depth_stencil->currentDesc.Width,
5786 This->depth_stencil->currentDesc.Height);
5787 if (This->depth_stencil == This->onscreen_depth_stencil)
5789 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5790 This->onscreen_depth_stencil = NULL;
5795 tmp = This->depth_stencil;
5796 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5797 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5798 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5800 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5802 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5811 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5812 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5815 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5816 WINED3DLOCKED_RECT lockedRect;
5818 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5819 iface, XHotSpot, YHotSpot, cursor_image);
5821 /* some basic validation checks */
5822 if (This->cursorTexture)
5824 struct wined3d_context *context = context_acquire(This, NULL);
5826 glDeleteTextures(1, &This->cursorTexture);
5828 context_release(context);
5829 This->cursorTexture = 0;
5832 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5833 This->haveHardwareCursor = TRUE;
5835 This->haveHardwareCursor = FALSE;
5839 WINED3DLOCKED_RECT rect;
5841 /* MSDN: Cursor must be A8R8G8B8 */
5842 if (s->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5844 WARN("surface %p has an invalid format.\n", cursor_image);
5845 return WINED3DERR_INVALIDCALL;
5848 /* MSDN: Cursor must be smaller than the display mode */
5849 if (s->currentDesc.Width > This->ddraw_width
5850 || s->currentDesc.Height > This->ddraw_height)
5852 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5853 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5854 return WINED3DERR_INVALIDCALL;
5857 if (!This->haveHardwareCursor) {
5858 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5860 /* Do not store the surface's pointer because the application may
5861 * release it after setting the cursor image. Windows doesn't
5862 * addref the set surface, so we can't do this either without
5863 * creating circular refcount dependencies. Copy out the gl texture
5866 This->cursorWidth = s->currentDesc.Width;
5867 This->cursorHeight = s->currentDesc.Height;
5868 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5870 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5871 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5872 struct wined3d_context *context;
5873 char *mem, *bits = rect.pBits;
5874 GLint intfmt = format_desc->glInternal;
5875 GLint format = format_desc->glFormat;
5876 GLint type = format_desc->glType;
5877 INT height = This->cursorHeight;
5878 INT width = This->cursorWidth;
5879 INT bpp = format_desc->byte_count;
5883 /* Reformat the texture memory (pitch and width can be
5885 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5886 for(i = 0; i < height; i++)
5887 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5888 IWineD3DSurface_UnlockRect(cursor_image);
5890 context = context_acquire(This, NULL);
5894 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5896 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5897 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5900 /* Make sure that a proper texture unit is selected */
5901 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5902 checkGLcall("glActiveTextureARB");
5903 sampler = This->rev_tex_unit_map[0];
5904 if (sampler != WINED3D_UNMAPPED_STAGE)
5906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5908 /* Create a new cursor texture */
5909 glGenTextures(1, &This->cursorTexture);
5910 checkGLcall("glGenTextures");
5911 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5912 checkGLcall("glBindTexture");
5913 /* Copy the bitmap memory into the cursor texture */
5914 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5915 HeapFree(GetProcessHeap(), 0, mem);
5916 checkGLcall("glTexImage2D");
5918 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5920 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5921 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5926 context_release(context);
5930 FIXME("A cursor texture was not returned.\n");
5931 This->cursorTexture = 0;
5936 /* Draw a hardware cursor */
5937 ICONINFO cursorInfo;
5939 /* Create and clear maskBits because it is not needed for
5940 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5942 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5943 (s->currentDesc.Width * s->currentDesc.Height / 8));
5944 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5945 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5946 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5948 cursorInfo.fIcon = FALSE;
5949 cursorInfo.xHotspot = XHotSpot;
5950 cursorInfo.yHotspot = YHotSpot;
5951 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5952 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5953 IWineD3DSurface_UnlockRect(cursor_image);
5954 /* Create our cursor and clean up. */
5955 cursor = CreateIconIndirect(&cursorInfo);
5957 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5958 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5959 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5960 This->hardwareCursor = cursor;
5961 HeapFree(GetProcessHeap(), 0, maskBits);
5965 This->xHotSpot = XHotSpot;
5966 This->yHotSpot = YHotSpot;
5970 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5972 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5974 This->xScreenSpace = XScreenSpace;
5975 This->yScreenSpace = YScreenSpace;
5981 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5983 BOOL oldVisible = This->bCursorVisible;
5986 TRACE("(%p) : visible(%d)\n", This, bShow);
5989 * When ShowCursor is first called it should make the cursor appear at the OS's last
5990 * known cursor position. Because of this, some applications just repetitively call
5991 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5994 This->xScreenSpace = pt.x;
5995 This->yScreenSpace = pt.y;
5997 if (This->haveHardwareCursor) {
5998 This->bCursorVisible = bShow;
6000 SetCursor(This->hardwareCursor);
6006 if (This->cursorTexture)
6007 This->bCursorVisible = bShow;
6013 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6014 TRACE("checking resource %p for eviction\n", resource);
6015 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6016 TRACE("Evicting %p\n", resource);
6017 IWineD3DResource_UnLoad(resource);
6019 IWineD3DResource_Release(resource);
6023 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6025 TRACE("iface %p.\n", iface);
6027 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6028 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6029 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6034 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6036 IWineD3DDeviceImpl *device = surface->resource.device;
6037 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6039 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6040 if(surface->Flags & SFLAG_DIBSECTION) {
6041 /* Release the DC */
6042 SelectObject(surface->hDC, surface->dib.holdbitmap);
6043 DeleteDC(surface->hDC);
6044 /* Release the DIB section */
6045 DeleteObject(surface->dib.DIBsection);
6046 surface->dib.bitmap_data = NULL;
6047 surface->resource.allocatedMemory = NULL;
6048 surface->Flags &= ~SFLAG_DIBSECTION;
6050 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6051 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6052 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6053 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6055 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6056 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6058 surface->pow2Width = surface->pow2Height = 1;
6059 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6060 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6063 if (surface->texture_name)
6065 struct wined3d_context *context = context_acquire(device, NULL);
6067 glDeleteTextures(1, &surface->texture_name);
6069 context_release(context);
6070 surface->texture_name = 0;
6071 surface->Flags &= ~SFLAG_CLIENT;
6073 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6074 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6075 surface->Flags |= SFLAG_NONPOW2;
6077 surface->Flags &= ~SFLAG_NONPOW2;
6079 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6080 surface->resource.allocatedMemory = NULL;
6081 surface->resource.heapMemory = NULL;
6082 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6084 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6086 if (!surface_init_sysmem(surface))
6088 return E_OUTOFMEMORY;
6093 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6094 TRACE("Unloading resource %p\n", resource);
6095 IWineD3DResource_UnLoad(resource);
6096 IWineD3DResource_Release(resource);
6100 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6103 WINED3DDISPLAYMODE m;
6106 /* All Windowed modes are supported, as is leaving the current mode */
6107 if(pp->Windowed) return TRUE;
6108 if(!pp->BackBufferWidth) return TRUE;
6109 if(!pp->BackBufferHeight) return TRUE;
6111 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6112 for(i = 0; i < count; i++) {
6113 memset(&m, 0, sizeof(m));
6114 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6116 ERR("EnumAdapterModes failed\n");
6118 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6119 /* Mode found, it is supported */
6123 /* Mode not found -> not supported */
6127 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6130 const struct wined3d_gl_info *gl_info;
6131 struct wined3d_context *context;
6132 IWineD3DBaseShaderImpl *shader;
6134 context = context_acquire(This, NULL);
6135 gl_info = context->gl_info;
6137 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6138 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6139 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6143 if(This->depth_blt_texture) {
6144 glDeleteTextures(1, &This->depth_blt_texture);
6145 This->depth_blt_texture = 0;
6147 if (This->depth_blt_rb) {
6148 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6149 This->depth_blt_rb = 0;
6150 This->depth_blt_rb_w = 0;
6151 This->depth_blt_rb_h = 0;
6155 This->blitter->free_private(iface);
6156 This->frag_pipe->free_private(iface);
6157 This->shader_backend->shader_free_private(iface);
6158 destroy_dummy_textures(This, gl_info);
6160 context_release(context);
6162 while (This->numContexts)
6164 context_destroy(This, This->contexts[0]);
6166 HeapFree(GetProcessHeap(), 0, swapchain->context);
6167 swapchain->context = NULL;
6168 swapchain->num_contexts = 0;
6171 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6174 struct wined3d_context *context;
6176 IWineD3DSurfaceImpl *target;
6178 /* Recreate the primary swapchain's context */
6179 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6180 if (!swapchain->context)
6182 ERR("Failed to allocate memory for swapchain context array.\n");
6183 return E_OUTOFMEMORY;
6186 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6187 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6189 WARN("Failed to create context.\n");
6190 HeapFree(GetProcessHeap(), 0, swapchain->context);
6194 swapchain->context[0] = context;
6195 swapchain->num_contexts = 1;
6196 create_dummy_textures(This);
6197 context_release(context);
6199 hr = This->shader_backend->shader_alloc_private(iface);
6202 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6206 hr = This->frag_pipe->alloc_private(iface);
6209 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6210 This->shader_backend->shader_free_private(iface);
6214 hr = This->blitter->alloc_private(iface);
6217 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6218 This->frag_pipe->free_private(iface);
6219 This->shader_backend->shader_free_private(iface);
6226 context_acquire(This, NULL);
6227 destroy_dummy_textures(This, context->gl_info);
6228 context_release(context);
6229 context_destroy(This, context);
6230 HeapFree(GetProcessHeap(), 0, swapchain->context);
6231 swapchain->num_contexts = 0;
6235 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6237 IWineD3DSwapChainImpl *swapchain;
6239 BOOL DisplayModeChanged = FALSE;
6240 WINED3DDISPLAYMODE mode;
6241 TRACE("(%p)\n", This);
6243 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6245 ERR("Failed to get the first implicit swapchain\n");
6249 if(!is_display_mode_supported(This, pPresentationParameters)) {
6250 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6251 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6252 pPresentationParameters->BackBufferHeight);
6253 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6254 return WINED3DERR_INVALIDCALL;
6257 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6258 * on an existing gl context, so there's no real need for recreation.
6260 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6262 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6264 TRACE("New params:\n");
6265 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6266 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6267 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6268 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6269 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6270 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6271 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6272 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6273 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6274 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6275 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6276 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6277 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6279 /* No special treatment of these parameters. Just store them */
6280 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6281 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6282 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6283 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6285 /* What to do about these? */
6286 if(pPresentationParameters->BackBufferCount != 0 &&
6287 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6288 ERR("Cannot change the back buffer count yet\n");
6290 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6291 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6292 ERR("Cannot change the back buffer format yet\n");
6294 if(pPresentationParameters->hDeviceWindow != NULL &&
6295 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6296 ERR("Cannot change the device window yet\n");
6298 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6302 TRACE("Creating the depth stencil buffer\n");
6304 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6306 pPresentationParameters->BackBufferWidth,
6307 pPresentationParameters->BackBufferHeight,
6308 pPresentationParameters->AutoDepthStencilFormat,
6309 pPresentationParameters->MultiSampleType,
6310 pPresentationParameters->MultiSampleQuality,
6312 (IWineD3DSurface **)&This->auto_depth_stencil);
6315 ERR("Failed to create the depth stencil buffer\n");
6316 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6317 return WINED3DERR_INVALIDCALL;
6321 if (This->onscreen_depth_stencil)
6323 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6324 This->onscreen_depth_stencil = NULL;
6327 /* Reset the depth stencil */
6328 if (pPresentationParameters->EnableAutoDepthStencil)
6329 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6331 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6333 TRACE("Resetting stateblock\n");
6334 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6335 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6337 delete_opengl_contexts(iface, swapchain);
6339 if(pPresentationParameters->Windowed) {
6340 mode.Width = swapchain->orig_width;
6341 mode.Height = swapchain->orig_height;
6342 mode.RefreshRate = 0;
6343 mode.Format = swapchain->presentParms.BackBufferFormat;
6345 mode.Width = pPresentationParameters->BackBufferWidth;
6346 mode.Height = pPresentationParameters->BackBufferHeight;
6347 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6348 mode.Format = swapchain->presentParms.BackBufferFormat;
6351 /* Should Width == 800 && Height == 0 set 800x600? */
6352 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6353 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6354 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6358 if(!pPresentationParameters->Windowed) {
6359 DisplayModeChanged = TRUE;
6361 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6362 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6364 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6367 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6371 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6373 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6376 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6380 if (This->auto_depth_stencil)
6382 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6385 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6391 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6392 || DisplayModeChanged)
6394 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6396 if (!pPresentationParameters->Windowed)
6398 if(swapchain->presentParms.Windowed) {
6399 /* switch from windowed to fs */
6400 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6401 pPresentationParameters->BackBufferHeight);
6403 /* Fullscreen -> fullscreen mode change */
6404 MoveWindow(swapchain->device_window, 0, 0,
6405 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6409 else if (!swapchain->presentParms.Windowed)
6411 /* Fullscreen -> windowed switch */
6412 swapchain_restore_fullscreen_window(swapchain);
6414 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6415 } else if(!pPresentationParameters->Windowed) {
6416 DWORD style = This->style, exStyle = This->exStyle;
6417 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6418 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6419 * Reset to clear up their mess. Guild Wars also loses the device during that.
6423 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6424 pPresentationParameters->BackBufferHeight);
6425 This->style = style;
6426 This->exStyle = exStyle;
6429 /* Note: No parent needed for initial internal stateblock */
6430 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6431 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6432 else TRACE("Created stateblock %p\n", This->stateBlock);
6433 This->updateStateBlock = This->stateBlock;
6434 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6436 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6438 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6441 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6444 GetClientRect(swapchain->win_handle, &client_rect);
6446 if(!swapchain->presentParms.BackBufferCount)
6448 TRACE("Single buffered rendering\n");
6449 swapchain->render_to_fbo = FALSE;
6451 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6452 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6454 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6455 swapchain->presentParms.BackBufferWidth,
6456 swapchain->presentParms.BackBufferHeight,
6457 client_rect.right, client_rect.bottom);
6458 swapchain->render_to_fbo = TRUE;
6462 TRACE("Rendering directly to GL_BACK\n");
6463 swapchain->render_to_fbo = FALSE;
6467 hr = create_primary_opengl_context(iface, swapchain);
6468 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6470 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6476 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6478 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6480 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6486 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6488 TRACE("(%p) : pParameters %p\n", This, pParameters);
6490 *pParameters = This->createParms;
6494 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6495 IWineD3DSwapChain *swapchain;
6497 TRACE("Relaying to swapchain\n");
6499 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6500 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6501 IWineD3DSwapChain_Release(swapchain);
6505 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6506 IWineD3DSwapChain *swapchain;
6508 TRACE("Relaying to swapchain\n");
6510 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6511 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6512 IWineD3DSwapChain_Release(swapchain);
6517 /** ********************************************************
6518 * Notification functions
6519 ** ********************************************************/
6520 /** This function must be called in the release of a resource when ref == 0,
6521 * the contents of resource must still be correct,
6522 * any handles to other resource held by the caller must be closed
6523 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6524 *****************************************************/
6525 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6527 TRACE("(%p) : Adding resource %p\n", This, resource);
6529 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6532 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6534 TRACE("(%p) : Removing resource %p\n", This, resource);
6536 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6539 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6541 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6544 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6546 context_resource_released(device, resource, type);
6550 case WINED3DRTYPE_SURFACE:
6551 if (!device->d3d_initialized) break;
6553 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6555 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6557 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6558 device->render_targets[i] = NULL;
6562 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6564 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6565 device->depth_stencil = NULL;
6569 case WINED3DRTYPE_TEXTURE:
6570 case WINED3DRTYPE_CUBETEXTURE:
6571 case WINED3DRTYPE_VOLUMETEXTURE:
6572 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6574 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6576 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6577 resource, device->stateBlock, i);
6578 device->stateBlock->textures[i] = NULL;
6581 if (device->updateStateBlock != device->stateBlock
6582 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6584 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6585 resource, device->updateStateBlock, i);
6586 device->updateStateBlock->textures[i] = NULL;
6591 case WINED3DRTYPE_BUFFER:
6592 for (i = 0; i < MAX_STREAMS; ++i)
6594 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6596 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6597 resource, device->stateBlock, i);
6598 device->stateBlock->streamSource[i] = NULL;
6601 if (device->updateStateBlock != device->stateBlock
6602 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6604 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6605 resource, device->updateStateBlock, i);
6606 device->updateStateBlock->streamSource[i] = NULL;
6611 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6613 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6614 resource, device->stateBlock);
6615 device->stateBlock->pIndexData = NULL;
6618 if (device->updateStateBlock != device->stateBlock
6619 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6621 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6622 resource, device->updateStateBlock);
6623 device->updateStateBlock->pIndexData = NULL;
6631 /* Remove the resource from the resourceStore */
6632 device_resource_remove(device, resource);
6634 TRACE("Resource released.\n");
6637 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6639 IWineD3DResourceImpl *resource, *cursor;
6641 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6643 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6644 TRACE("enumerating resource %p\n", resource);
6645 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6646 ret = pCallback((IWineD3DResource *) resource, pData);
6647 if(ret == S_FALSE) {
6648 TRACE("Canceling enumeration\n");
6655 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6658 IWineD3DResourceImpl *resource;
6660 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6662 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6663 if (type == WINED3DRTYPE_SURFACE)
6665 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6667 TRACE("Found surface %p for dc %p.\n", resource, dc);
6668 *surface = (IWineD3DSurface *)resource;
6674 return WINED3DERR_INVALIDCALL;
6677 /**********************************************************
6678 * IWineD3DDevice VTbl follows
6679 **********************************************************/
6681 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6683 /*** IUnknown methods ***/
6684 IWineD3DDeviceImpl_QueryInterface,
6685 IWineD3DDeviceImpl_AddRef,
6686 IWineD3DDeviceImpl_Release,
6687 /*** IWineD3DDevice methods ***/
6688 IWineD3DDeviceImpl_GetParent,
6689 /*** Creation methods**/
6690 IWineD3DDeviceImpl_CreateBuffer,
6691 IWineD3DDeviceImpl_CreateVertexBuffer,
6692 IWineD3DDeviceImpl_CreateIndexBuffer,
6693 IWineD3DDeviceImpl_CreateStateBlock,
6694 IWineD3DDeviceImpl_CreateSurface,
6695 IWineD3DDeviceImpl_CreateRendertargetView,
6696 IWineD3DDeviceImpl_CreateTexture,
6697 IWineD3DDeviceImpl_CreateVolumeTexture,
6698 IWineD3DDeviceImpl_CreateVolume,
6699 IWineD3DDeviceImpl_CreateCubeTexture,
6700 IWineD3DDeviceImpl_CreateQuery,
6701 IWineD3DDeviceImpl_CreateSwapChain,
6702 IWineD3DDeviceImpl_CreateVertexDeclaration,
6703 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6704 IWineD3DDeviceImpl_CreateVertexShader,
6705 IWineD3DDeviceImpl_CreateGeometryShader,
6706 IWineD3DDeviceImpl_CreatePixelShader,
6707 IWineD3DDeviceImpl_CreatePalette,
6708 /*** Odd functions **/
6709 IWineD3DDeviceImpl_Init3D,
6710 IWineD3DDeviceImpl_InitGDI,
6711 IWineD3DDeviceImpl_Uninit3D,
6712 IWineD3DDeviceImpl_UninitGDI,
6713 IWineD3DDeviceImpl_SetMultithreaded,
6714 IWineD3DDeviceImpl_EvictManagedResources,
6715 IWineD3DDeviceImpl_GetAvailableTextureMem,
6716 IWineD3DDeviceImpl_GetBackBuffer,
6717 IWineD3DDeviceImpl_GetCreationParameters,
6718 IWineD3DDeviceImpl_GetDeviceCaps,
6719 IWineD3DDeviceImpl_GetDirect3D,
6720 IWineD3DDeviceImpl_GetDisplayMode,
6721 IWineD3DDeviceImpl_SetDisplayMode,
6722 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6723 IWineD3DDeviceImpl_GetRasterStatus,
6724 IWineD3DDeviceImpl_GetSwapChain,
6725 IWineD3DDeviceImpl_Reset,
6726 IWineD3DDeviceImpl_SetDialogBoxMode,
6727 IWineD3DDeviceImpl_SetCursorProperties,
6728 IWineD3DDeviceImpl_SetCursorPosition,
6729 IWineD3DDeviceImpl_ShowCursor,
6730 /*** Getters and setters **/
6731 IWineD3DDeviceImpl_SetClipPlane,
6732 IWineD3DDeviceImpl_GetClipPlane,
6733 IWineD3DDeviceImpl_SetClipStatus,
6734 IWineD3DDeviceImpl_GetClipStatus,
6735 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6736 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6737 IWineD3DDeviceImpl_SetDepthStencilSurface,
6738 IWineD3DDeviceImpl_GetDepthStencilSurface,
6739 IWineD3DDeviceImpl_SetGammaRamp,
6740 IWineD3DDeviceImpl_GetGammaRamp,
6741 IWineD3DDeviceImpl_SetIndexBuffer,
6742 IWineD3DDeviceImpl_GetIndexBuffer,
6743 IWineD3DDeviceImpl_SetBaseVertexIndex,
6744 IWineD3DDeviceImpl_GetBaseVertexIndex,
6745 IWineD3DDeviceImpl_SetLight,
6746 IWineD3DDeviceImpl_GetLight,
6747 IWineD3DDeviceImpl_SetLightEnable,
6748 IWineD3DDeviceImpl_GetLightEnable,
6749 IWineD3DDeviceImpl_SetMaterial,
6750 IWineD3DDeviceImpl_GetMaterial,
6751 IWineD3DDeviceImpl_SetNPatchMode,
6752 IWineD3DDeviceImpl_GetNPatchMode,
6753 IWineD3DDeviceImpl_SetPaletteEntries,
6754 IWineD3DDeviceImpl_GetPaletteEntries,
6755 IWineD3DDeviceImpl_SetPixelShader,
6756 IWineD3DDeviceImpl_GetPixelShader,
6757 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6758 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6759 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6760 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6761 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6762 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6763 IWineD3DDeviceImpl_SetRenderState,
6764 IWineD3DDeviceImpl_GetRenderState,
6765 IWineD3DDeviceImpl_SetRenderTarget,
6766 IWineD3DDeviceImpl_GetRenderTarget,
6767 IWineD3DDeviceImpl_SetFrontBackBuffers,
6768 IWineD3DDeviceImpl_SetSamplerState,
6769 IWineD3DDeviceImpl_GetSamplerState,
6770 IWineD3DDeviceImpl_SetScissorRect,
6771 IWineD3DDeviceImpl_GetScissorRect,
6772 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6773 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6774 IWineD3DDeviceImpl_SetStreamSource,
6775 IWineD3DDeviceImpl_GetStreamSource,
6776 IWineD3DDeviceImpl_SetStreamSourceFreq,
6777 IWineD3DDeviceImpl_GetStreamSourceFreq,
6778 IWineD3DDeviceImpl_SetTexture,
6779 IWineD3DDeviceImpl_GetTexture,
6780 IWineD3DDeviceImpl_SetTextureStageState,
6781 IWineD3DDeviceImpl_GetTextureStageState,
6782 IWineD3DDeviceImpl_SetTransform,
6783 IWineD3DDeviceImpl_GetTransform,
6784 IWineD3DDeviceImpl_SetVertexDeclaration,
6785 IWineD3DDeviceImpl_GetVertexDeclaration,
6786 IWineD3DDeviceImpl_SetVertexShader,
6787 IWineD3DDeviceImpl_GetVertexShader,
6788 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6789 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6790 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6791 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6792 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6793 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6794 IWineD3DDeviceImpl_SetViewport,
6795 IWineD3DDeviceImpl_GetViewport,
6796 IWineD3DDeviceImpl_MultiplyTransform,
6797 IWineD3DDeviceImpl_ValidateDevice,
6798 IWineD3DDeviceImpl_ProcessVertices,
6799 /*** State block ***/
6800 IWineD3DDeviceImpl_BeginStateBlock,
6801 IWineD3DDeviceImpl_EndStateBlock,
6802 /*** Scene management ***/
6803 IWineD3DDeviceImpl_BeginScene,
6804 IWineD3DDeviceImpl_EndScene,
6805 IWineD3DDeviceImpl_Present,
6806 IWineD3DDeviceImpl_Clear,
6807 IWineD3DDeviceImpl_ClearRendertargetView,
6809 IWineD3DDeviceImpl_SetPrimitiveType,
6810 IWineD3DDeviceImpl_GetPrimitiveType,
6811 IWineD3DDeviceImpl_DrawPrimitive,
6812 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6813 IWineD3DDeviceImpl_DrawPrimitiveUP,
6814 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6815 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6816 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6817 IWineD3DDeviceImpl_DrawRectPatch,
6818 IWineD3DDeviceImpl_DrawTriPatch,
6819 IWineD3DDeviceImpl_DeletePatch,
6820 IWineD3DDeviceImpl_ColorFill,
6821 IWineD3DDeviceImpl_UpdateTexture,
6822 IWineD3DDeviceImpl_UpdateSurface,
6823 IWineD3DDeviceImpl_GetFrontBufferData,
6824 /*** object tracking ***/
6825 IWineD3DDeviceImpl_EnumResources,
6826 IWineD3DDeviceImpl_GetSurfaceFromDC,
6827 IWineD3DDeviceImpl_AcquireFocusWindow,
6828 IWineD3DDeviceImpl_ReleaseFocusWindow,
6831 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6832 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6833 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6835 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6836 const struct fragment_pipeline *fragment_pipeline;
6837 struct shader_caps shader_caps;
6838 struct fragment_caps ffp_caps;
6839 WINED3DDISPLAYMODE mode;
6843 device->lpVtbl = &IWineD3DDevice_Vtbl;
6845 device->wined3d = (IWineD3D *)wined3d;
6846 IWineD3D_AddRef(device->wined3d);
6847 device->adapter = wined3d->adapter_count ? adapter : NULL;
6848 device->parent = parent;
6849 device->device_parent = device_parent;
6850 list_init(&device->resources);
6851 list_init(&device->shaders);
6853 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6854 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6856 /* Get the initial screen setup for ddraw. */
6857 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6860 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6861 IWineD3D_Release(device->wined3d);
6864 device->ddraw_width = mode.Width;
6865 device->ddraw_height = mode.Height;
6866 device->ddraw_format = mode.Format;
6868 /* Save the creation parameters. */
6869 device->createParms.AdapterOrdinal = adapter_idx;
6870 device->createParms.DeviceType = device_type;
6871 device->createParms.hFocusWindow = focus_window;
6872 device->createParms.BehaviorFlags = flags;
6874 device->devType = device_type;
6875 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6877 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6878 device->shader_backend = adapter->shader_backend;
6880 if (device->shader_backend)
6882 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6883 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6884 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6885 device->vs_clipping = shader_caps.VSClipping;
6887 fragment_pipeline = adapter->fragment_pipe;
6888 device->frag_pipe = fragment_pipeline;
6889 if (fragment_pipeline)
6891 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6892 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6894 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6895 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6898 ERR("Failed to compile state table, hr %#x.\n", hr);
6899 IWineD3D_Release(device->wined3d);
6903 device->blitter = adapter->blitter;
6909 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6910 DWORD rep = This->StateTable[state].representative;
6911 struct wined3d_context *context;
6916 for(i = 0; i < This->numContexts; i++) {
6917 context = This->contexts[i];
6918 if(isStateDirty(context, rep)) continue;
6920 context->dirtyArray[context->numDirtyEntries++] = rep;
6921 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6922 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6923 context->isStateDirty[idx] |= (1 << shift);
6927 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6929 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6930 *width = context->current_rt->pow2Width;
6931 *height = context->current_rt->pow2Height;
6934 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6936 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6937 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6938 * current context's drawable, which is the size of the back buffer of the swapchain
6939 * the active context belongs to. */
6940 *width = swapchain->presentParms.BackBufferWidth;
6941 *height = swapchain->presentParms.BackBufferHeight;
6944 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6945 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6947 if (device->filter_messages)
6949 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6950 window, message, wparam, lparam);
6951 return DefWindowProcW(window, message, wparam, lparam);
6954 if (message == WM_DESTROY)
6956 TRACE("unregister window %p.\n", window);
6957 wined3d_unregister_window(window);
6959 if (device->focus_window == window) device->focus_window = NULL;
6960 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6963 return CallWindowProcW(proc, window, message, wparam, lparam);