2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 GLuint buffer_object = 0;
195 const BYTE *data = NULL;
200 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201 element, i + 1, declaration->element_count);
203 if (!This->stateBlock->streamSource[element->input_slot]) continue;
205 stride = This->stateBlock->streamStride[element->input_slot];
206 if (This->stateBlock->streamIsUP)
208 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
215 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot],
216 &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot],
228 &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->streamIsUP)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
319 struct wined3d_event_query *query;
321 if (!(map & 1)) continue;
323 element = &stream_info->elements[i];
324 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
325 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
327 /* If PreLoad dropped the buffer object, update the stream info. */
328 if (buffer->buffer_object != element->buffer_object)
330 element->buffer_object = 0;
331 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 query = ((struct wined3d_buffer *) buffer)->query;
337 This->buffer_queries[This->num_buffer_queries++] = query;
343 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
344 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
346 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
347 e->format_desc = format_desc;
348 e->stride = strided->dwStride;
349 e->data = strided->lpData;
351 e->buffer_object = 0;
354 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
355 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
359 memset(stream_info, 0, sizeof(*stream_info));
361 if (strided->position.lpData)
362 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
363 if (strided->normal.lpData)
364 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
365 if (strided->diffuse.lpData)
366 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
367 if (strided->specular.lpData)
368 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
370 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
372 if (strided->texCoords[i].lpData)
373 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
374 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
377 stream_info->position_transformed = strided->position_transformed;
379 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
381 if (!stream_info->elements[i].format_desc) continue;
383 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
384 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
386 stream_info->swizzle_map |= 1 << i;
388 stream_info->use_map |= 1 << i;
392 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
394 TRACE("Strided Data:\n");
395 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
412 /* Context activation is done by the caller. */
413 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
415 struct wined3d_stream_info *stream_info = &device->strided_streams;
416 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
417 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
420 if (device->up_strided)
422 /* Note: this is a ddraw fixed-function code path. */
423 TRACE("=============================== Strided Input ================================\n");
424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
429 TRACE("============================= Vertex Declaration =============================\n");
430 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
433 if (vs && !stream_info->position_transformed)
435 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
438 device->useDrawStridedSlow = TRUE;
442 device->useDrawStridedSlow = FALSE;
447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
453 device->useDrawStridedSlow = TRUE;
457 device->useDrawStridedSlow = FALSE;
462 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
464 IWineD3DBaseTextureImpl *texture;
465 enum WINED3DSRGB srgb;
467 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
468 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
469 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
472 void device_preload_textures(IWineD3DDeviceImpl *device)
474 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
477 if (use_vs(stateblock))
479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
486 if (use_ps(stateblock))
488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
490 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
491 device_preload_texture(stateblock, i);
496 WORD ffu_map = device->fixed_function_usage_map;
498 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
501 device_preload_texture(stateblock, i);
506 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
508 struct wined3d_context **new_array;
510 TRACE("Adding context %p.\n", context);
512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
517 ERR("Failed to grow the context array.\n");
521 new_array[device->numContexts++] = context;
522 device->contexts = new_array;
526 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
528 struct wined3d_context **new_array;
532 TRACE("Removing context %p.\n", context);
534 for (i = 0; i < device->numContexts; ++i)
536 if (device->contexts[i] == context)
545 ERR("Context %p doesn't exist in context array.\n", context);
549 if (!--device->numContexts)
551 HeapFree(GetProcessHeap(), 0, device->contexts);
552 device->contexts = NULL;
556 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
557 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
560 ERR("Failed to shrink context array. Oh well.\n");
564 device->contexts = new_array;
567 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
569 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
570 WINED3DVIEWPORT *vp = &stateblock->viewport;
572 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
574 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
576 IntersectRect(rect, rect, &stateblock->scissorRect);
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
597 /* partial draw rect */
598 if (draw_rect->left || draw_rect->top
599 || draw_rect->right < target->currentDesc.Width
600 || draw_rect->bottom < target->currentDesc.Height)
603 /* partial clear rect */
604 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
605 || clear_rect->right < target->currentDesc.Width
606 || clear_rect->bottom < target->currentDesc.Height))
612 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
613 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
615 RECT current_rect, r;
617 if (ds->Flags & location)
618 SetRect(¤t_rect, 0, 0,
619 ds->ds_current_size.cx,
620 ds->ds_current_size.cy);
622 SetRectEmpty(¤t_rect);
624 IntersectRect(&r, draw_rect, ¤t_rect);
625 if (EqualRect(&r, draw_rect))
627 /* current_rect ⊇ draw_rect, modify only. */
628 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
632 if (EqualRect(&r, ¤t_rect))
634 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
638 /* Full clear, modify only. */
639 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 IntersectRect(&r, draw_rect, clear_rect);
644 if (EqualRect(&r, draw_rect))
646 /* clear_rect ⊇ draw_rect, modify only. */
647 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
653 surface_load_ds_location(ds, context, location);
654 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
657 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
658 UINT rect_count, const WINED3DRECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
660 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
661 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
662 IWineD3DSurfaceImpl *target = rts[0];
663 UINT drawable_width, drawable_height;
664 struct wined3d_context *context;
665 GLbitfield clear_mask = 0;
669 device_get_draw_rect(device, &draw_rect);
671 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
672 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
673 * for the cleared parts, and the untouched parts.
675 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
676 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
677 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
678 * checking all this if the dest surface is in the drawable anyway. */
679 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, &draw_rect, clear_rect))
681 for (i = 0; i < rt_count; ++i)
683 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
687 context = context_acquire(device, target);
690 context_release(context);
691 WARN("Invalid context, skipping clear.\n");
695 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
697 target->get_drawable_size(context, &drawable_width, &drawable_height);
701 /* Only set the values up once, as they are not changing. */
702 if (flags & WINED3DCLEAR_STENCIL)
704 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
706 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
707 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
710 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
711 glClearStencil(stencil);
712 checkGLcall("glClearStencil");
713 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
716 if (flags & WINED3DCLEAR_ZBUFFER)
718 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
720 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
721 device_switch_onscreen_ds(device, context, depth_stencil);
722 prepare_ds_clear(depth_stencil, context, location, &draw_rect, rect_count, clear_rect);
723 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
725 glDepthMask(GL_TRUE);
726 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
728 checkGLcall("glClearDepth");
729 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
732 if (flags & WINED3DCLEAR_TARGET)
734 for (i = 0; i < rt_count; ++i)
736 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
739 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
744 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
745 checkGLcall("glClearColor");
746 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
751 if (context->render_offscreen)
753 glScissor(draw_rect.left, draw_rect.top,
754 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
758 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
759 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
761 checkGLcall("glScissor");
763 checkGLcall("glClear");
769 /* Now process each rect in turn. */
770 for (i = 0; i < rect_count; ++i)
772 /* Note that GL uses lower left, width/height. */
773 IntersectRect(¤t_rect, &draw_rect, &clear_rect[i]);
775 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
776 wine_dbgstr_rect(&clear_rect[i]),
777 wine_dbgstr_rect(¤t_rect));
779 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
780 * The rectangle is not cleared, no error is returned, but further rectanlges are
781 * still cleared if they are valid. */
782 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
784 TRACE("Rectangle with negative dimensions, ignoring.\n");
788 if (context->render_offscreen)
790 glScissor(current_rect.left, current_rect.top,
791 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
795 glScissor(current_rect.left, drawable_height - current_rect.bottom,
796 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 checkGLcall("glScissor");
801 checkGLcall("glClear");
807 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
808 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
809 wglFlush(); /* Flush to ensure ordering across contexts. */
811 context_release(context);
817 /**********************************************************
818 * IUnknown parts follows
819 **********************************************************/
821 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
825 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
826 if (IsEqualGUID(riid, &IID_IUnknown)
827 || IsEqualGUID(riid, &IID_IWineD3DBase)
828 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
829 IUnknown_AddRef(iface);
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
889 /**********************************************************
890 * IWineD3DDevice implementation follows
891 **********************************************************/
892 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
894 *pParent = This->parent;
895 IUnknown_AddRef(This->parent);
899 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
900 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
903 struct wined3d_buffer *object;
906 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
908 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
911 ERR("Failed to allocate memory\n");
912 return E_OUTOFMEMORY;
915 FIXME("Ignoring access flags (pool)\n");
917 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
918 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
921 WARN("Failed to initialize buffer, hr %#x.\n", hr);
922 HeapFree(GetProcessHeap(), 0, object);
925 object->desc = *desc;
927 TRACE("Created buffer %p.\n", object);
929 *buffer = (IWineD3DBuffer *)object;
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
935 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
936 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
939 struct wined3d_buffer *object;
942 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
943 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
945 if (Pool == WINED3DPOOL_SCRATCH)
947 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
948 * anyway, SCRATCH vertex buffers aren't usable anywhere
950 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
951 *ppVertexBuffer = NULL;
952 return WINED3DERR_INVALIDCALL;
955 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
958 ERR("Out of memory\n");
959 *ppVertexBuffer = NULL;
960 return WINED3DERR_OUTOFVIDEOMEMORY;
963 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
964 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
967 WARN("Failed to initialize buffer, hr %#x.\n", hr);
968 HeapFree(GetProcessHeap(), 0, object);
972 TRACE("Created buffer %p.\n", object);
973 *ppVertexBuffer = (IWineD3DBuffer *)object;
978 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
979 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
980 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 struct wined3d_buffer *object;
986 TRACE("(%p) Creating index buffer\n", This);
988 /* Allocate the storage for the device */
989 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
992 ERR("Out of memory\n");
993 *ppIndexBuffer = NULL;
994 return WINED3DERR_OUTOFVIDEOMEMORY;
997 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
998 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1002 WARN("Failed to initialize buffer, hr %#x\n", hr);
1003 HeapFree(GetProcessHeap(), 0, object);
1007 TRACE("Created buffer %p.\n", object);
1009 *ppIndexBuffer = (IWineD3DBuffer *) object;
1014 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1015 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
1017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1018 IWineD3DStateBlockImpl *object;
1021 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1024 ERR("Failed to allocate stateblock memory.\n");
1025 return E_OUTOFMEMORY;
1028 hr = stateblock_init(object, This, type);
1031 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1032 HeapFree(GetProcessHeap(), 0, object);
1036 TRACE("Created stateblock %p.\n", object);
1037 *stateblock = (IWineD3DStateBlock *)object;
1042 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1043 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
1044 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
1045 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048 IWineD3DSurfaceImpl *object;
1051 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1052 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1053 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1054 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1055 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1057 if (Impl == SURFACE_OPENGL && !This->adapter)
1059 ERR("OpenGL surfaces are not available without OpenGL.\n");
1060 return WINED3DERR_NOTAVAILABLE;
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1066 ERR("Failed to allocate surface memory.\n");
1067 return WINED3DERR_OUTOFVIDEOMEMORY;
1070 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1071 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1074 WARN("Failed to initialize surface, returning %#x.\n", hr);
1075 HeapFree(GetProcessHeap(), 0, object);
1079 TRACE("(%p) : Created surface %p\n", This, object);
1081 *ppSurface = (IWineD3DSurface *)object;
1086 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1087 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1089 struct wined3d_rendertarget_view *object;
1091 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1092 iface, resource, parent, rendertarget_view);
1094 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1097 ERR("Failed to allocate memory\n");
1098 return E_OUTOFMEMORY;
1101 wined3d_rendertarget_view_init(object, resource, parent);
1103 TRACE("Created render target view %p.\n", object);
1104 *rendertarget_view = (IWineD3DRendertargetView *)object;
1109 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1110 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1111 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1114 IWineD3DTextureImpl *object;
1117 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1118 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1119 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1121 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1124 ERR("Out of memory\n");
1126 return WINED3DERR_OUTOFVIDEOMEMORY;
1129 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1132 WARN("Failed to initialize texture, returning %#x\n", hr);
1133 HeapFree(GetProcessHeap(), 0, object);
1138 *ppTexture = (IWineD3DTexture *)object;
1140 TRACE("(%p) : Created texture %p\n", This, object);
1145 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1146 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1147 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1150 IWineD3DVolumeTextureImpl *object;
1153 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1154 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1156 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1159 ERR("Out of memory\n");
1160 *ppVolumeTexture = NULL;
1161 return WINED3DERR_OUTOFVIDEOMEMORY;
1164 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1167 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1168 HeapFree(GetProcessHeap(), 0, object);
1169 *ppVolumeTexture = NULL;
1173 TRACE("(%p) : Created volume texture %p.\n", This, object);
1174 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1179 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1180 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1181 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1184 IWineD3DVolumeImpl *object;
1187 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1188 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1190 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1193 ERR("Out of memory\n");
1195 return WINED3DERR_OUTOFVIDEOMEMORY;
1198 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1201 WARN("Failed to initialize volume, returning %#x.\n", hr);
1202 HeapFree(GetProcessHeap(), 0, object);
1206 TRACE("(%p) : Created volume %p.\n", This, object);
1207 *ppVolume = (IWineD3DVolume *)object;
1212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1213 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1214 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1217 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1220 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1223 ERR("Out of memory\n");
1224 *ppCubeTexture = NULL;
1225 return WINED3DERR_OUTOFVIDEOMEMORY;
1228 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1231 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1232 HeapFree(GetProcessHeap(), 0, object);
1233 *ppCubeTexture = NULL;
1237 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1238 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1243 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1244 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1247 IWineD3DQueryImpl *object;
1250 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1252 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1255 ERR("Failed to allocate query memory.\n");
1256 return E_OUTOFMEMORY;
1259 hr = query_init(object, This, type, parent);
1262 WARN("Failed to initialize query, hr %#x.\n", hr);
1263 HeapFree(GetProcessHeap(), 0, object);
1267 TRACE("Created query %p.\n", object);
1268 *query = (IWineD3DQuery *)object;
1273 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1274 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1275 IUnknown *parent, WINED3DSURFTYPE surface_type)
1277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1278 IWineD3DSwapChainImpl *object;
1281 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1282 iface, present_parameters, swapchain, parent, surface_type);
1284 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1287 ERR("Failed to allocate swapchain memory.\n");
1288 return E_OUTOFMEMORY;
1291 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1294 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1295 HeapFree(GetProcessHeap(), 0, object);
1299 TRACE("Created swapchain %p.\n", object);
1300 *swapchain = (IWineD3DSwapChain *)object;
1305 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1306 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 TRACE("(%p)\n", This);
1310 return This->NumberOfSwapChains;
1313 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1315 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1317 if(iSwapChain < This->NumberOfSwapChains) {
1318 *pSwapChain = This->swapchains[iSwapChain];
1319 IWineD3DSwapChain_AddRef(*pSwapChain);
1320 TRACE("(%p) returning %p\n", This, *pSwapChain);
1323 TRACE("Swapchain out of range\n");
1325 return WINED3DERR_INVALIDCALL;
1329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1330 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1331 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1334 IWineD3DVertexDeclarationImpl *object = NULL;
1337 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1338 iface, declaration, parent, elements, element_count);
1340 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1343 ERR("Failed to allocate vertex declaration memory.\n");
1344 return E_OUTOFMEMORY;
1347 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1350 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1351 HeapFree(GetProcessHeap(), 0, object);
1355 TRACE("Created vertex declaration %p.\n", object);
1356 *declaration = (IWineD3DVertexDeclaration *)object;
1361 struct wined3d_fvf_convert_state
1363 const struct wined3d_gl_info *gl_info;
1364 WINED3DVERTEXELEMENT *elements;
1369 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1370 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1372 WINED3DVERTEXELEMENT *elements = state->elements;
1373 const struct wined3d_format_desc *format_desc;
1374 UINT offset = state->offset;
1375 UINT idx = state->idx;
1377 elements[idx].format = format;
1378 elements[idx].input_slot = 0;
1379 elements[idx].offset = offset;
1380 elements[idx].output_slot = 0;
1381 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1382 elements[idx].usage = usage;
1383 elements[idx].usage_idx = usage_idx;
1385 format_desc = getFormatDescEntry(format, state->gl_info);
1386 state->offset += format_desc->component_count * format_desc->component_size;
1390 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1391 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1393 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1394 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1395 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1396 BOOL has_blend_idx = has_blend &&
1397 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1398 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1399 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1400 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1401 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1402 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1403 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1405 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1406 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1407 struct wined3d_fvf_convert_state state;
1410 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1411 if (has_blend_idx) num_blends--;
1413 /* Compute declaration size */
1414 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1415 has_psize + has_diffuse + has_specular + num_textures;
1417 state.gl_info = gl_info;
1418 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1419 if (!state.elements) return ~0U;
1425 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1426 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1427 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1428 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1430 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1433 if (has_blend && (num_blends > 0))
1435 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1436 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1442 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1445 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1448 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1451 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1454 ERR("Unexpected amount of blend values: %u\n", num_blends);
1461 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1462 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1463 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1464 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1465 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1467 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1470 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1471 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1472 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1473 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1475 for (idx = 0; idx < num_textures; ++idx)
1477 switch ((texcoords >> (idx * 2)) & 0x03)
1479 case WINED3DFVF_TEXTUREFORMAT1:
1480 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 case WINED3DFVF_TEXTUREFORMAT2:
1483 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1485 case WINED3DFVF_TEXTUREFORMAT3:
1486 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1488 case WINED3DFVF_TEXTUREFORMAT4:
1489 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1494 *ppVertexElements = state.elements;
1498 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1499 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1500 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1503 WINED3DVERTEXELEMENT *elements;
1507 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1509 size = ConvertFvfToDeclaration(This, fvf, &elements);
1510 if (size == ~0U) return E_OUTOFMEMORY;
1512 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1513 HeapFree(GetProcessHeap(), 0, elements);
1517 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1518 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1519 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1520 const struct wined3d_parent_ops *parent_ops)
1522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1523 IWineD3DVertexShaderImpl *object;
1526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1529 ERR("Failed to allocate shader memory.\n");
1530 return E_OUTOFMEMORY;
1533 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1536 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1537 HeapFree(GetProcessHeap(), 0, object);
1541 TRACE("Created vertex shader %p.\n", object);
1542 *ppVertexShader = (IWineD3DVertexShader *)object;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1548 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1549 IWineD3DGeometryShader **shader, IUnknown *parent,
1550 const struct wined3d_parent_ops *parent_ops)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 struct wined3d_geometryshader *object;
1556 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1559 ERR("Failed to allocate shader memory.\n");
1560 return E_OUTOFMEMORY;
1563 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1566 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1567 HeapFree(GetProcessHeap(), 0, object);
1571 TRACE("Created geometry shader %p.\n", object);
1572 *shader = (IWineD3DGeometryShader *)object;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1578 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1579 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1580 const struct wined3d_parent_ops *parent_ops)
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 IWineD3DPixelShaderImpl *object;
1586 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1589 ERR("Failed to allocate shader memory.\n");
1590 return E_OUTOFMEMORY;
1593 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1596 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1597 HeapFree(GetProcessHeap(), 0, object);
1601 TRACE("Created pixel shader %p.\n", object);
1602 *ppPixelShader = (IWineD3DPixelShader *)object;
1607 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1608 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1611 IWineD3DPaletteImpl *object;
1614 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1615 iface, Flags, PalEnt, Palette, Parent);
1617 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1620 ERR("Failed to allocate palette memory.\n");
1621 return E_OUTOFMEMORY;
1624 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1627 WARN("Failed to initialize palette, hr %#x.\n", hr);
1628 HeapFree(GetProcessHeap(), 0, object);
1632 TRACE("Created palette %p.\n", object);
1633 *Palette = (IWineD3DPalette *)object;
1638 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1642 HDC dcb = NULL, dcs = NULL;
1643 WINEDDCOLORKEY colorkey;
1645 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1648 GetObjectA(hbm, sizeof(BITMAP), &bm);
1649 dcb = CreateCompatibleDC(NULL);
1651 SelectObject(dcb, hbm);
1655 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1656 * couldn't be loaded
1658 memset(&bm, 0, sizeof(bm));
1663 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1664 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1665 NULL, &wined3d_null_parent_ops);
1667 ERR("Wine logo requested, but failed to create surface\n");
1672 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1673 if(FAILED(hr)) goto out;
1674 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1675 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1677 colorkey.dwColorSpaceLowValue = 0;
1678 colorkey.dwColorSpaceHighValue = 0;
1679 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1681 /* Fill the surface with a white color to show that wined3d is there */
1682 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1686 if (dcb) DeleteDC(dcb);
1687 if (hbm) DeleteObject(hbm);
1690 /* Context activation is done by the caller. */
1691 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1693 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1695 /* Under DirectX you can have texture stage operations even if no texture is
1696 bound, whereas opengl will only do texture operations when a valid texture is
1697 bound. We emulate this by creating dummy textures and binding them to each
1698 texture stage, but disable all stages by default. Hence if a stage is enabled
1699 then the default texture will kick in until replaced by a SetTexture call */
1702 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1704 /* The dummy texture does not have client storage backing */
1705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1709 for (i = 0; i < gl_info->limits.textures; ++i)
1711 GLubyte white = 255;
1713 /* Make appropriate texture active */
1714 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1715 checkGLcall("glActiveTextureARB");
1717 /* Generate an opengl texture name */
1718 glGenTextures(1, &This->dummyTextureName[i]);
1719 checkGLcall("glGenTextures");
1720 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1722 /* Generate a dummy 2d texture (not using 1d because they cause many
1723 * DRI drivers fall back to sw) */
1724 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1725 checkGLcall("glBindTexture");
1727 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1728 checkGLcall("glTexImage2D");
1731 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1733 /* Reenable because if supported it is enabled by default */
1734 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1735 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1741 /* Context activation is done by the caller. */
1742 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1745 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1746 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1749 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1752 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1754 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1756 if (!wined3d_register_window(window, device))
1758 ERR("Failed to register window %p.\n", window);
1762 device->focus_window = window;
1763 SetForegroundWindow(window);
1768 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1770 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1772 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1773 device->focus_window = NULL;
1776 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1777 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1780 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1781 IWineD3DSwapChainImpl *swapchain = NULL;
1782 struct wined3d_context *context;
1787 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1789 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1790 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1792 TRACE("(%p) : Creating stateblock\n", This);
1793 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1794 hr = IWineD3DDevice_CreateStateBlock(iface,
1796 (IWineD3DStateBlock **)&This->stateBlock,
1798 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1799 WARN("Failed to create stateblock\n");
1802 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1803 This->updateStateBlock = This->stateBlock;
1804 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1806 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1807 sizeof(*This->render_targets) * gl_info->limits.buffers);
1808 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1809 sizeof(GLenum) * gl_info->limits.buffers);
1811 This->NumberOfPalettes = 1;
1812 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1813 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1814 ERR("Out of memory!\n");
1818 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1819 if(!This->palettes[0]) {
1820 ERR("Out of memory!\n");
1824 for (i = 0; i < 256; ++i) {
1825 This->palettes[0][i].peRed = 0xFF;
1826 This->palettes[0][i].peGreen = 0xFF;
1827 This->palettes[0][i].peBlue = 0xFF;
1828 This->palettes[0][i].peFlags = 0xFF;
1830 This->currentPalette = 0;
1832 /* Initialize the texture unit mapping to a 1:1 mapping */
1833 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1835 if (state < gl_info->limits.fragment_samplers)
1837 This->texUnitMap[state] = state;
1838 This->rev_tex_unit_map[state] = state;
1840 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1841 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1845 /* Setup the implicit swapchain. This also initializes a context. */
1846 TRACE("Creating implicit swapchain\n");
1847 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1848 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1851 WARN("Failed to create implicit swapchain\n");
1855 This->NumberOfSwapChains = 1;
1856 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1857 if(!This->swapchains) {
1858 ERR("Out of memory!\n");
1861 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1863 if (swapchain->back_buffers && swapchain->back_buffers[0])
1865 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1866 This->render_targets[0] = swapchain->back_buffers[0];
1870 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1871 This->render_targets[0] = swapchain->front_buffer;
1873 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1875 /* Depth Stencil support */
1876 This->depth_stencil = This->auto_depth_stencil;
1877 if (This->depth_stencil)
1878 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1880 hr = This->shader_backend->shader_alloc_private(iface);
1882 TRACE("Shader private data couldn't be allocated\n");
1885 hr = This->frag_pipe->alloc_private(iface);
1887 TRACE("Fragment pipeline private data couldn't be allocated\n");
1890 hr = This->blitter->alloc_private(iface);
1892 TRACE("Blitter private data couldn't be allocated\n");
1896 /* Set up some starting GL setup */
1898 /* Setup all the devices defaults */
1899 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1901 context = context_acquire(This, swapchain->front_buffer);
1903 create_dummy_textures(This);
1907 /* Initialize the current view state */
1908 This->view_ident = 1;
1909 This->contexts[0]->last_was_rhw = 0;
1910 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1911 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1913 switch(wined3d_settings.offscreen_rendering_mode) {
1915 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1918 case ORM_BACKBUFFER:
1920 if (context_get_current()->aux_buffers > 0)
1922 TRACE("Using auxilliary buffer for offscreen rendering\n");
1923 This->offscreenBuffer = GL_AUX0;
1925 TRACE("Using back buffer for offscreen rendering\n");
1926 This->offscreenBuffer = GL_BACK;
1931 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1934 context_release(context);
1936 /* Clear the screen */
1937 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1938 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1941 This->d3d_initialized = TRUE;
1943 if(wined3d_settings.logo) {
1944 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1946 This->highest_dirty_ps_const = 0;
1947 This->highest_dirty_vs_const = 0;
1951 HeapFree(GetProcessHeap(), 0, This->render_targets);
1952 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1953 HeapFree(GetProcessHeap(), 0, This->swapchains);
1954 This->NumberOfSwapChains = 0;
1955 if(This->palettes) {
1956 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1957 HeapFree(GetProcessHeap(), 0, This->palettes);
1959 This->NumberOfPalettes = 0;
1961 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1963 if(This->stateBlock) {
1964 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1965 This->stateBlock = NULL;
1967 if (This->blit_priv) {
1968 This->blitter->free_private(iface);
1970 if (This->fragment_priv) {
1971 This->frag_pipe->free_private(iface);
1973 if (This->shader_priv) {
1974 This->shader_backend->shader_free_private(iface);
1979 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1980 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1983 IWineD3DSwapChainImpl *swapchain = NULL;
1986 /* Setup the implicit swapchain */
1987 TRACE("Creating implicit swapchain\n");
1988 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1989 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1992 WARN("Failed to create implicit swapchain\n");
1996 This->NumberOfSwapChains = 1;
1997 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1998 if(!This->swapchains) {
1999 ERR("Out of memory!\n");
2002 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2006 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2010 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2012 IWineD3DResource_UnLoad(resource);
2013 IWineD3DResource_Release(resource);
2017 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2018 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2021 const struct wined3d_gl_info *gl_info;
2022 struct wined3d_context *context;
2025 TRACE("(%p)\n", This);
2027 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2029 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2030 * it was created. Thus make sure a context is active for the glDelete* calls
2032 context = context_acquire(This, NULL);
2033 gl_info = context->gl_info;
2035 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2037 /* Unload resources */
2038 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2040 TRACE("Deleting high order patches\n");
2041 for(i = 0; i < PATCHMAP_SIZE; i++) {
2042 struct list *e1, *e2;
2043 struct WineD3DRectPatch *patch;
2044 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2045 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2046 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2050 /* Delete the mouse cursor texture */
2051 if(This->cursorTexture) {
2053 glDeleteTextures(1, &This->cursorTexture);
2055 This->cursorTexture = 0;
2058 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2059 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2061 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2062 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2065 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2066 * private data, it might contain opengl pointers
2068 if(This->depth_blt_texture) {
2070 glDeleteTextures(1, &This->depth_blt_texture);
2072 This->depth_blt_texture = 0;
2074 if (This->depth_blt_rb) {
2076 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2078 This->depth_blt_rb = 0;
2079 This->depth_blt_rb_w = 0;
2080 This->depth_blt_rb_h = 0;
2083 /* Release the update stateblock */
2084 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2085 if(This->updateStateBlock != This->stateBlock)
2086 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2088 This->updateStateBlock = NULL;
2090 { /* because were not doing proper internal refcounts releasing the primary state block
2091 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2092 to set this->stateBlock = NULL; first */
2093 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2094 This->stateBlock = NULL;
2096 /* Release the stateblock */
2097 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2098 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2102 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2103 This->blitter->free_private(iface);
2104 This->frag_pipe->free_private(iface);
2105 This->shader_backend->shader_free_private(iface);
2107 /* Release the buffers (with sanity checks)*/
2108 if (This->onscreen_depth_stencil)
2110 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2111 This->onscreen_depth_stencil = NULL;
2114 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2115 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2117 if (This->auto_depth_stencil != This->depth_stencil)
2118 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2120 This->depth_stencil = NULL;
2122 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2123 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2125 TRACE("Setting rendertarget to NULL\n");
2126 This->render_targets[0] = NULL;
2128 if (This->auto_depth_stencil)
2130 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2132 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2134 This->auto_depth_stencil = NULL;
2137 context_release(context);
2139 for(i=0; i < This->NumberOfSwapChains; i++) {
2140 TRACE("Releasing the implicit swapchain %d\n", i);
2141 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2142 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2146 HeapFree(GetProcessHeap(), 0, This->swapchains);
2147 This->swapchains = NULL;
2148 This->NumberOfSwapChains = 0;
2150 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2151 HeapFree(GetProcessHeap(), 0, This->palettes);
2152 This->palettes = NULL;
2153 This->NumberOfPalettes = 0;
2155 HeapFree(GetProcessHeap(), 0, This->render_targets);
2156 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2157 This->render_targets = NULL;
2158 This->draw_buffers = NULL;
2160 This->d3d_initialized = FALSE;
2165 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2169 for(i=0; i < This->NumberOfSwapChains; i++) {
2170 TRACE("Releasing the implicit swapchain %d\n", i);
2171 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2172 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2176 HeapFree(GetProcessHeap(), 0, This->swapchains);
2177 This->swapchains = NULL;
2178 This->NumberOfSwapChains = 0;
2182 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2183 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2184 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2186 * There is no way to deactivate thread safety once it is enabled.
2188 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2191 /*For now just store the flag(needed in case of ddraw) */
2192 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2195 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2196 const WINED3DDISPLAYMODE* pMode) {
2198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2199 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2203 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2205 /* Resize the screen even without a window:
2206 * The app could have unset it with SetCooperativeLevel, but not called
2207 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2208 * but we don't have any hwnd
2211 memset(&devmode, 0, sizeof(devmode));
2212 devmode.dmSize = sizeof(devmode);
2213 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2214 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2215 devmode.dmPelsWidth = pMode->Width;
2216 devmode.dmPelsHeight = pMode->Height;
2218 devmode.dmDisplayFrequency = pMode->RefreshRate;
2219 if (pMode->RefreshRate != 0) {
2220 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2223 /* Only change the mode if necessary */
2224 if( (This->ddraw_width == pMode->Width) &&
2225 (This->ddraw_height == pMode->Height) &&
2226 (This->ddraw_format == pMode->Format) &&
2227 (pMode->RefreshRate == 0) ) {
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2232 if (ret != DISP_CHANGE_SUCCESSFUL) {
2233 if(devmode.dmDisplayFrequency != 0) {
2234 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2235 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2236 devmode.dmDisplayFrequency = 0;
2237 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2239 if(ret != DISP_CHANGE_SUCCESSFUL) {
2240 return WINED3DERR_NOTAVAILABLE;
2244 /* Store the new values */
2245 This->ddraw_width = pMode->Width;
2246 This->ddraw_height = pMode->Height;
2247 This->ddraw_format = pMode->Format;
2249 /* And finally clip mouse to our screen */
2250 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2251 ClipCursor(&clip_rc);
2256 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2258 *ppD3D = This->wined3d;
2259 TRACE("Returning %p.\n", *ppD3D);
2260 IWineD3D_AddRef(*ppD3D);
2264 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2267 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2268 (This->adapter->TextureRam/(1024*1024)),
2269 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2270 /* return simulated texture memory left */
2271 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2275 * Get / Set Stream Source
2277 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2278 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2281 IWineD3DBuffer *oldSrc;
2283 if (StreamNumber >= MAX_STREAMS) {
2284 WARN("Stream out of range %d\n", StreamNumber);
2285 return WINED3DERR_INVALIDCALL;
2286 } else if(OffsetInBytes & 0x3) {
2287 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2288 return WINED3DERR_INVALIDCALL;
2291 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2292 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2294 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2296 if(oldSrc == pStreamData &&
2297 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2298 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2299 TRACE("Application is setting the old values over, nothing to do\n");
2303 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2305 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2306 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2309 /* Handle recording of state blocks */
2310 if (This->isRecordingState) {
2311 TRACE("Recording... not performing anything\n");
2312 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2313 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2317 if (pStreamData != NULL) {
2318 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2319 IWineD3DBuffer_AddRef(pStreamData);
2321 if (oldSrc != NULL) {
2322 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2323 IWineD3DBuffer_Release(oldSrc);
2326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2332 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2337 This->stateBlock->streamSource[StreamNumber],
2338 This->stateBlock->streamOffset[StreamNumber],
2339 This->stateBlock->streamStride[StreamNumber]);
2341 if (StreamNumber >= MAX_STREAMS) {
2342 WARN("Stream out of range %d\n", StreamNumber);
2343 return WINED3DERR_INVALIDCALL;
2345 *pStream = This->stateBlock->streamSource[StreamNumber];
2346 *pStride = This->stateBlock->streamStride[StreamNumber];
2348 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2351 if (*pStream != NULL) {
2352 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2359 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2360 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2362 /* Verify input at least in d3d9 this is invalid*/
2363 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2364 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL;
2367 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2368 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2369 return WINED3DERR_INVALIDCALL;
2372 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2373 return WINED3DERR_INVALIDCALL;
2376 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2377 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2379 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2380 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2382 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2383 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2394 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2396 TRACE("(%p) : returning %d\n", This, *Divider);
2402 * Get / Set & Multiply Transform
2404 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2407 /* Most of this routine, comments included copied from ddraw tree initially: */
2408 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2410 /* Handle recording of state blocks */
2411 if (This->isRecordingState) {
2412 TRACE("Recording... not performing anything\n");
2413 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2414 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2419 * If the new matrix is the same as the current one,
2420 * we cut off any further processing. this seems to be a reasonable
2421 * optimization because as was noticed, some apps (warcraft3 for example)
2422 * tend towards setting the same matrix repeatedly for some reason.
2424 * From here on we assume that the new matrix is different, wherever it matters.
2426 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2427 TRACE("The app is setting the same matrix over again\n");
2430 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2434 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2435 where ViewMat = Camera space, WorldMat = world space.
2437 In OpenGL, camera and world space is combined into GL_MODELVIEW
2438 matrix. The Projection matrix stay projection matrix.
2441 /* Capture the times we can just ignore the change for now */
2442 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2443 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2444 /* Handled by the state manager */
2447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2454 *pMatrix = This->stateBlock->transforms[State];
2458 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2459 const WINED3DMATRIX *mat = NULL;
2462 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2463 * below means it will be recorded in a state block change, but it
2464 * works regardless where it is recorded.
2465 * If this is found to be wrong, change to StateBlock.
2467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2470 if (State <= HIGHEST_TRANSFORMSTATE)
2472 mat = &This->updateStateBlock->transforms[State];
2474 FIXME("Unhandled transform state!!\n");
2477 multiply_matrix(&temp, mat, pMatrix);
2479 /* Apply change via set transform - will reapply to eg. lights this way */
2480 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2486 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2487 you can reference any indexes you want as long as that number max are enabled at any
2488 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2489 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2490 but when recording, just build a chain pretty much of commands to be replayed. */
2492 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2494 struct wined3d_light_info *object = NULL;
2495 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2499 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2501 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2505 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2506 return WINED3DERR_INVALIDCALL;
2509 switch(pLight->Type) {
2510 case WINED3DLIGHT_POINT:
2511 case WINED3DLIGHT_SPOT:
2512 case WINED3DLIGHT_PARALLELPOINT:
2513 case WINED3DLIGHT_GLSPOT:
2514 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2517 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2519 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2520 return WINED3DERR_INVALIDCALL;
2524 case WINED3DLIGHT_DIRECTIONAL:
2525 /* Ignores attenuation */
2529 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2530 return WINED3DERR_INVALIDCALL;
2533 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2535 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2536 if(object->OriginalIndex == Index) break;
2541 TRACE("Adding new light\n");
2542 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2544 ERR("Out of memory error when allocating a light\n");
2545 return E_OUTOFMEMORY;
2547 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2548 object->glIndex = -1;
2549 object->OriginalIndex = Index;
2552 /* Initialize the object */
2553 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,
2554 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2555 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2556 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2557 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2558 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2559 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2561 /* Save away the information */
2562 object->OriginalParms = *pLight;
2564 switch (pLight->Type) {
2565 case WINED3DLIGHT_POINT:
2567 object->lightPosn[0] = pLight->Position.x;
2568 object->lightPosn[1] = pLight->Position.y;
2569 object->lightPosn[2] = pLight->Position.z;
2570 object->lightPosn[3] = 1.0f;
2571 object->cutoff = 180.0f;
2575 case WINED3DLIGHT_DIRECTIONAL:
2577 object->lightPosn[0] = -pLight->Direction.x;
2578 object->lightPosn[1] = -pLight->Direction.y;
2579 object->lightPosn[2] = -pLight->Direction.z;
2580 object->lightPosn[3] = 0.0f;
2581 object->exponent = 0.0f;
2582 object->cutoff = 180.0f;
2585 case WINED3DLIGHT_SPOT:
2587 object->lightPosn[0] = pLight->Position.x;
2588 object->lightPosn[1] = pLight->Position.y;
2589 object->lightPosn[2] = pLight->Position.z;
2590 object->lightPosn[3] = 1.0f;
2593 object->lightDirn[0] = pLight->Direction.x;
2594 object->lightDirn[1] = pLight->Direction.y;
2595 object->lightDirn[2] = pLight->Direction.z;
2596 object->lightDirn[3] = 1.0f;
2599 * opengl-ish and d3d-ish spot lights use too different models for the
2600 * light "intensity" as a function of the angle towards the main light direction,
2601 * so we only can approximate very roughly.
2602 * however spot lights are rather rarely used in games (if ever used at all).
2603 * furthermore if still used, probably nobody pays attention to such details.
2605 if (pLight->Falloff == 0) {
2606 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2607 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2608 * will always be 1.0 for both of them, and we don't have to care for the
2609 * rest of the rather complex calculation
2611 object->exponent = 0.0f;
2613 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2614 if (rho < 0.0001f) rho = 0.0001f;
2615 object->exponent = -0.3f/logf(cosf(rho/2));
2617 if (object->exponent > 128.0f)
2619 object->exponent = 128.0f;
2621 object->cutoff = pLight->Phi*90/M_PI;
2627 FIXME("Unrecognized light type %d\n", pLight->Type);
2630 /* Update the live definitions if the light is currently assigned a glIndex */
2631 if (object->glIndex != -1 && !This->isRecordingState) {
2632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2637 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2639 struct wined3d_light_info *lightInfo = NULL;
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2643 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2645 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2647 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2648 if(lightInfo->OriginalIndex == Index) break;
2652 if (lightInfo == NULL) {
2653 TRACE("Light information requested but light not defined\n");
2654 return WINED3DERR_INVALIDCALL;
2657 *pLight = lightInfo->OriginalParms;
2662 * Get / Set Light Enable
2663 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2665 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2667 struct wined3d_light_info *lightInfo = NULL;
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2671 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2673 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2675 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2676 if(lightInfo->OriginalIndex == Index) break;
2679 TRACE("Found light: %p\n", lightInfo);
2681 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2682 if (lightInfo == NULL) {
2684 TRACE("Light enabled requested but light not defined, so defining one!\n");
2685 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2687 /* Search for it again! Should be fairly quick as near head of list */
2688 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2690 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2691 if(lightInfo->OriginalIndex == Index) break;
2694 if (lightInfo == NULL) {
2695 FIXME("Adding default lights has failed dismally\n");
2696 return WINED3DERR_INVALIDCALL;
2701 if(lightInfo->glIndex != -1) {
2702 if(!This->isRecordingState) {
2703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2706 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2707 lightInfo->glIndex = -1;
2709 TRACE("Light already disabled, nothing to do\n");
2711 lightInfo->enabled = FALSE;
2713 lightInfo->enabled = TRUE;
2714 if (lightInfo->glIndex != -1) {
2716 TRACE("Nothing to do as light was enabled\n");
2719 /* Find a free gl light */
2720 for(i = 0; i < This->maxConcurrentLights; i++) {
2721 if(This->updateStateBlock->activeLights[i] == NULL) {
2722 This->updateStateBlock->activeLights[i] = lightInfo;
2723 lightInfo->glIndex = i;
2727 if(lightInfo->glIndex == -1) {
2728 /* Our tests show that Windows returns D3D_OK in this situation, even with
2729 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2730 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2731 * as well for those lights.
2733 * TODO: Test how this affects rendering
2735 WARN("Too many concurrently active lights\n");
2739 /* i == lightInfo->glIndex */
2740 if(!This->isRecordingState) {
2741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2749 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2751 struct wined3d_light_info *lightInfo = NULL;
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2755 TRACE("(%p) : for idx(%d)\n", This, Index);
2757 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2759 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2760 if(lightInfo->OriginalIndex == Index) break;
2764 if (lightInfo == NULL) {
2765 TRACE("Light enabled state requested but light not defined\n");
2766 return WINED3DERR_INVALIDCALL;
2768 /* true is 128 according to SetLightEnable */
2769 *pEnable = lightInfo->enabled ? 128 : 0;
2774 * Get / Set Clip Planes
2776 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2780 /* Validate Index */
2781 if (Index >= This->adapter->gl_info.limits.clipplanes)
2783 TRACE("Application has requested clipplane this device doesn't support\n");
2784 return WINED3DERR_INVALIDCALL;
2787 This->updateStateBlock->changed.clipplane |= 1 << Index;
2789 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2790 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2791 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2792 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2793 TRACE("Application is setting old values over, nothing to do\n");
2797 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2798 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2799 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2800 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2802 /* Handle recording of state blocks */
2803 if (This->isRecordingState) {
2804 TRACE("Recording... not performing anything\n");
2808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2813 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2815 TRACE("(%p) : for idx %d\n", This, Index);
2817 /* Validate Index */
2818 if (Index >= This->adapter->gl_info.limits.clipplanes)
2820 TRACE("Application has requested clipplane this device doesn't support\n");
2821 return WINED3DERR_INVALIDCALL;
2824 pPlane[0] = This->stateBlock->clipplane[Index][0];
2825 pPlane[1] = This->stateBlock->clipplane[Index][1];
2826 pPlane[2] = This->stateBlock->clipplane[Index][2];
2827 pPlane[3] = This->stateBlock->clipplane[Index][3];
2832 * Get / Set Clip Plane Status
2833 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2835 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 FIXME("(%p) : stub\n", This);
2838 if (NULL == pClipStatus) {
2839 return WINED3DERR_INVALIDCALL;
2841 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2842 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2846 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2848 FIXME("(%p) : stub\n", This);
2849 if (NULL == pClipStatus) {
2850 return WINED3DERR_INVALIDCALL;
2852 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2853 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2858 * Get / Set Material
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 This->updateStateBlock->changed.material = TRUE;
2864 This->updateStateBlock->material = *pMaterial;
2866 /* Handle recording of state blocks */
2867 if (This->isRecordingState) {
2868 TRACE("Recording... not performing anything\n");
2872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2876 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 *pMaterial = This->updateStateBlock->material;
2879 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2880 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2881 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2882 pMaterial->Ambient.b, pMaterial->Ambient.a);
2883 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2884 pMaterial->Specular.b, pMaterial->Specular.a);
2885 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2886 pMaterial->Emissive.b, pMaterial->Emissive.a);
2887 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2895 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2896 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2899 IWineD3DBuffer *oldIdxs;
2901 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2902 oldIdxs = This->updateStateBlock->pIndexData;
2904 This->updateStateBlock->changed.indices = TRUE;
2905 This->updateStateBlock->pIndexData = pIndexData;
2906 This->updateStateBlock->IndexFmt = fmt;
2908 /* Handle recording of state blocks */
2909 if (This->isRecordingState) {
2910 TRACE("Recording... not performing anything\n");
2911 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2912 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2916 if(oldIdxs != pIndexData) {
2917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2919 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2920 IWineD3DBuffer_AddRef(pIndexData);
2923 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2924 IWineD3DBuffer_Release(oldIdxs);
2931 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 *ppIndexData = This->stateBlock->pIndexData;
2937 /* up ref count on ppindexdata */
2939 IWineD3DBuffer_AddRef(*ppIndexData);
2940 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2942 TRACE("(%p) No index data set\n", This);
2944 TRACE("Returning %p\n", *ppIndexData);
2949 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 TRACE("(%p)->(%d)\n", This, BaseIndex);
2954 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2955 TRACE("Application is setting the old value over, nothing to do\n");
2959 This->updateStateBlock->baseVertexIndex = BaseIndex;
2961 if (This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2965 /* The base vertex index affects the stream sources */
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 TRACE("(%p) : base_index %p\n", This, base_index);
2974 *base_index = This->stateBlock->baseVertexIndex;
2976 TRACE("Returning %u\n", *base_index);
2982 * Get / Set Viewports
2984 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 TRACE("(%p)\n", This);
2988 This->updateStateBlock->changed.viewport = TRUE;
2989 This->updateStateBlock->viewport = *pViewport;
2991 /* Handle recording of state blocks */
2992 if (This->isRecordingState) {
2993 TRACE("Recording... not performing anything\n");
2997 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2998 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3005 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 TRACE("(%p)\n", This);
3008 *pViewport = This->stateBlock->viewport;
3013 * Get / Set Render States
3014 * TODO: Verify against dx9 definitions
3016 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 DWORD oldValue = This->stateBlock->renderState[State];
3021 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3023 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3024 This->updateStateBlock->renderState[State] = Value;
3026 /* Handle recording of state blocks */
3027 if (This->isRecordingState) {
3028 TRACE("Recording... not performing anything\n");
3032 /* Compared here and not before the assignment to allow proper stateblock recording */
3033 if(Value == oldValue) {
3034 TRACE("Application is setting the old value over, nothing to do\n");
3036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3045 *pValue = This->stateBlock->renderState[State];
3050 * Get / Set Sampler States
3051 * TODO: Verify against dx9 definitions
3054 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3059 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3061 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3062 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3065 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3066 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3067 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3070 * SetSampler is designed to allow for more than the standard up to 8 textures
3071 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3072 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3074 * http://developer.nvidia.com/object/General_FAQ.html#t6
3076 * There are two new settings for GForce
3078 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3079 * and the texture one:
3080 * GL_MAX_TEXTURE_COORDS_ARB.
3081 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3084 oldValue = This->stateBlock->samplerState[Sampler][Type];
3085 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3086 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3088 /* Handle recording of state blocks */
3089 if (This->isRecordingState) {
3090 TRACE("Recording... not performing anything\n");
3094 if(oldValue == Value) {
3095 TRACE("Application is setting the old value over, nothing to do\n");
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3107 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3108 This, Sampler, debug_d3dsamplerstate(Type), Type);
3110 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3111 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3114 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3115 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3116 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3118 *Value = This->stateBlock->samplerState[Sampler][Type];
3119 TRACE("(%p) : Returning %#x\n", This, *Value);
3124 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 This->updateStateBlock->changed.scissorRect = TRUE;
3128 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3129 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3132 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3134 if(This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3144 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 *pRect = This->updateStateBlock->scissorRect;
3148 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3152 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3154 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3156 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3158 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3159 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3161 This->updateStateBlock->vertexDecl = pDecl;
3162 This->updateStateBlock->changed.vertexDecl = TRUE;
3164 if (This->isRecordingState) {
3165 TRACE("Recording... not performing anything\n");
3167 } else if(pDecl == oldDecl) {
3168 /* Checked after the assignment to allow proper stateblock recording */
3169 TRACE("Application is setting the old declaration over, nothing to do\n");
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3182 *ppDecl = This->stateBlock->vertexDecl;
3183 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3187 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3191 This->updateStateBlock->vertexShader = pShader;
3192 This->updateStateBlock->changed.vertexShader = TRUE;
3194 if (This->isRecordingState) {
3195 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3196 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3197 TRACE("Recording... not performing anything\n");
3199 } else if(oldShader == pShader) {
3200 /* Checked here to allow proper stateblock recording */
3201 TRACE("App is setting the old shader over, nothing to do\n");
3205 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3206 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3207 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3214 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 if (NULL == ppShader) {
3218 return WINED3DERR_INVALIDCALL;
3220 *ppShader = This->stateBlock->vertexShader;
3221 if( NULL != *ppShader)
3222 IWineD3DVertexShader_AddRef(*ppShader);
3224 TRACE("(%p) : returning %p\n", This, *ppShader);
3228 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3229 IWineD3DDevice *iface,
3231 CONST BOOL *srcData,
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3235 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3237 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3238 iface, srcData, start, count);
3240 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3242 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3243 for (i = 0; i < cnt; i++)
3244 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3246 for (i = start; i < cnt + start; ++i) {
3247 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3250 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3255 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3256 IWineD3DDevice *iface,
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 int cnt = min(count, MAX_CONST_B - start);
3264 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3265 iface, dstData, start, count);
3267 if (dstData == NULL || cnt < 0)
3268 return WINED3DERR_INVALIDCALL;
3270 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3275 IWineD3DDevice *iface,
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3283 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3284 iface, srcData, start, count);
3286 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3288 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3289 for (i = 0; i < cnt; i++)
3290 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3291 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3293 for (i = start; i < cnt + start; ++i) {
3294 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3297 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3302 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3303 IWineD3DDevice *iface,
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 int cnt = min(count, MAX_CONST_I - start);
3311 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3312 iface, dstData, start, count);
3314 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3315 return WINED3DERR_INVALIDCALL;
3317 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3321 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3322 IWineD3DDevice *iface,
3324 CONST float *srcData,
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3330 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3331 iface, srcData, start, count);
3333 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3334 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3335 return WINED3DERR_INVALIDCALL;
3337 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3339 for (i = 0; i < count; i++)
3340 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3341 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3344 if (!This->isRecordingState)
3346 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3350 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3351 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3356 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3357 IWineD3DDevice *iface,
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 int cnt = min(count, This->d3d_vshader_constantF - start);
3365 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3366 iface, dstData, start, count);
3368 if (dstData == NULL || cnt < 0)
3369 return WINED3DERR_INVALIDCALL;
3371 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3375 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3377 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3383 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3385 DWORD i = This->rev_tex_unit_map[unit];
3386 DWORD j = This->texUnitMap[stage];
3388 This->texUnitMap[stage] = unit;
3389 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3391 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3394 This->rev_tex_unit_map[unit] = stage;
3395 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3397 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3401 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3404 This->fixed_function_usage_map = 0;
3405 for (i = 0; i < MAX_TEXTURES; ++i) {
3406 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3407 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3408 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3409 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3410 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3411 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3412 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3413 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3415 if (color_op == WINED3DTOP_DISABLE) {
3416 /* Not used, and disable higher stages */
3420 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3421 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3422 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3423 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3424 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3425 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3426 This->fixed_function_usage_map |= (1 << i);
3429 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3430 This->fixed_function_usage_map |= (1 << (i + 1));
3435 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3437 unsigned int i, tex;
3440 device_update_fixed_function_usage_map(This);
3441 ffu_map = This->fixed_function_usage_map;
3443 if (This->max_ffp_textures == gl_info->limits.texture_stages
3444 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3446 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3448 if (!(ffu_map & 1)) continue;
3450 if (This->texUnitMap[i] != i) {
3451 device_map_stage(This, i, i);
3452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3453 markTextureStagesDirty(This, i);
3459 /* Now work out the mapping */
3461 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3463 if (!(ffu_map & 1)) continue;
3465 if (This->texUnitMap[i] != tex) {
3466 device_map_stage(This, i, tex);
3467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3468 markTextureStagesDirty(This, i);
3475 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3477 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3478 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3481 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3482 if (sampler_type[i] && This->texUnitMap[i] != i)
3484 device_map_stage(This, i, i);
3485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3486 if (i < gl_info->limits.texture_stages)
3488 markTextureStagesDirty(This, i);
3494 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3495 const DWORD *vshader_sampler_tokens, DWORD unit)
3497 DWORD current_mapping = This->rev_tex_unit_map[unit];
3499 /* Not currently used */
3500 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3502 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3503 /* Used by a fragment sampler */
3505 if (!pshader_sampler_tokens) {
3506 /* No pixel shader, check fixed function */
3507 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3510 /* Pixel shader, check the shader's sampler map */
3511 return !pshader_sampler_tokens[current_mapping];
3514 /* Used by a vertex sampler */
3515 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3518 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3520 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3521 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3522 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3523 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3527 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3529 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3530 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3531 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3534 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3535 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3536 if (vshader_sampler_type[i])
3538 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3540 /* Already mapped somewhere */
3544 while (start >= 0) {
3545 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3547 device_map_stage(This, vsampler_idx, start);
3548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3560 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3562 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3563 BOOL vs = use_vs(This->stateBlock);
3564 BOOL ps = use_ps(This->stateBlock);
3567 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3568 * that would be really messy and require shader recompilation
3569 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3570 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3572 if (ps) device_map_psamplers(This, gl_info);
3573 else device_map_fixed_function_samplers(This, gl_info);
3575 if (vs) device_map_vsamplers(This, ps, gl_info);
3578 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3580 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3581 This->updateStateBlock->pixelShader = pShader;
3582 This->updateStateBlock->changed.pixelShader = TRUE;
3584 /* Handle recording of state blocks */
3585 if (This->isRecordingState) {
3586 TRACE("Recording... not performing anything\n");
3589 if (This->isRecordingState) {
3590 TRACE("Recording... not performing anything\n");
3591 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3592 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3596 if(pShader == oldShader) {
3597 TRACE("App is setting the old pixel shader over, nothing to do\n");
3601 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3602 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3604 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3610 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 if (NULL == ppShader) {
3614 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3615 return WINED3DERR_INVALIDCALL;
3618 *ppShader = This->stateBlock->pixelShader;
3619 if (NULL != *ppShader) {
3620 IWineD3DPixelShader_AddRef(*ppShader);
3622 TRACE("(%p) : returning %p\n", This, *ppShader);
3626 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3627 IWineD3DDevice *iface,
3629 CONST BOOL *srcData,
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3633 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3635 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3636 iface, srcData, start, count);
3638 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3640 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3641 for (i = 0; i < cnt; i++)
3642 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3644 for (i = start; i < cnt + start; ++i) {
3645 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3648 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3653 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3654 IWineD3DDevice *iface,
3659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3660 int cnt = min(count, MAX_CONST_B - start);
3662 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3663 iface, dstData, start, count);
3665 if (dstData == NULL || cnt < 0)
3666 return WINED3DERR_INVALIDCALL;
3668 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3672 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3673 IWineD3DDevice *iface,
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3681 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3682 iface, srcData, start, count);
3684 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3686 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3687 for (i = 0; i < cnt; i++)
3688 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3689 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3691 for (i = start; i < cnt + start; ++i) {
3692 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3695 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3700 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3701 IWineD3DDevice *iface,
3706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3707 int cnt = min(count, MAX_CONST_I - start);
3709 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3710 iface, dstData, start, count);
3712 if (dstData == NULL || cnt < 0)
3713 return WINED3DERR_INVALIDCALL;
3715 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3719 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3720 IWineD3DDevice *iface,
3722 CONST float *srcData,
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3728 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3729 iface, srcData, start, count);
3731 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3732 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3733 return WINED3DERR_INVALIDCALL;
3735 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3737 for (i = 0; i < count; i++)
3738 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3739 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3742 if (!This->isRecordingState)
3744 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3748 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3749 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3754 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3755 IWineD3DDevice *iface,
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 int cnt = min(count, This->d3d_pshader_constantF - start);
3763 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3764 iface, dstData, start, count);
3766 if (dstData == NULL || cnt < 0)
3767 return WINED3DERR_INVALIDCALL;
3769 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3773 /* Context activation is done by the caller. */
3774 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3775 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3776 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3779 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3780 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3783 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3787 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3789 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3792 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3794 ERR("Source has no position mask\n");
3795 return WINED3DERR_INVALIDCALL;
3798 /* We might access VBOs from this code, so hold the lock */
3801 if (!dest->resource.allocatedMemory)
3802 buffer_get_sysmem(dest, gl_info);
3804 /* Get a pointer into the destination vbo(create one if none exists) and
3805 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3807 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3809 dest->flags |= WINED3D_BUFFER_CREATEBO;
3810 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3813 if (dest->buffer_object)
3815 unsigned char extrabytes = 0;
3816 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3817 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3818 * this may write 4 extra bytes beyond the area that should be written
3820 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3821 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3822 if(!dest_conv_addr) {
3823 ERR("Out of memory\n");
3824 /* Continue without storing converted vertices */
3826 dest_conv = dest_conv_addr;
3830 * a) WINED3DRS_CLIPPING is enabled
3831 * b) WINED3DVOP_CLIP is passed
3833 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3834 static BOOL warned = FALSE;
3836 * The clipping code is not quite correct. Some things need
3837 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3838 * so disable clipping for now.
3839 * (The graphics in Half-Life are broken, and my processvertices
3840 * test crashes with IDirect3DDevice3)
3846 FIXME("Clipping is broken and disabled for now\n");
3848 } else doClip = FALSE;
3849 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3851 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3854 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3855 WINED3DTS_PROJECTION,
3857 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3858 WINED3DTS_WORLDMATRIX(0),
3861 TRACE("View mat:\n");
3862 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);
3863 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);
3864 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);
3865 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);
3867 TRACE("Proj mat:\n");
3868 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);
3869 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);
3870 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);
3871 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);
3873 TRACE("World mat:\n");
3874 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);
3875 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);
3876 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);
3877 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);
3879 /* Get the viewport */
3880 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3881 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3882 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3884 multiply_matrix(&mat,&view_mat,&world_mat);
3885 multiply_matrix(&mat,&proj_mat,&mat);
3887 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3889 for (i = 0; i < dwCount; i+= 1) {
3890 unsigned int tex_index;
3892 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3893 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3894 /* The position first */
3895 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3896 const float *p = (const float *)(element->data + i * element->stride);
3898 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3900 /* Multiplication with world, view and projection matrix */
3901 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);
3902 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);
3903 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);
3904 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);
3906 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3908 /* WARNING: The following things are taken from d3d7 and were not yet checked
3909 * against d3d8 or d3d9!
3912 /* Clipping conditions: From msdn
3914 * A vertex is clipped if it does not match the following requirements
3918 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3920 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3921 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3926 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3927 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3930 /* "Normal" viewport transformation (not clipped)
3931 * 1) The values are divided by rhw
3932 * 2) The y axis is negative, so multiply it with -1
3933 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3934 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3935 * 4) Multiply x with Width/2 and add Width/2
3936 * 5) The same for the height
3937 * 6) Add the viewpoint X and Y to the 2D coordinates and
3938 * The minimum Z value to z
3939 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3941 * Well, basically it's simply a linear transformation into viewport
3953 z *= vp.MaxZ - vp.MinZ;
3955 x += vp.Width / 2 + vp.X;
3956 y += vp.Height / 2 + vp.Y;
3961 /* That vertex got clipped
3962 * Contrary to OpenGL it is not dropped completely, it just
3963 * undergoes a different calculation.
3965 TRACE("Vertex got clipped\n");
3972 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3973 * outside of the main vertex buffer memory. That needs some more
3978 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3981 ( (float *) dest_ptr)[0] = x;
3982 ( (float *) dest_ptr)[1] = y;
3983 ( (float *) dest_ptr)[2] = z;
3984 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3986 dest_ptr += 3 * sizeof(float);
3988 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3989 dest_ptr += sizeof(float);
3994 ( (float *) dest_conv)[0] = x * w;
3995 ( (float *) dest_conv)[1] = y * w;
3996 ( (float *) dest_conv)[2] = z * w;
3997 ( (float *) dest_conv)[3] = w;
3999 dest_conv += 3 * sizeof(float);
4001 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4002 dest_conv += sizeof(float);
4006 if (DestFVF & WINED3DFVF_PSIZE) {
4007 dest_ptr += sizeof(DWORD);
4008 if(dest_conv) dest_conv += sizeof(DWORD);
4010 if (DestFVF & WINED3DFVF_NORMAL) {
4011 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4012 const float *normal = (const float *)(element->data + i * element->stride);
4013 /* AFAIK this should go into the lighting information */
4014 FIXME("Didn't expect the destination to have a normal\n");
4015 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4017 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4021 if (DestFVF & WINED3DFVF_DIFFUSE) {
4022 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4023 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4024 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4026 static BOOL warned = FALSE;
4029 ERR("No diffuse color in source, but destination has one\n");
4033 *( (DWORD *) dest_ptr) = 0xffffffff;
4034 dest_ptr += sizeof(DWORD);
4037 *( (DWORD *) dest_conv) = 0xffffffff;
4038 dest_conv += sizeof(DWORD);
4042 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4044 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4045 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4046 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4047 dest_conv += sizeof(DWORD);
4052 if (DestFVF & WINED3DFVF_SPECULAR)
4054 /* What's the color value in the feedback buffer? */
4055 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4056 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4057 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4059 static BOOL warned = FALSE;
4062 ERR("No specular color in source, but destination has one\n");
4066 *( (DWORD *) dest_ptr) = 0xFF000000;
4067 dest_ptr += sizeof(DWORD);
4070 *( (DWORD *) dest_conv) = 0xFF000000;
4071 dest_conv += sizeof(DWORD);
4075 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4077 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4078 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4079 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4080 dest_conv += sizeof(DWORD);
4085 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4086 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4087 const float *tex_coord = (const float *)(element->data + i * element->stride);
4088 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4090 ERR("No source texture, but destination requests one\n");
4091 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4092 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4095 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4097 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4104 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4105 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4106 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4107 dwCount * get_flexible_vertex_size(DestFVF),
4109 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4110 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4117 #undef copy_and_next
4119 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4120 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 struct wined3d_stream_info stream_info;
4125 const struct wined3d_gl_info *gl_info;
4126 struct wined3d_context *context;
4127 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4130 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4133 ERR("Output vertex declaration not implemented yet\n");
4136 /* Need any context to write to the vbo. */
4137 context = context_acquire(This, NULL);
4138 gl_info = context->gl_info;
4140 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4141 * control the streamIsUP flag, thus restore it afterwards.
4143 This->stateBlock->streamIsUP = FALSE;
4144 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4145 This->stateBlock->streamIsUP = streamWasUP;
4147 if(vbo || SrcStartIndex) {
4149 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4150 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4152 * Also get the start index in, but only loop over all elements if there's something to add at all.
4154 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4156 struct wined3d_stream_info_element *e;
4158 if (!(stream_info.use_map & (1 << i))) continue;
4160 e = &stream_info.elements[i];
4161 if (e->buffer_object)
4163 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4164 e->buffer_object = 0;
4165 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4167 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4168 vb->buffer_object = 0;
4171 if (e->data) e->data += e->stride * SrcStartIndex;
4175 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4176 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4178 context_release(context);
4184 * Get / Set Texture Stage States
4185 * TODO: Verify against dx9 definitions
4187 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4189 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4190 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4192 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4194 if (Stage >= gl_info->limits.texture_stages)
4196 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4197 Stage, gl_info->limits.texture_stages - 1);
4201 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4202 This->updateStateBlock->textureState[Stage][Type] = Value;
4204 if (This->isRecordingState) {
4205 TRACE("Recording... not performing anything\n");
4209 /* Checked after the assignments to allow proper stateblock recording */
4210 if(oldValue == Value) {
4211 TRACE("App is setting the old value over, nothing to do\n");
4215 if(Stage > This->stateBlock->lowest_disabled_stage &&
4216 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4217 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4218 * Changes in other states are important on disabled stages too
4223 if(Type == WINED3DTSS_COLOROP) {
4226 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4227 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4228 * they have to be disabled
4230 * The current stage is dirtified below.
4232 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4233 TRACE("Additionally dirtifying stage %u\n", i);
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4236 This->stateBlock->lowest_disabled_stage = Stage;
4237 TRACE("New lowest disabled: %u\n", Stage);
4238 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4239 /* Previously disabled stage enabled. Stages above it may need enabling
4240 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4241 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4243 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4246 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4248 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4251 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4254 This->stateBlock->lowest_disabled_stage = i;
4255 TRACE("New lowest disabled: %u\n", i);
4259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4264 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4266 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4267 *pValue = This->updateStateBlock->textureState[Stage][Type];
4274 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4275 DWORD stage, IWineD3DBaseTexture *texture)
4277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4278 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4279 IWineD3DBaseTexture *prev;
4281 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4283 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4284 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4286 /* Windows accepts overflowing this array... we do not. */
4287 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4289 WARN("Ignoring invalid stage %u.\n", stage);
4293 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4294 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4296 WARN("Rejecting attempt to set scratch texture.\n");
4297 return WINED3DERR_INVALIDCALL;
4300 This->updateStateBlock->changed.textures |= 1 << stage;
4302 prev = This->updateStateBlock->textures[stage];
4303 TRACE("Previous texture %p.\n", prev);
4305 if (texture == prev)
4307 TRACE("App is setting the same texture again, nothing to do.\n");
4311 TRACE("Setting new texture to %p.\n", texture);
4312 This->updateStateBlock->textures[stage] = texture;
4314 if (This->isRecordingState)
4316 TRACE("Recording... not performing anything\n");
4318 if (texture) IWineD3DBaseTexture_AddRef(texture);
4319 if (prev) IWineD3DBaseTexture_Release(prev);
4326 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4327 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4328 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4330 IWineD3DBaseTexture_AddRef(texture);
4332 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4337 if (!prev && stage < gl_info->limits.texture_stages)
4339 /* The source arguments for color and alpha ops have different
4340 * meanings when a NULL texture is bound, so the COLOROP and
4341 * ALPHAOP have to be dirtified. */
4342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4346 if (bind_count == 1) t->baseTexture.sampler = stage;
4351 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4352 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4354 IWineD3DBaseTexture_Release(prev);
4356 if (!texture && stage < gl_info->limits.texture_stages)
4358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4362 if (bind_count && t->baseTexture.sampler == stage)
4366 /* Search for other stages the texture is bound to. Shouldn't
4367 * happen if applications bind textures to a single stage only. */
4368 TRACE("Searching for other stages the texture is bound to.\n");
4369 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4371 if (This->updateStateBlock->textures[i] == prev)
4373 TRACE("Texture is also bound to stage %u.\n", i);
4374 t->baseTexture.sampler = i;
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4386 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4389 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4391 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4392 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4395 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4396 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4397 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4400 *ppTexture=This->stateBlock->textures[Stage];
4402 IWineD3DBaseTexture_AddRef(*ppTexture);
4404 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4412 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4413 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4415 IWineD3DSwapChain *swapchain;
4418 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4419 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4421 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4424 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4428 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4429 IWineD3DSwapChain_Release(swapchain);
4432 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4439 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 WARN("(%p) : stub, calling idirect3d for now\n", This);
4442 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4445 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 IWineD3DSwapChain *swapChain;
4450 if(iSwapChain > 0) {
4451 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4452 if (hr == WINED3D_OK) {
4453 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4454 IWineD3DSwapChain_Release(swapChain);
4456 FIXME("(%p) Error getting display mode\n", This);
4459 /* Don't read the real display mode,
4460 but return the stored mode instead. X11 can't change the color
4461 depth, and some apps are pretty angry if they SetDisplayMode from
4462 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4464 Also don't relay to the swapchain because with ddraw it's possible
4465 that there isn't a swapchain at all */
4466 pMode->Width = This->ddraw_width;
4467 pMode->Height = This->ddraw_height;
4468 pMode->Format = This->ddraw_format;
4469 pMode->RefreshRate = 0;
4477 * Stateblock related functions
4480 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4482 IWineD3DStateBlock *stateblock;
4485 TRACE("(%p)\n", This);
4487 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4489 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4490 if (FAILED(hr)) return hr;
4492 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4493 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4494 This->isRecordingState = TRUE;
4496 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4501 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4505 if (!This->isRecordingState) {
4506 WARN("(%p) not recording! returning error\n", This);
4507 *ppStateBlock = NULL;
4508 return WINED3DERR_INVALIDCALL;
4511 stateblock_init_contained_states(object);
4513 *ppStateBlock = (IWineD3DStateBlock*) object;
4514 This->isRecordingState = FALSE;
4515 This->updateStateBlock = This->stateBlock;
4516 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4517 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4518 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4523 * Scene related functions
4525 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4526 /* At the moment we have no need for any functionality at the beginning
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("(%p)\n", This);
4532 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4533 return WINED3DERR_INVALIDCALL;
4535 This->inScene = TRUE;
4539 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 struct wined3d_context *context;
4544 TRACE("(%p)\n", This);
4546 if(!This->inScene) {
4547 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4548 return WINED3DERR_INVALIDCALL;
4551 context = context_acquire(This, NULL);
4552 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4554 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4556 context_release(context);
4558 This->inScene = FALSE;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4563 const RECT *pSourceRect, const RECT *pDestRect,
4564 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4566 IWineD3DSwapChain *swapChain = NULL;
4568 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4570 TRACE("iface %p.\n", iface);
4572 for(i = 0 ; i < swapchains ; i ++) {
4574 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4575 TRACE("presentinng chain %d, %p\n", i, swapChain);
4576 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4577 IWineD3DSwapChain_Release(swapChain);
4583 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4584 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4589 Count, pRects, Flags, Color, Z, Stencil);
4591 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4593 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4594 /* TODO: What about depth stencil buffers without stencil bits? */
4595 return WINED3DERR_INVALIDCALL;
4598 return device_clear_render_targets(This, This->adapter->gl_info.limits.buffers,
4599 This->render_targets, Count, pRects, Flags, Color, Z, Stencil);
4606 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4607 WINED3DPRIMITIVETYPE primitive_type)
4609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4611 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4613 This->updateStateBlock->changed.primitive_type = TRUE;
4614 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4617 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4618 WINED3DPRIMITIVETYPE *primitive_type)
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4624 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4626 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4629 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4635 if(!This->stateBlock->vertexDecl) {
4636 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4637 return WINED3DERR_INVALIDCALL;
4640 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4641 if(This->stateBlock->streamIsUP) {
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4643 This->stateBlock->streamIsUP = FALSE;
4646 if(This->stateBlock->loadBaseVertexIndex != 0) {
4647 This->stateBlock->loadBaseVertexIndex = 0;
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4650 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4651 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4655 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 IWineD3DBuffer *pIB;
4662 pIB = This->stateBlock->pIndexData;
4664 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4665 * without an index buffer set. (The first time at least...)
4666 * D3D8 simply dies, but I doubt it can do much harm to return
4667 * D3DERR_INVALIDCALL there as well. */
4668 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4669 return WINED3DERR_INVALIDCALL;
4672 if(!This->stateBlock->vertexDecl) {
4673 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4674 return WINED3DERR_INVALIDCALL;
4677 if(This->stateBlock->streamIsUP) {
4678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4679 This->stateBlock->streamIsUP = FALSE;
4681 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4683 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4685 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4691 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4692 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4696 drawPrimitive(iface, index_count, startIndex, idxStride,
4697 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4703 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4709 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4711 if(!This->stateBlock->vertexDecl) {
4712 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4713 return WINED3DERR_INVALIDCALL;
4716 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4717 vb = This->stateBlock->streamSource[0];
4718 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4719 if (vb) IWineD3DBuffer_Release(vb);
4720 This->stateBlock->streamOffset[0] = 0;
4721 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4722 This->stateBlock->streamIsUP = TRUE;
4723 This->stateBlock->loadBaseVertexIndex = 0;
4725 /* TODO: Only mark dirty if drawing from a different UP address */
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4728 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4730 /* MSDN specifies stream zero settings must be set to NULL */
4731 This->stateBlock->streamStride[0] = 0;
4732 This->stateBlock->streamSource[0] = NULL;
4734 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4735 * the new stream sources or use UP drawing again
4740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4741 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4742 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4749 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4750 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4752 if(!This->stateBlock->vertexDecl) {
4753 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4754 return WINED3DERR_INVALIDCALL;
4757 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4763 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4764 vb = This->stateBlock->streamSource[0];
4765 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4766 if (vb) IWineD3DBuffer_Release(vb);
4767 This->stateBlock->streamIsUP = TRUE;
4768 This->stateBlock->streamOffset[0] = 0;
4769 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4771 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4772 This->stateBlock->baseVertexIndex = 0;
4773 This->stateBlock->loadBaseVertexIndex = 0;
4774 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4778 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4780 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4781 This->stateBlock->streamSource[0] = NULL;
4782 This->stateBlock->streamStride[0] = 0;
4783 ib = This->stateBlock->pIndexData;
4785 IWineD3DBuffer_Release(ib);
4786 This->stateBlock->pIndexData = NULL;
4788 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4789 * SetStreamSource to specify a vertex buffer
4795 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4796 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4800 /* Mark the state dirty until we have nicer tracking
4801 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4806 This->stateBlock->baseVertexIndex = 0;
4807 This->up_strided = DrawPrimStrideData;
4808 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4809 This->up_strided = NULL;
4813 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4814 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4815 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4818 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4820 /* Mark the state dirty until we have nicer tracking
4821 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4826 This->stateBlock->streamIsUP = TRUE;
4827 This->stateBlock->baseVertexIndex = 0;
4828 This->up_strided = DrawPrimStrideData;
4829 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4830 This->up_strided = NULL;
4834 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4835 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4836 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4838 WINED3DLOCKED_BOX src;
4839 WINED3DLOCKED_BOX dst;
4842 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4843 iface, pSourceVolume, pDestinationVolume);
4845 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4846 * dirtification to improve loading performance.
4848 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4849 if(FAILED(hr)) return hr;
4850 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4852 IWineD3DVolume_UnlockBox(pSourceVolume);
4856 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4858 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4860 IWineD3DVolume_UnlockBox(pSourceVolume);
4862 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4867 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4868 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4870 unsigned int level_count, i;
4871 WINED3DRESOURCETYPE type;
4874 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4876 /* Verify that the source and destination textures are non-NULL. */
4877 if (!src_texture || !dst_texture)
4879 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4880 return WINED3DERR_INVALIDCALL;
4883 if (src_texture == dst_texture)
4885 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4886 return WINED3DERR_INVALIDCALL;
4889 /* Verify that the source and destination textures are the same type. */
4890 type = IWineD3DBaseTexture_GetType(src_texture);
4891 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4893 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4894 return WINED3DERR_INVALIDCALL;
4897 /* Check that both textures have the identical numbers of levels. */
4898 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4899 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4901 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4902 return WINED3DERR_INVALIDCALL;
4905 /* Make sure that the destination texture is loaded. */
4906 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4908 /* Update every surface level of the texture. */
4911 case WINED3DRTYPE_TEXTURE:
4913 IWineD3DSurface *src_surface;
4914 IWineD3DSurface *dst_surface;
4916 for (i = 0; i < level_count; ++i)
4918 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4919 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4920 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4921 IWineD3DSurface_Release(dst_surface);
4922 IWineD3DSurface_Release(src_surface);
4925 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4932 case WINED3DRTYPE_CUBETEXTURE:
4934 IWineD3DSurface *src_surface;
4935 IWineD3DSurface *dst_surface;
4936 WINED3DCUBEMAP_FACES face;
4938 for (i = 0; i < level_count; ++i)
4940 /* Update each cube face. */
4941 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4943 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4944 face, i, &src_surface);
4945 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4946 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4947 face, i, &dst_surface);
4948 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4949 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4950 IWineD3DSurface_Release(dst_surface);
4951 IWineD3DSurface_Release(src_surface);
4954 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4962 case WINED3DRTYPE_VOLUMETEXTURE:
4964 IWineD3DVolume *src_volume;
4965 IWineD3DVolume *dst_volume;
4967 for (i = 0; i < level_count; ++i)
4969 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4970 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4971 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4972 IWineD3DVolume_Release(dst_volume);
4973 IWineD3DVolume_Release(src_volume);
4976 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4984 FIXME("Unsupported texture type %#x.\n", type);
4985 return WINED3DERR_INVALIDCALL;
4991 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4992 IWineD3DSwapChain *swapChain;
4994 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4995 if(hr == WINED3D_OK) {
4996 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4997 IWineD3DSwapChain_Release(swapChain);
5002 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5004 IWineD3DBaseTextureImpl *texture;
5007 TRACE("(%p) : %p\n", This, pNumPasses);
5009 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5010 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5011 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5012 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5014 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5015 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5016 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5019 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5020 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5022 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5023 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5026 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5027 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5030 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5031 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5032 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5037 /* return a sensible default */
5040 TRACE("returning D3D_OK\n");
5044 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5048 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5050 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5051 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5052 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5054 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5059 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 PALETTEENTRY **palettes;
5065 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5067 if (PaletteNumber >= MAX_PALETTES) {
5068 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5069 return WINED3DERR_INVALIDCALL;
5072 if (PaletteNumber >= This->NumberOfPalettes) {
5073 NewSize = This->NumberOfPalettes;
5076 } while(PaletteNumber >= NewSize);
5077 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5079 ERR("Out of memory!\n");
5080 return E_OUTOFMEMORY;
5082 This->palettes = palettes;
5083 This->NumberOfPalettes = NewSize;
5086 if (!This->palettes[PaletteNumber]) {
5087 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5088 if (!This->palettes[PaletteNumber]) {
5089 ERR("Out of memory!\n");
5090 return E_OUTOFMEMORY;
5094 for (j = 0; j < 256; ++j) {
5095 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5096 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5097 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5098 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5100 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5101 TRACE("(%p) : returning\n", This);
5105 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5108 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5109 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5110 /* What happens in such situation isn't documented; Native seems to silently abort
5111 on such conditions. Return Invalid Call. */
5112 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5113 return WINED3DERR_INVALIDCALL;
5115 for (j = 0; j < 256; ++j) {
5116 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5117 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5118 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5119 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5121 TRACE("(%p) : returning\n", This);
5125 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5127 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5128 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5129 (tested with reference rasterizer). Return Invalid Call. */
5130 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5131 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5132 return WINED3DERR_INVALIDCALL;
5134 /*TODO: stateblocks */
5135 if (This->currentPalette != PaletteNumber) {
5136 This->currentPalette = PaletteNumber;
5137 dirtify_p8_texture_samplers(This);
5139 TRACE("(%p) : returning\n", This);
5143 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 if (PaletteNumber == NULL) {
5146 WARN("(%p) : returning Invalid Call\n", This);
5147 return WINED3DERR_INVALIDCALL;
5149 /*TODO: stateblocks */
5150 *PaletteNumber = This->currentPalette;
5151 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5155 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5160 FIXME("(%p) : stub\n", This);
5164 This->softwareVertexProcessing = bSoftware;
5169 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5174 FIXME("(%p) : stub\n", This);
5177 return This->softwareVertexProcessing;
5180 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5181 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5183 IWineD3DSwapChain *swapchain;
5186 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5187 iface, swapchain_idx, raster_status);
5189 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5192 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5196 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5197 IWineD3DSwapChain_Release(swapchain);
5200 WARN("Failed to get raster status, hr %#x.\n", hr);
5207 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5210 if(nSegments != 0.0f) {
5213 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5220 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5225 FIXME("iface %p stub!\n", iface);
5231 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5232 IWineD3DSurface *src_surface, const RECT *src_rect,
5233 IWineD3DSurface *dst_surface, const POINT *dst_point)
5235 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5236 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 const struct wined3d_format_desc *src_format;
5239 const struct wined3d_format_desc *dst_format;
5240 const struct wined3d_gl_info *gl_info;
5241 struct wined3d_context *context;
5242 const unsigned char *data;
5243 UINT update_w, update_h;
5244 CONVERT_TYPES convert;
5248 struct wined3d_format_desc desc;
5250 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5251 iface, src_surface, wine_dbgstr_rect(src_rect),
5252 dst_surface, wine_dbgstr_point(dst_point));
5254 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5256 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5257 src_surface, dst_surface);
5258 return WINED3DERR_INVALIDCALL;
5261 src_format = src_impl->resource.format_desc;
5262 dst_format = dst_impl->resource.format_desc;
5264 if (src_format->format != dst_format->format)
5266 WARN("Source and destination surfaces should have the same format.\n");
5267 return WINED3DERR_INVALIDCALL;
5270 dst_x = dst_point ? dst_point->x : 0;
5271 dst_y = dst_point ? dst_point->y : 0;
5273 /* This call loads the OpenGL surface directly, instead of copying the
5274 * surface to the destination's sysmem copy. If surface conversion is
5275 * needed, use BltFast instead to copy in sysmem and use regular surface
5277 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5278 if (convert != NO_CONVERSION || desc.convert)
5279 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5281 context = context_acquire(This, NULL);
5282 gl_info = context->gl_info;
5285 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5286 checkGLcall("glActiveTextureARB");
5289 /* Make sure the surface is loaded and up to date */
5290 surface_internal_preload(dst_impl, SRGB_RGB);
5291 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5293 src_w = src_impl->currentDesc.Width;
5294 src_h = src_impl->currentDesc.Height;
5295 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5296 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5298 data = IWineD3DSurface_GetData(src_surface);
5299 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5303 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5305 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5306 UINT row_count = update_h / src_format->block_height;
5307 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5311 data += (src_rect->top / src_format->block_height) * src_pitch;
5312 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5315 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5316 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5317 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5319 if (row_length == src_pitch)
5321 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5322 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5328 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5329 * can't use the unpack row length like below. */
5330 for (row = 0, y = dst_y; row < row_count; ++row)
5332 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5333 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5334 y += src_format->block_height;
5338 checkGLcall("glCompressedTexSubImage2DARB");
5344 data += src_rect->top * src_w * src_format->byte_count;
5345 data += src_rect->left * src_format->byte_count;
5348 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5349 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5350 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5352 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5353 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5354 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5355 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5356 checkGLcall("glTexSubImage2D");
5360 context_release(context);
5362 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5363 sampler = This->rev_tex_unit_map[0];
5364 if (sampler != WINED3D_UNMAPPED_STAGE)
5366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5372 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 struct WineD3DRectPatch *patch;
5375 GLenum old_primitive_type;
5379 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5381 if(!(Handle || pRectPatchInfo)) {
5382 /* TODO: Write a test for the return value, thus the FIXME */
5383 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5384 return WINED3DERR_INVALIDCALL;
5388 i = PATCHMAP_HASHFUNC(Handle);
5390 LIST_FOR_EACH(e, &This->patches[i]) {
5391 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5392 if(patch->Handle == Handle) {
5399 TRACE("Patch does not exist. Creating a new one\n");
5400 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5401 patch->Handle = Handle;
5402 list_add_head(&This->patches[i], &patch->entry);
5404 TRACE("Found existing patch %p\n", patch);
5407 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5408 * attributes we have to tesselate, read back, and draw. This needs a patch
5409 * management structure instance. Create one.
5411 * A possible improvement is to check if a vertex shader is used, and if not directly
5414 FIXME("Drawing an uncached patch. This is slow\n");
5415 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5418 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5419 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5420 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5422 TRACE("Tesselation density or patch info changed, retesselating\n");
5424 if(pRectPatchInfo) {
5425 patch->RectPatchInfo = *pRectPatchInfo;
5427 patch->numSegs[0] = pNumSegs[0];
5428 patch->numSegs[1] = pNumSegs[1];
5429 patch->numSegs[2] = pNumSegs[2];
5430 patch->numSegs[3] = pNumSegs[3];
5432 hr = tesselate_rectpatch(This, patch);
5434 WARN("Patch tesselation failed\n");
5436 /* Do not release the handle to store the params of the patch */
5438 HeapFree(GetProcessHeap(), 0, patch);
5444 This->currentPatch = patch;
5445 old_primitive_type = This->stateBlock->gl_primitive_type;
5446 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5447 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5448 This->stateBlock->gl_primitive_type = old_primitive_type;
5449 This->currentPatch = NULL;
5451 /* Destroy uncached patches */
5453 HeapFree(GetProcessHeap(), 0, patch->mem);
5454 HeapFree(GetProcessHeap(), 0, patch);
5459 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5460 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5462 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5463 iface, handle, segment_count, patch_info);
5468 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5471 struct WineD3DRectPatch *patch;
5473 TRACE("(%p) Handle(%d)\n", This, Handle);
5475 i = PATCHMAP_HASHFUNC(Handle);
5476 LIST_FOR_EACH(e, &This->patches[i]) {
5477 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5478 if(patch->Handle == Handle) {
5479 TRACE("Deleting patch %p\n", patch);
5480 list_remove(&patch->entry);
5481 HeapFree(GetProcessHeap(), 0, patch->mem);
5482 HeapFree(GetProcessHeap(), 0, patch);
5487 /* TODO: Write a test for the return value */
5488 FIXME("Attempt to destroy nonexistent patch\n");
5489 return WINED3DERR_INVALIDCALL;
5492 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5493 const WINED3DRECT *rect, const float color[4])
5495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5496 struct wined3d_context *context;
5498 if (rect) surface_load_location(surface, SFLAG_INDRAWABLE, NULL);
5499 surface_modify_location(surface, SFLAG_INDRAWABLE, TRUE);
5501 context = context_acquire(This, surface);
5502 context_apply_clear_state(context, This, 1, &surface, NULL);
5508 if (surface_is_offscreen(surface))
5509 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5511 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5512 rect->x2 - rect->x1, rect->y2 - rect->y1);
5513 checkGLcall("glScissor");
5517 glDisable(GL_SCISSOR_TEST);
5520 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5526 glClearColor(color[0], color[1], color[2], color[3]);
5527 glClear(GL_COLOR_BUFFER_BIT);
5528 checkGLcall("glClear");
5532 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5534 context_release(context);
5537 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5538 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5540 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5543 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5545 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5546 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5547 return WINED3DERR_INVALIDCALL;
5550 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5551 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5552 color_fill_fbo(iface, surface, pRect, c);
5555 /* Just forward this to the DirectDraw blitting engine */
5556 memset(&BltFx, 0, sizeof(BltFx));
5557 BltFx.dwSize = sizeof(BltFx);
5558 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5559 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5560 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5564 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5565 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5567 IWineD3DResource *resource;
5568 IWineD3DSurfaceImpl *surface;
5571 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5574 ERR("Failed to get resource, hr %#x\n", hr);
5578 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5580 FIXME("Only supported on surface resources\n");
5581 IWineD3DResource_Release(resource);
5585 surface = (IWineD3DSurfaceImpl *)resource;
5587 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5589 color_fill_fbo(iface, surface, NULL, color);
5596 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5598 c = ((DWORD)(color[2] * 255.0f));
5599 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5600 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5601 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5603 /* Just forward this to the DirectDraw blitting engine */
5604 memset(&BltFx, 0, sizeof(BltFx));
5605 BltFx.dwSize = sizeof(BltFx);
5606 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5607 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5608 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5611 ERR("Blt failed, hr %#x\n", hr);
5615 IWineD3DResource_Release(resource);
5618 /* rendertarget and depth stencil functions */
5619 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5622 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5624 ERR("(%p) : Only %d render targets are supported.\n",
5625 This, This->adapter->gl_info.limits.buffers);
5626 return WINED3DERR_INVALIDCALL;
5629 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5630 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5631 /* Note inc ref on returned surface */
5632 if(*ppRenderTarget != NULL)
5633 IWineD3DSurface_AddRef(*ppRenderTarget);
5637 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5638 IWineD3DSurface *front, IWineD3DSurface *back)
5640 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5641 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5642 IWineD3DSwapChainImpl *swapchain;
5645 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5647 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5649 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5653 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5655 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5656 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5657 return WINED3DERR_INVALIDCALL;
5662 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5664 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5665 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5666 return WINED3DERR_INVALIDCALL;
5669 if (!swapchain->back_buffers)
5671 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5672 if (!swapchain->back_buffers)
5674 ERR("Failed to allocate back buffer array memory.\n");
5675 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5676 return E_OUTOFMEMORY;
5681 if (swapchain->front_buffer != front_impl)
5683 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5685 if (swapchain->front_buffer)
5687 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5688 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5690 swapchain->front_buffer = front_impl;
5694 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5695 front_impl->Flags |= SFLAG_SWAPCHAIN;
5699 if (swapchain->back_buffers[0] != back_impl)
5701 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5703 if (swapchain->back_buffers[0])
5705 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5706 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5708 swapchain->back_buffers[0] = back_impl;
5712 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5713 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5714 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5715 swapchain->presentParms.BackBufferCount = 1;
5717 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5718 back_impl->Flags |= SFLAG_SWAPCHAIN;
5722 swapchain->presentParms.BackBufferCount = 0;
5723 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5724 swapchain->back_buffers = NULL;
5728 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5732 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5735 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5737 if(*ppZStencilSurface != NULL) {
5738 /* Note inc ref on returned surface */
5739 IWineD3DSurface_AddRef(*ppZStencilSurface);
5742 return WINED3DERR_NOTFOUND;
5746 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5747 BOOL set_viewport) {
5748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5750 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5752 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5754 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5755 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5756 return WINED3DERR_INVALIDCALL;
5759 /* MSDN says that null disables the render target
5760 but a device must always be associated with a render target
5761 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5763 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5764 FIXME("Trying to set render target 0 to NULL\n");
5765 return WINED3DERR_INVALIDCALL;
5767 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5768 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5769 return WINED3DERR_INVALIDCALL;
5772 /* If we are trying to set what we already have, don't bother */
5773 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5775 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5779 IWineD3DSurface_AddRef(pRenderTarget);
5780 if (This->render_targets[RenderTargetIndex])
5781 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5782 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5784 /* Render target 0 is special */
5785 if(RenderTargetIndex == 0 && set_viewport) {
5786 /* Finally, reset the viewport and scissor rect as the MSDN states.
5787 * Tests show that stateblock recording is ignored, the change goes
5788 * directly into the primary stateblock.
5790 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5791 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5792 This->stateBlock->viewport.X = 0;
5793 This->stateBlock->viewport.Y = 0;
5794 This->stateBlock->viewport.MaxZ = 1.0f;
5795 This->stateBlock->viewport.MinZ = 0.0f;
5796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5798 This->stateBlock->scissorRect.top = 0;
5799 This->stateBlock->scissorRect.left = 0;
5800 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5801 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5807 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 IWineD3DSurfaceImpl *tmp;
5811 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5813 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5815 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5819 if (This->depth_stencil)
5821 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5822 || This->depth_stencil->Flags & SFLAG_DISCARD)
5824 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5825 This->depth_stencil->currentDesc.Width,
5826 This->depth_stencil->currentDesc.Height);
5827 if (This->depth_stencil == This->onscreen_depth_stencil)
5829 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5830 This->onscreen_depth_stencil = NULL;
5835 tmp = This->depth_stencil;
5836 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5837 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5838 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5840 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5842 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5851 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5852 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5854 /* TODO: the use of Impl is deprecated. */
5855 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5856 WINED3DLOCKED_RECT lockedRect;
5858 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5860 /* some basic validation checks */
5861 if (This->cursorTexture)
5863 struct wined3d_context *context = context_acquire(This, NULL);
5865 glDeleteTextures(1, &This->cursorTexture);
5867 context_release(context);
5868 This->cursorTexture = 0;
5871 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5872 This->haveHardwareCursor = TRUE;
5874 This->haveHardwareCursor = FALSE;
5877 WINED3DLOCKED_RECT rect;
5879 /* MSDN: Cursor must be A8R8G8B8 */
5880 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5882 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5883 return WINED3DERR_INVALIDCALL;
5886 /* MSDN: Cursor must be smaller than the display mode */
5887 if(pSur->currentDesc.Width > This->ddraw_width ||
5888 pSur->currentDesc.Height > This->ddraw_height) {
5889 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5890 return WINED3DERR_INVALIDCALL;
5893 if (!This->haveHardwareCursor) {
5894 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5896 /* Do not store the surface's pointer because the application may
5897 * release it after setting the cursor image. Windows doesn't
5898 * addref the set surface, so we can't do this either without
5899 * creating circular refcount dependencies. Copy out the gl texture
5902 This->cursorWidth = pSur->currentDesc.Width;
5903 This->cursorHeight = pSur->currentDesc.Height;
5904 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5906 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5907 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5908 struct wined3d_context *context;
5909 char *mem, *bits = rect.pBits;
5910 GLint intfmt = format_desc->glInternal;
5911 GLint format = format_desc->glFormat;
5912 GLint type = format_desc->glType;
5913 INT height = This->cursorHeight;
5914 INT width = This->cursorWidth;
5915 INT bpp = format_desc->byte_count;
5919 /* Reformat the texture memory (pitch and width can be
5921 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5922 for(i = 0; i < height; i++)
5923 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5924 IWineD3DSurface_UnlockRect(pCursorBitmap);
5926 context = context_acquire(This, NULL);
5930 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5932 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5933 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5936 /* Make sure that a proper texture unit is selected */
5937 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5938 checkGLcall("glActiveTextureARB");
5939 sampler = This->rev_tex_unit_map[0];
5940 if (sampler != WINED3D_UNMAPPED_STAGE)
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5944 /* Create a new cursor texture */
5945 glGenTextures(1, &This->cursorTexture);
5946 checkGLcall("glGenTextures");
5947 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5948 checkGLcall("glBindTexture");
5949 /* Copy the bitmap memory into the cursor texture */
5950 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5951 HeapFree(GetProcessHeap(), 0, mem);
5952 checkGLcall("glTexImage2D");
5954 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5956 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5957 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5962 context_release(context);
5966 FIXME("A cursor texture was not returned.\n");
5967 This->cursorTexture = 0;
5972 /* Draw a hardware cursor */
5973 ICONINFO cursorInfo;
5975 /* Create and clear maskBits because it is not needed for
5976 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5978 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5979 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5980 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5981 WINED3DLOCK_NO_DIRTY_UPDATE |
5982 WINED3DLOCK_READONLY
5984 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5985 pSur->currentDesc.Height);
5987 cursorInfo.fIcon = FALSE;
5988 cursorInfo.xHotspot = XHotSpot;
5989 cursorInfo.yHotspot = YHotSpot;
5990 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
5992 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
5993 1, 32, lockedRect.pBits);
5994 IWineD3DSurface_UnlockRect(pCursorBitmap);
5995 /* Create our cursor and clean up. */
5996 cursor = CreateIconIndirect(&cursorInfo);
5998 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5999 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6000 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6001 This->hardwareCursor = cursor;
6002 HeapFree(GetProcessHeap(), 0, maskBits);
6006 This->xHotSpot = XHotSpot;
6007 This->yHotSpot = YHotSpot;
6011 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6013 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6015 This->xScreenSpace = XScreenSpace;
6016 This->yScreenSpace = YScreenSpace;
6022 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6024 BOOL oldVisible = This->bCursorVisible;
6027 TRACE("(%p) : visible(%d)\n", This, bShow);
6030 * When ShowCursor is first called it should make the cursor appear at the OS's last
6031 * known cursor position. Because of this, some applications just repetitively call
6032 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6035 This->xScreenSpace = pt.x;
6036 This->yScreenSpace = pt.y;
6038 if (This->haveHardwareCursor) {
6039 This->bCursorVisible = bShow;
6041 SetCursor(This->hardwareCursor);
6047 if (This->cursorTexture)
6048 This->bCursorVisible = bShow;
6054 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6055 TRACE("checking resource %p for eviction\n", resource);
6056 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6057 TRACE("Evicting %p\n", resource);
6058 IWineD3DResource_UnLoad(resource);
6060 IWineD3DResource_Release(resource);
6064 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6066 TRACE("iface %p.\n", iface);
6068 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6069 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6070 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6075 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6077 IWineD3DDeviceImpl *device = surface->resource.device;
6078 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6080 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6081 if(surface->Flags & SFLAG_DIBSECTION) {
6082 /* Release the DC */
6083 SelectObject(surface->hDC, surface->dib.holdbitmap);
6084 DeleteDC(surface->hDC);
6085 /* Release the DIB section */
6086 DeleteObject(surface->dib.DIBsection);
6087 surface->dib.bitmap_data = NULL;
6088 surface->resource.allocatedMemory = NULL;
6089 surface->Flags &= ~SFLAG_DIBSECTION;
6091 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6092 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6093 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6094 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6096 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6097 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6099 surface->pow2Width = surface->pow2Height = 1;
6100 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6101 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6104 if (surface->texture_name)
6106 struct wined3d_context *context = context_acquire(device, NULL);
6108 glDeleteTextures(1, &surface->texture_name);
6110 context_release(context);
6111 surface->texture_name = 0;
6112 surface->Flags &= ~SFLAG_CLIENT;
6114 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6115 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6116 surface->Flags |= SFLAG_NONPOW2;
6118 surface->Flags &= ~SFLAG_NONPOW2;
6120 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6121 surface->resource.allocatedMemory = NULL;
6122 surface->resource.heapMemory = NULL;
6123 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6125 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6127 if (!surface_init_sysmem(surface))
6129 return E_OUTOFMEMORY;
6134 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6135 TRACE("Unloading resource %p\n", resource);
6136 IWineD3DResource_UnLoad(resource);
6137 IWineD3DResource_Release(resource);
6141 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6144 WINED3DDISPLAYMODE m;
6147 /* All Windowed modes are supported, as is leaving the current mode */
6148 if(pp->Windowed) return TRUE;
6149 if(!pp->BackBufferWidth) return TRUE;
6150 if(!pp->BackBufferHeight) return TRUE;
6152 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6153 for(i = 0; i < count; i++) {
6154 memset(&m, 0, sizeof(m));
6155 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6157 ERR("EnumAdapterModes failed\n");
6159 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6160 /* Mode found, it is supported */
6164 /* Mode not found -> not supported */
6168 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6171 const struct wined3d_gl_info *gl_info;
6172 struct wined3d_context *context;
6173 IWineD3DBaseShaderImpl *shader;
6175 context = context_acquire(This, NULL);
6176 gl_info = context->gl_info;
6178 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6179 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6180 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6184 if(This->depth_blt_texture) {
6185 glDeleteTextures(1, &This->depth_blt_texture);
6186 This->depth_blt_texture = 0;
6188 if (This->depth_blt_rb) {
6189 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6190 This->depth_blt_rb = 0;
6191 This->depth_blt_rb_w = 0;
6192 This->depth_blt_rb_h = 0;
6196 This->blitter->free_private(iface);
6197 This->frag_pipe->free_private(iface);
6198 This->shader_backend->shader_free_private(iface);
6199 destroy_dummy_textures(This, gl_info);
6201 context_release(context);
6203 while (This->numContexts)
6205 context_destroy(This, This->contexts[0]);
6207 HeapFree(GetProcessHeap(), 0, swapchain->context);
6208 swapchain->context = NULL;
6209 swapchain->num_contexts = 0;
6212 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6215 struct wined3d_context *context;
6217 IWineD3DSurfaceImpl *target;
6219 /* Recreate the primary swapchain's context */
6220 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6221 if (!swapchain->context)
6223 ERR("Failed to allocate memory for swapchain context array.\n");
6224 return E_OUTOFMEMORY;
6227 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6228 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6230 WARN("Failed to create context.\n");
6231 HeapFree(GetProcessHeap(), 0, swapchain->context);
6235 swapchain->context[0] = context;
6236 swapchain->num_contexts = 1;
6237 create_dummy_textures(This);
6238 context_release(context);
6240 hr = This->shader_backend->shader_alloc_private(iface);
6243 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6247 hr = This->frag_pipe->alloc_private(iface);
6250 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6251 This->shader_backend->shader_free_private(iface);
6255 hr = This->blitter->alloc_private(iface);
6258 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6259 This->frag_pipe->free_private(iface);
6260 This->shader_backend->shader_free_private(iface);
6267 context_acquire(This, NULL);
6268 destroy_dummy_textures(This, context->gl_info);
6269 context_release(context);
6270 context_destroy(This, context);
6271 HeapFree(GetProcessHeap(), 0, swapchain->context);
6272 swapchain->num_contexts = 0;
6276 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6278 IWineD3DSwapChainImpl *swapchain;
6280 BOOL DisplayModeChanged = FALSE;
6281 WINED3DDISPLAYMODE mode;
6282 TRACE("(%p)\n", This);
6284 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6286 ERR("Failed to get the first implicit swapchain\n");
6290 if(!is_display_mode_supported(This, pPresentationParameters)) {
6291 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6292 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6293 pPresentationParameters->BackBufferHeight);
6294 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6295 return WINED3DERR_INVALIDCALL;
6298 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6299 * on an existing gl context, so there's no real need for recreation.
6301 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6303 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6305 TRACE("New params:\n");
6306 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6307 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6308 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6309 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6310 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6311 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6312 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6313 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6314 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6315 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6316 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6317 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6318 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6320 /* No special treatment of these parameters. Just store them */
6321 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6322 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6323 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6324 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6326 /* What to do about these? */
6327 if(pPresentationParameters->BackBufferCount != 0 &&
6328 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6329 ERR("Cannot change the back buffer count yet\n");
6331 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6332 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6333 ERR("Cannot change the back buffer format yet\n");
6335 if(pPresentationParameters->hDeviceWindow != NULL &&
6336 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6337 ERR("Cannot change the device window yet\n");
6339 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6343 TRACE("Creating the depth stencil buffer\n");
6345 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6347 pPresentationParameters->BackBufferWidth,
6348 pPresentationParameters->BackBufferHeight,
6349 pPresentationParameters->AutoDepthStencilFormat,
6350 pPresentationParameters->MultiSampleType,
6351 pPresentationParameters->MultiSampleQuality,
6353 (IWineD3DSurface **)&This->auto_depth_stencil);
6356 ERR("Failed to create the depth stencil buffer\n");
6357 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6358 return WINED3DERR_INVALIDCALL;
6362 if (This->onscreen_depth_stencil)
6364 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6365 This->onscreen_depth_stencil = NULL;
6368 /* Reset the depth stencil */
6369 if (pPresentationParameters->EnableAutoDepthStencil)
6370 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6372 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6374 TRACE("Resetting stateblock\n");
6375 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6376 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6378 delete_opengl_contexts(iface, swapchain);
6380 if(pPresentationParameters->Windowed) {
6381 mode.Width = swapchain->orig_width;
6382 mode.Height = swapchain->orig_height;
6383 mode.RefreshRate = 0;
6384 mode.Format = swapchain->presentParms.BackBufferFormat;
6386 mode.Width = pPresentationParameters->BackBufferWidth;
6387 mode.Height = pPresentationParameters->BackBufferHeight;
6388 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6389 mode.Format = swapchain->presentParms.BackBufferFormat;
6392 /* Should Width == 800 && Height == 0 set 800x600? */
6393 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6394 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6395 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6399 if(!pPresentationParameters->Windowed) {
6400 DisplayModeChanged = TRUE;
6402 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6403 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6405 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6408 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6412 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6414 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6417 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6421 if (This->auto_depth_stencil)
6423 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6426 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6432 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6433 || DisplayModeChanged)
6435 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6437 if (!pPresentationParameters->Windowed)
6439 if(swapchain->presentParms.Windowed) {
6440 /* switch from windowed to fs */
6441 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6442 pPresentationParameters->BackBufferHeight);
6444 /* Fullscreen -> fullscreen mode change */
6445 MoveWindow(swapchain->device_window, 0, 0,
6446 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6450 else if (!swapchain->presentParms.Windowed)
6452 /* Fullscreen -> windowed switch */
6453 swapchain_restore_fullscreen_window(swapchain);
6455 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6456 } else if(!pPresentationParameters->Windowed) {
6457 DWORD style = This->style, exStyle = This->exStyle;
6458 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6459 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6460 * Reset to clear up their mess. Guild Wars also loses the device during that.
6464 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6465 pPresentationParameters->BackBufferHeight);
6466 This->style = style;
6467 This->exStyle = exStyle;
6470 /* Note: No parent needed for initial internal stateblock */
6471 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6472 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6473 else TRACE("Created stateblock %p\n", This->stateBlock);
6474 This->updateStateBlock = This->stateBlock;
6475 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6477 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6479 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6482 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6485 GetClientRect(swapchain->win_handle, &client_rect);
6487 if(!swapchain->presentParms.BackBufferCount)
6489 TRACE("Single buffered rendering\n");
6490 swapchain->render_to_fbo = FALSE;
6492 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6493 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6495 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6496 swapchain->presentParms.BackBufferWidth,
6497 swapchain->presentParms.BackBufferHeight,
6498 client_rect.right, client_rect.bottom);
6499 swapchain->render_to_fbo = TRUE;
6503 TRACE("Rendering directly to GL_BACK\n");
6504 swapchain->render_to_fbo = FALSE;
6508 hr = create_primary_opengl_context(iface, swapchain);
6509 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6511 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6517 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6519 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6521 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6527 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6529 TRACE("(%p) : pParameters %p\n", This, pParameters);
6531 *pParameters = This->createParms;
6535 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6536 IWineD3DSwapChain *swapchain;
6538 TRACE("Relaying to swapchain\n");
6540 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6541 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6542 IWineD3DSwapChain_Release(swapchain);
6546 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6547 IWineD3DSwapChain *swapchain;
6549 TRACE("Relaying to swapchain\n");
6551 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6552 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6553 IWineD3DSwapChain_Release(swapchain);
6558 /** ********************************************************
6559 * Notification functions
6560 ** ********************************************************/
6561 /** This function must be called in the release of a resource when ref == 0,
6562 * the contents of resource must still be correct,
6563 * any handles to other resource held by the caller must be closed
6564 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6565 *****************************************************/
6566 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6568 TRACE("(%p) : Adding resource %p\n", This, resource);
6570 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6573 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6575 TRACE("(%p) : Removing resource %p\n", This, resource);
6577 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6580 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6582 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6585 TRACE("(%p) : resource %p\n", This, resource);
6587 context_resource_released((IWineD3DDevice *)This, resource, type);
6590 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6591 case WINED3DRTYPE_SURFACE: {
6594 if (This->d3d_initialized)
6596 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6598 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6599 This->render_targets[i] = NULL;
6601 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6602 This->depth_stencil = NULL;
6607 case WINED3DRTYPE_TEXTURE:
6608 case WINED3DRTYPE_CUBETEXTURE:
6609 case WINED3DRTYPE_VOLUMETEXTURE:
6610 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6611 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6612 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6613 This->stateBlock->textures[counter] = NULL;
6615 if (This->updateStateBlock != This->stateBlock ){
6616 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6617 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6618 This->updateStateBlock->textures[counter] = NULL;
6623 case WINED3DRTYPE_VOLUME:
6624 /* TODO: nothing really? */
6626 case WINED3DRTYPE_BUFFER:
6629 TRACE("Cleaning up stream pointers\n");
6631 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6632 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6633 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6635 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6636 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6637 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6638 This->updateStateBlock->streamSource[streamNumber] = 0;
6639 /* Set changed flag? */
6642 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6643 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6644 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6645 This->stateBlock->streamSource[streamNumber] = 0;
6650 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6651 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6652 This->updateStateBlock->pIndexData = NULL;
6655 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6656 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6657 This->stateBlock->pIndexData = NULL;
6664 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6669 /* Remove the resource from the resourceStore */
6670 device_resource_remove(This, resource);
6672 TRACE("Resource released\n");
6676 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6678 IWineD3DResourceImpl *resource, *cursor;
6680 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6682 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6683 TRACE("enumerating resource %p\n", resource);
6684 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6685 ret = pCallback((IWineD3DResource *) resource, pData);
6686 if(ret == S_FALSE) {
6687 TRACE("Canceling enumeration\n");
6694 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6697 IWineD3DResourceImpl *resource;
6699 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6701 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6702 if (type == WINED3DRTYPE_SURFACE)
6704 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6706 TRACE("Found surface %p for dc %p.\n", resource, dc);
6707 *surface = (IWineD3DSurface *)resource;
6713 return WINED3DERR_INVALIDCALL;
6716 /**********************************************************
6717 * IWineD3DDevice VTbl follows
6718 **********************************************************/
6720 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6722 /*** IUnknown methods ***/
6723 IWineD3DDeviceImpl_QueryInterface,
6724 IWineD3DDeviceImpl_AddRef,
6725 IWineD3DDeviceImpl_Release,
6726 /*** IWineD3DDevice methods ***/
6727 IWineD3DDeviceImpl_GetParent,
6728 /*** Creation methods**/
6729 IWineD3DDeviceImpl_CreateBuffer,
6730 IWineD3DDeviceImpl_CreateVertexBuffer,
6731 IWineD3DDeviceImpl_CreateIndexBuffer,
6732 IWineD3DDeviceImpl_CreateStateBlock,
6733 IWineD3DDeviceImpl_CreateSurface,
6734 IWineD3DDeviceImpl_CreateRendertargetView,
6735 IWineD3DDeviceImpl_CreateTexture,
6736 IWineD3DDeviceImpl_CreateVolumeTexture,
6737 IWineD3DDeviceImpl_CreateVolume,
6738 IWineD3DDeviceImpl_CreateCubeTexture,
6739 IWineD3DDeviceImpl_CreateQuery,
6740 IWineD3DDeviceImpl_CreateSwapChain,
6741 IWineD3DDeviceImpl_CreateVertexDeclaration,
6742 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6743 IWineD3DDeviceImpl_CreateVertexShader,
6744 IWineD3DDeviceImpl_CreateGeometryShader,
6745 IWineD3DDeviceImpl_CreatePixelShader,
6746 IWineD3DDeviceImpl_CreatePalette,
6747 /*** Odd functions **/
6748 IWineD3DDeviceImpl_Init3D,
6749 IWineD3DDeviceImpl_InitGDI,
6750 IWineD3DDeviceImpl_Uninit3D,
6751 IWineD3DDeviceImpl_UninitGDI,
6752 IWineD3DDeviceImpl_SetMultithreaded,
6753 IWineD3DDeviceImpl_EvictManagedResources,
6754 IWineD3DDeviceImpl_GetAvailableTextureMem,
6755 IWineD3DDeviceImpl_GetBackBuffer,
6756 IWineD3DDeviceImpl_GetCreationParameters,
6757 IWineD3DDeviceImpl_GetDeviceCaps,
6758 IWineD3DDeviceImpl_GetDirect3D,
6759 IWineD3DDeviceImpl_GetDisplayMode,
6760 IWineD3DDeviceImpl_SetDisplayMode,
6761 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6762 IWineD3DDeviceImpl_GetRasterStatus,
6763 IWineD3DDeviceImpl_GetSwapChain,
6764 IWineD3DDeviceImpl_Reset,
6765 IWineD3DDeviceImpl_SetDialogBoxMode,
6766 IWineD3DDeviceImpl_SetCursorProperties,
6767 IWineD3DDeviceImpl_SetCursorPosition,
6768 IWineD3DDeviceImpl_ShowCursor,
6769 /*** Getters and setters **/
6770 IWineD3DDeviceImpl_SetClipPlane,
6771 IWineD3DDeviceImpl_GetClipPlane,
6772 IWineD3DDeviceImpl_SetClipStatus,
6773 IWineD3DDeviceImpl_GetClipStatus,
6774 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6775 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6776 IWineD3DDeviceImpl_SetDepthStencilSurface,
6777 IWineD3DDeviceImpl_GetDepthStencilSurface,
6778 IWineD3DDeviceImpl_SetGammaRamp,
6779 IWineD3DDeviceImpl_GetGammaRamp,
6780 IWineD3DDeviceImpl_SetIndexBuffer,
6781 IWineD3DDeviceImpl_GetIndexBuffer,
6782 IWineD3DDeviceImpl_SetBaseVertexIndex,
6783 IWineD3DDeviceImpl_GetBaseVertexIndex,
6784 IWineD3DDeviceImpl_SetLight,
6785 IWineD3DDeviceImpl_GetLight,
6786 IWineD3DDeviceImpl_SetLightEnable,
6787 IWineD3DDeviceImpl_GetLightEnable,
6788 IWineD3DDeviceImpl_SetMaterial,
6789 IWineD3DDeviceImpl_GetMaterial,
6790 IWineD3DDeviceImpl_SetNPatchMode,
6791 IWineD3DDeviceImpl_GetNPatchMode,
6792 IWineD3DDeviceImpl_SetPaletteEntries,
6793 IWineD3DDeviceImpl_GetPaletteEntries,
6794 IWineD3DDeviceImpl_SetPixelShader,
6795 IWineD3DDeviceImpl_GetPixelShader,
6796 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6797 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6798 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6799 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6800 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6801 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6802 IWineD3DDeviceImpl_SetRenderState,
6803 IWineD3DDeviceImpl_GetRenderState,
6804 IWineD3DDeviceImpl_SetRenderTarget,
6805 IWineD3DDeviceImpl_GetRenderTarget,
6806 IWineD3DDeviceImpl_SetFrontBackBuffers,
6807 IWineD3DDeviceImpl_SetSamplerState,
6808 IWineD3DDeviceImpl_GetSamplerState,
6809 IWineD3DDeviceImpl_SetScissorRect,
6810 IWineD3DDeviceImpl_GetScissorRect,
6811 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6812 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6813 IWineD3DDeviceImpl_SetStreamSource,
6814 IWineD3DDeviceImpl_GetStreamSource,
6815 IWineD3DDeviceImpl_SetStreamSourceFreq,
6816 IWineD3DDeviceImpl_GetStreamSourceFreq,
6817 IWineD3DDeviceImpl_SetTexture,
6818 IWineD3DDeviceImpl_GetTexture,
6819 IWineD3DDeviceImpl_SetTextureStageState,
6820 IWineD3DDeviceImpl_GetTextureStageState,
6821 IWineD3DDeviceImpl_SetTransform,
6822 IWineD3DDeviceImpl_GetTransform,
6823 IWineD3DDeviceImpl_SetVertexDeclaration,
6824 IWineD3DDeviceImpl_GetVertexDeclaration,
6825 IWineD3DDeviceImpl_SetVertexShader,
6826 IWineD3DDeviceImpl_GetVertexShader,
6827 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6828 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6829 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6830 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6831 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6832 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6833 IWineD3DDeviceImpl_SetViewport,
6834 IWineD3DDeviceImpl_GetViewport,
6835 IWineD3DDeviceImpl_MultiplyTransform,
6836 IWineD3DDeviceImpl_ValidateDevice,
6837 IWineD3DDeviceImpl_ProcessVertices,
6838 /*** State block ***/
6839 IWineD3DDeviceImpl_BeginStateBlock,
6840 IWineD3DDeviceImpl_EndStateBlock,
6841 /*** Scene management ***/
6842 IWineD3DDeviceImpl_BeginScene,
6843 IWineD3DDeviceImpl_EndScene,
6844 IWineD3DDeviceImpl_Present,
6845 IWineD3DDeviceImpl_Clear,
6846 IWineD3DDeviceImpl_ClearRendertargetView,
6848 IWineD3DDeviceImpl_SetPrimitiveType,
6849 IWineD3DDeviceImpl_GetPrimitiveType,
6850 IWineD3DDeviceImpl_DrawPrimitive,
6851 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6852 IWineD3DDeviceImpl_DrawPrimitiveUP,
6853 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6854 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6855 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6856 IWineD3DDeviceImpl_DrawRectPatch,
6857 IWineD3DDeviceImpl_DrawTriPatch,
6858 IWineD3DDeviceImpl_DeletePatch,
6859 IWineD3DDeviceImpl_ColorFill,
6860 IWineD3DDeviceImpl_UpdateTexture,
6861 IWineD3DDeviceImpl_UpdateSurface,
6862 IWineD3DDeviceImpl_GetFrontBufferData,
6863 /*** object tracking ***/
6864 IWineD3DDeviceImpl_EnumResources,
6865 IWineD3DDeviceImpl_GetSurfaceFromDC,
6866 IWineD3DDeviceImpl_AcquireFocusWindow,
6867 IWineD3DDeviceImpl_ReleaseFocusWindow,
6870 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6871 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6872 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6874 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6875 const struct fragment_pipeline *fragment_pipeline;
6876 struct shader_caps shader_caps;
6877 struct fragment_caps ffp_caps;
6878 WINED3DDISPLAYMODE mode;
6882 device->lpVtbl = &IWineD3DDevice_Vtbl;
6884 device->wined3d = (IWineD3D *)wined3d;
6885 IWineD3D_AddRef(device->wined3d);
6886 device->adapter = wined3d->adapter_count ? adapter : NULL;
6887 device->parent = parent;
6888 device->device_parent = device_parent;
6889 list_init(&device->resources);
6890 list_init(&device->shaders);
6892 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6893 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6895 /* Get the initial screen setup for ddraw. */
6896 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6899 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6900 IWineD3D_Release(device->wined3d);
6903 device->ddraw_width = mode.Width;
6904 device->ddraw_height = mode.Height;
6905 device->ddraw_format = mode.Format;
6907 /* Save the creation parameters. */
6908 device->createParms.AdapterOrdinal = adapter_idx;
6909 device->createParms.DeviceType = device_type;
6910 device->createParms.hFocusWindow = focus_window;
6911 device->createParms.BehaviorFlags = flags;
6913 device->devType = device_type;
6914 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6916 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6917 device->shader_backend = adapter->shader_backend;
6919 if (device->shader_backend)
6921 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6922 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6923 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6924 device->vs_clipping = shader_caps.VSClipping;
6926 fragment_pipeline = adapter->fragment_pipe;
6927 device->frag_pipe = fragment_pipeline;
6928 if (fragment_pipeline)
6930 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6931 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6933 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6934 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6937 ERR("Failed to compile state table, hr %#x.\n", hr);
6938 IWineD3D_Release(device->wined3d);
6942 device->blitter = adapter->blitter;
6948 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6949 DWORD rep = This->StateTable[state].representative;
6950 struct wined3d_context *context;
6955 for(i = 0; i < This->numContexts; i++) {
6956 context = This->contexts[i];
6957 if(isStateDirty(context, rep)) continue;
6959 context->dirtyArray[context->numDirtyEntries++] = rep;
6960 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6961 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6962 context->isStateDirty[idx] |= (1 << shift);
6966 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6968 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6969 *width = context->current_rt->pow2Width;
6970 *height = context->current_rt->pow2Height;
6973 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6975 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6976 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6977 * current context's drawable, which is the size of the back buffer of the swapchain
6978 * the active context belongs to. */
6979 *width = swapchain->presentParms.BackBufferWidth;
6980 *height = swapchain->presentParms.BackBufferHeight;
6983 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6984 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6986 if (device->filter_messages)
6988 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6989 window, message, wparam, lparam);
6990 return DefWindowProcW(window, message, wparam, lparam);
6993 if (message == WM_DESTROY)
6995 TRACE("unregister window %p.\n", window);
6996 wined3d_unregister_window(window);
6998 if (device->focus_window == window) device->focus_window = NULL;
6999 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7002 return CallWindowProcW(proc, window, message, wparam, lparam);