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->id), 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->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
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->id == 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 e->format = wined3d_get_format(gl_info, strided->format);
347 e->stride = strided->dwStride;
348 e->data = strided->lpData;
350 e->buffer_object = 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
354 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
358 memset(stream_info, 0, sizeof(*stream_info));
360 if (strided->position.lpData)
361 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
362 if (strided->normal.lpData)
363 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
364 if (strided->diffuse.lpData)
365 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
366 if (strided->specular.lpData)
367 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
369 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
371 if (strided->texCoords[i].lpData)
372 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
373 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
376 stream_info->position_transformed = strided->position_transformed;
378 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
380 if (!stream_info->elements[i].format) continue;
382 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
383 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
385 stream_info->swizzle_map |= 1 << i;
387 stream_info->use_map |= 1 << i;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
414 struct wined3d_stream_info *stream_info = &device->strided_streams;
415 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
416 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
419 if (device->up_strided)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
424 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
432 if (vs && !stream_info->position_transformed)
434 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device->useDrawStridedSlow = TRUE;
441 device->useDrawStridedSlow = FALSE;
446 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
447 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
448 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
450 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
452 device->useDrawStridedSlow = TRUE;
456 device->useDrawStridedSlow = FALSE;
461 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
463 IWineD3DBaseTextureImpl *texture;
464 enum WINED3DSRGB srgb;
466 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
467 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
468 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
471 void device_preload_textures(IWineD3DDeviceImpl *device)
473 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
476 if (use_vs(stateblock))
478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
480 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
481 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
485 if (use_ps(stateblock))
487 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
489 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, i);
495 WORD ffu_map = device->fixed_function_usage_map;
497 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
500 device_preload_texture(stateblock, i);
505 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
507 struct wined3d_context **new_array;
509 TRACE("Adding context %p.\n", context);
511 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
512 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
516 ERR("Failed to grow the context array.\n");
520 new_array[device->numContexts++] = context;
521 device->contexts = new_array;
525 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
527 struct wined3d_context **new_array;
531 TRACE("Removing context %p.\n", context);
533 for (i = 0; i < device->numContexts; ++i)
535 if (device->contexts[i] == context)
544 ERR("Context %p doesn't exist in context array.\n", context);
548 if (!--device->numContexts)
550 HeapFree(GetProcessHeap(), 0, device->contexts);
551 device->contexts = NULL;
555 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
556 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
559 ERR("Failed to shrink context array. Oh well.\n");
563 device->contexts = new_array;
566 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
568 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
569 WINED3DVIEWPORT *vp = &stateblock->viewport;
571 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
573 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
575 IntersectRect(rect, rect, &stateblock->scissorRect);
579 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
580 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
582 if (device->onscreen_depth_stencil)
584 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
585 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
586 device->onscreen_depth_stencil->ds_current_size.cx,
587 device->onscreen_depth_stencil->ds_current_size.cy);
588 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
590 device->onscreen_depth_stencil = depth_stencil;
591 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
594 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
596 /* partial draw rect */
597 if (draw_rect->left || draw_rect->top
598 || draw_rect->right < target->currentDesc.Width
599 || draw_rect->bottom < target->currentDesc.Height)
602 /* partial clear rect */
603 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
604 || clear_rect->right < target->currentDesc.Width
605 || clear_rect->bottom < target->currentDesc.Height))
611 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
612 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
614 RECT current_rect, r;
616 if (ds->Flags & location)
617 SetRect(¤t_rect, 0, 0,
618 ds->ds_current_size.cx,
619 ds->ds_current_size.cy);
621 SetRectEmpty(¤t_rect);
623 IntersectRect(&r, draw_rect, ¤t_rect);
624 if (EqualRect(&r, draw_rect))
626 /* current_rect ⊇ draw_rect, modify only. */
627 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
631 if (EqualRect(&r, ¤t_rect))
633 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
637 /* Full clear, modify only. */
638 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
642 IntersectRect(&r, draw_rect, clear_rect);
643 if (EqualRect(&r, draw_rect))
645 /* clear_rect ⊇ draw_rect, modify only. */
646 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
652 surface_load_ds_location(ds, context, location);
653 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
656 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
657 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
658 const WINED3DCOLORVALUE *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;
668 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
669 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
670 * for the cleared parts, and the untouched parts.
672 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
673 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
674 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
675 * checking all this if the dest surface is in the drawable anyway. */
676 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
678 for (i = 0; i < rt_count; ++i)
680 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
684 context = context_acquire(device, target);
687 context_release(context);
688 WARN("Invalid context, skipping clear.\n");
692 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
694 target->get_drawable_size(context, &drawable_width, &drawable_height);
698 /* Only set the values up once, as they are not changing. */
699 if (flags & WINED3DCLEAR_STENCIL)
701 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
703 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
707 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
708 glClearStencil(stencil);
709 checkGLcall("glClearStencil");
710 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
713 if (flags & WINED3DCLEAR_ZBUFFER)
715 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
717 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
718 device_switch_onscreen_ds(device, context, depth_stencil);
719 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
720 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
722 glDepthMask(GL_TRUE);
723 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
725 checkGLcall("glClearDepth");
726 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
729 if (flags & WINED3DCLEAR_TARGET)
731 for (i = 0; i < rt_count; ++i)
733 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
736 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
737 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
741 glClearColor(color->r, color->g, color->b, color->a);
742 checkGLcall("glClearColor");
743 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
748 if (context->render_offscreen)
750 glScissor(draw_rect->left, draw_rect->top,
751 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
755 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
756 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
758 checkGLcall("glScissor");
760 checkGLcall("glClear");
766 /* Now process each rect in turn. */
767 for (i = 0; i < rect_count; ++i)
769 /* Note that GL uses lower left, width/height. */
770 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
772 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
773 wine_dbgstr_rect(&clear_rect[i]),
774 wine_dbgstr_rect(¤t_rect));
776 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
777 * The rectangle is not cleared, no error is returned, but further rectanlges are
778 * still cleared if they are valid. */
779 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
781 TRACE("Rectangle with negative dimensions, ignoring.\n");
785 if (context->render_offscreen)
787 glScissor(current_rect.left, current_rect.top,
788 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
792 glScissor(current_rect.left, drawable_height - current_rect.bottom,
793 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
795 checkGLcall("glScissor");
798 checkGLcall("glClear");
804 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
805 && target->container.u.swapchain->front_buffer == target))
806 wglFlush(); /* Flush to ensure ordering across contexts. */
808 context_release(context);
814 /**********************************************************
815 * IUnknown parts follows
816 **********************************************************/
818 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
820 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
822 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
823 || IsEqualGUID(riid, &IID_IUnknown))
825 IUnknown_AddRef(iface);
830 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
833 return E_NOINTERFACE;
836 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
838 ULONG refCount = InterlockedIncrement(&This->ref);
840 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
844 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
846 ULONG refCount = InterlockedDecrement(&This->ref);
848 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
853 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
854 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
855 This->multistate_funcs[i] = NULL;
858 /* TODO: Clean up all the surfaces and textures! */
859 /* NOTE: You must release the parent if the object was created via a callback
860 ** ***************************/
862 if (!list_empty(&This->resources))
864 IWineD3DResourceImpl *resource;
865 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
867 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
869 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
870 FIXME("Leftover resource %p with type %s (%#x).\n",
871 resource, debug_d3dresourcetype(type), type);
875 if(This->contexts) ERR("Context array not freed!\n");
876 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
877 This->haveHardwareCursor = FALSE;
879 IWineD3D_Release(This->wined3d);
880 This->wined3d = NULL;
881 HeapFree(GetProcessHeap(), 0, This);
882 TRACE("Freed device %p\n", This);
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
889 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
892 struct wined3d_buffer *object;
895 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
897 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
900 ERR("Failed to allocate memory\n");
901 return E_OUTOFMEMORY;
904 FIXME("Ignoring access flags (pool)\n");
906 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
907 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
910 WARN("Failed to initialize buffer, hr %#x.\n", hr);
911 HeapFree(GetProcessHeap(), 0, object);
914 object->desc = *desc;
916 TRACE("Created buffer %p.\n", object);
918 *buffer = (IWineD3DBuffer *)object;
923 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
924 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
925 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
928 struct wined3d_buffer *object;
931 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
932 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
934 if (Pool == WINED3DPOOL_SCRATCH)
936 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
937 * anyway, SCRATCH vertex buffers aren't usable anywhere
939 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
940 *ppVertexBuffer = NULL;
941 return WINED3DERR_INVALIDCALL;
944 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
947 ERR("Out of memory\n");
948 *ppVertexBuffer = NULL;
949 return WINED3DERR_OUTOFVIDEOMEMORY;
952 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
953 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
956 WARN("Failed to initialize buffer, hr %#x.\n", hr);
957 HeapFree(GetProcessHeap(), 0, object);
961 TRACE("Created buffer %p.\n", object);
962 *ppVertexBuffer = (IWineD3DBuffer *)object;
967 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
968 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
969 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
972 struct wined3d_buffer *object;
975 TRACE("(%p) Creating index buffer\n", This);
977 /* Allocate the storage for the device */
978 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
981 ERR("Out of memory\n");
982 *ppIndexBuffer = NULL;
983 return WINED3DERR_OUTOFVIDEOMEMORY;
986 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
987 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
991 WARN("Failed to initialize buffer, hr %#x\n", hr);
992 HeapFree(GetProcessHeap(), 0, object);
996 TRACE("Created buffer %p.\n", object);
998 *ppIndexBuffer = (IWineD3DBuffer *) object;
1003 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1004 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1007 IWineD3DStateBlockImpl *object;
1010 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1013 ERR("Failed to allocate stateblock memory.\n");
1014 return E_OUTOFMEMORY;
1017 hr = stateblock_init(object, This, type);
1020 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1021 HeapFree(GetProcessHeap(), 0, object);
1025 TRACE("Created stateblock %p.\n", object);
1026 *stateblock = (IWineD3DStateBlock *)object;
1031 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1032 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1033 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1034 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1037 IWineD3DSurfaceImpl *object;
1040 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1041 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1042 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1043 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1044 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1046 if (Impl == SURFACE_OPENGL && !This->adapter)
1048 ERR("OpenGL surfaces are not available without OpenGL.\n");
1049 return WINED3DERR_NOTAVAILABLE;
1052 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1055 ERR("Failed to allocate surface memory.\n");
1056 return WINED3DERR_OUTOFVIDEOMEMORY;
1059 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1060 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1063 WARN("Failed to initialize surface, returning %#x.\n", hr);
1064 HeapFree(GetProcessHeap(), 0, object);
1068 TRACE("(%p) : Created surface %p\n", This, object);
1070 *surface = (IWineD3DSurface *)object;
1075 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1076 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1078 struct wined3d_rendertarget_view *object;
1080 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1081 iface, resource, parent, rendertarget_view);
1083 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1086 ERR("Failed to allocate memory\n");
1087 return E_OUTOFMEMORY;
1090 wined3d_rendertarget_view_init(object, resource, parent);
1092 TRACE("Created render target view %p.\n", object);
1093 *rendertarget_view = (IWineD3DRendertargetView *)object;
1098 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1099 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1100 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1103 IWineD3DTextureImpl *object;
1106 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1107 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1108 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1110 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1113 ERR("Out of memory\n");
1115 return WINED3DERR_OUTOFVIDEOMEMORY;
1118 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1121 WARN("Failed to initialize texture, returning %#x\n", hr);
1122 HeapFree(GetProcessHeap(), 0, object);
1127 *ppTexture = (IWineD3DTexture *)object;
1129 TRACE("(%p) : Created texture %p\n", This, object);
1134 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1135 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1136 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1139 IWineD3DVolumeTextureImpl *object;
1142 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1143 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1145 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1148 ERR("Out of memory\n");
1149 *ppVolumeTexture = NULL;
1150 return WINED3DERR_OUTOFVIDEOMEMORY;
1153 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1156 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1157 HeapFree(GetProcessHeap(), 0, object);
1158 *ppVolumeTexture = NULL;
1162 TRACE("(%p) : Created volume texture %p.\n", This, object);
1163 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1168 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1169 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1170 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1173 IWineD3DVolumeImpl *object;
1176 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1177 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1179 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1182 ERR("Out of memory\n");
1184 return WINED3DERR_OUTOFVIDEOMEMORY;
1187 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1190 WARN("Failed to initialize volume, returning %#x.\n", hr);
1191 HeapFree(GetProcessHeap(), 0, object);
1195 TRACE("(%p) : Created volume %p.\n", This, object);
1196 *ppVolume = (IWineD3DVolume *)object;
1201 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1202 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1203 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1206 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1209 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1212 ERR("Out of memory\n");
1213 *ppCubeTexture = NULL;
1214 return WINED3DERR_OUTOFVIDEOMEMORY;
1217 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1220 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1221 HeapFree(GetProcessHeap(), 0, object);
1222 *ppCubeTexture = NULL;
1226 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1227 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1232 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1233 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 IWineD3DQueryImpl *object;
1239 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1241 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1244 ERR("Failed to allocate query memory.\n");
1245 return E_OUTOFMEMORY;
1248 hr = query_init(object, This, type);
1251 WARN("Failed to initialize query, hr %#x.\n", hr);
1252 HeapFree(GetProcessHeap(), 0, object);
1256 TRACE("Created query %p.\n", object);
1257 *query = (IWineD3DQuery *)object;
1262 /* Do not call while under the GL lock. */
1263 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1264 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1265 void *parent, IWineD3DSwapChain **swapchain)
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1268 IWineD3DSwapChainImpl *object;
1271 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1272 iface, present_parameters, swapchain, parent, surface_type);
1274 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1277 ERR("Failed to allocate swapchain memory.\n");
1278 return E_OUTOFMEMORY;
1281 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1284 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1285 HeapFree(GetProcessHeap(), 0, object);
1289 TRACE("Created swapchain %p.\n", object);
1290 *swapchain = (IWineD3DSwapChain *)object;
1295 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1296 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 TRACE("(%p)\n", This);
1300 return This->NumberOfSwapChains;
1303 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1307 if(iSwapChain < This->NumberOfSwapChains) {
1308 *pSwapChain = This->swapchains[iSwapChain];
1309 IWineD3DSwapChain_AddRef(*pSwapChain);
1310 TRACE("(%p) returning %p\n", This, *pSwapChain);
1313 TRACE("Swapchain out of range\n");
1315 return WINED3DERR_INVALIDCALL;
1319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1320 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1321 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1324 IWineD3DVertexDeclarationImpl *object = NULL;
1327 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1328 iface, declaration, parent, elements, element_count);
1330 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1333 ERR("Failed to allocate vertex declaration memory.\n");
1334 return E_OUTOFMEMORY;
1337 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1340 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1341 HeapFree(GetProcessHeap(), 0, object);
1345 TRACE("Created vertex declaration %p.\n", object);
1346 *declaration = (IWineD3DVertexDeclaration *)object;
1351 struct wined3d_fvf_convert_state
1353 const struct wined3d_gl_info *gl_info;
1354 WINED3DVERTEXELEMENT *elements;
1359 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1360 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1362 WINED3DVERTEXELEMENT *elements = state->elements;
1363 const struct wined3d_format *format;
1364 UINT offset = state->offset;
1365 UINT idx = state->idx;
1367 elements[idx].format = format_id;
1368 elements[idx].input_slot = 0;
1369 elements[idx].offset = offset;
1370 elements[idx].output_slot = 0;
1371 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1372 elements[idx].usage = usage;
1373 elements[idx].usage_idx = usage_idx;
1375 format = wined3d_get_format(state->gl_info, format_id);
1376 state->offset += format->component_count * format->component_size;
1380 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1381 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1383 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1384 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1385 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1386 BOOL has_blend_idx = has_blend &&
1387 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1388 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1389 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1390 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1391 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1392 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1393 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1395 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1396 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1397 struct wined3d_fvf_convert_state state;
1400 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1401 if (has_blend_idx) num_blends--;
1403 /* Compute declaration size */
1404 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1405 has_psize + has_diffuse + has_specular + num_textures;
1407 state.gl_info = gl_info;
1408 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1409 if (!state.elements) return ~0U;
1415 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1416 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1417 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1418 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1420 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1423 if (has_blend && (num_blends > 0))
1425 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1426 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1432 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1435 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 ERR("Unexpected amount of blend values: %u\n", num_blends);
1451 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1452 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1453 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1454 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1455 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1457 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1460 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1461 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1462 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1463 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1465 for (idx = 0; idx < num_textures; ++idx)
1467 switch ((texcoords >> (idx * 2)) & 0x03)
1469 case WINED3DFVF_TEXTUREFORMAT1:
1470 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1472 case WINED3DFVF_TEXTUREFORMAT2:
1473 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1475 case WINED3DFVF_TEXTUREFORMAT3:
1476 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 case WINED3DFVF_TEXTUREFORMAT4:
1479 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1484 *ppVertexElements = state.elements;
1488 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1489 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1490 IWineD3DVertexDeclaration **declaration)
1492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1493 WINED3DVERTEXELEMENT *elements;
1497 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1499 size = ConvertFvfToDeclaration(This, fvf, &elements);
1500 if (size == ~0U) return E_OUTOFMEMORY;
1502 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1503 HeapFree(GetProcessHeap(), 0, elements);
1507 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1508 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1509 void *parent, const struct wined3d_parent_ops *parent_ops,
1510 IWineD3DVertexShader **ppVertexShader)
1512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1513 IWineD3DVertexShaderImpl *object;
1516 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1519 ERR("Failed to allocate shader memory.\n");
1520 return E_OUTOFMEMORY;
1523 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1526 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1527 HeapFree(GetProcessHeap(), 0, object);
1531 TRACE("Created vertex shader %p.\n", object);
1532 *ppVertexShader = (IWineD3DVertexShader *)object;
1537 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1538 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1539 void *parent, const struct wined3d_parent_ops *parent_ops,
1540 IWineD3DGeometryShader **shader)
1542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1543 struct wined3d_geometryshader *object;
1546 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1549 ERR("Failed to allocate shader memory.\n");
1550 return E_OUTOFMEMORY;
1553 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1556 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1557 HeapFree(GetProcessHeap(), 0, object);
1561 TRACE("Created geometry shader %p.\n", object);
1562 *shader = (IWineD3DGeometryShader *)object;
1567 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1568 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1569 void *parent, const struct wined3d_parent_ops *parent_ops,
1570 IWineD3DPixelShader **ppPixelShader)
1572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1573 IWineD3DPixelShaderImpl *object;
1576 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1579 ERR("Failed to allocate shader memory.\n");
1580 return E_OUTOFMEMORY;
1583 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1586 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1587 HeapFree(GetProcessHeap(), 0, object);
1591 TRACE("Created pixel shader %p.\n", object);
1592 *ppPixelShader = (IWineD3DPixelShader *)object;
1597 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1598 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1601 IWineD3DPaletteImpl *object;
1604 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1605 iface, Flags, PalEnt, Palette, parent);
1607 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1610 ERR("Failed to allocate palette memory.\n");
1611 return E_OUTOFMEMORY;
1614 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1617 WARN("Failed to initialize palette, hr %#x.\n", hr);
1618 HeapFree(GetProcessHeap(), 0, object);
1622 TRACE("Created palette %p.\n", object);
1623 *Palette = (IWineD3DPalette *)object;
1628 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1632 HDC dcb = NULL, dcs = NULL;
1633 WINEDDCOLORKEY colorkey;
1635 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1638 GetObjectA(hbm, sizeof(BITMAP), &bm);
1639 dcb = CreateCompatibleDC(NULL);
1641 SelectObject(dcb, hbm);
1645 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1646 * couldn't be loaded
1648 memset(&bm, 0, sizeof(bm));
1653 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1654 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1655 &wined3d_null_parent_ops, &This->logo_surface);
1658 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1663 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1664 if(FAILED(hr)) goto out;
1665 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1666 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1668 colorkey.dwColorSpaceLowValue = 0;
1669 colorkey.dwColorSpaceHighValue = 0;
1670 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1674 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1675 /* Fill the surface with a white color to show that wined3d is there */
1676 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1680 if (dcb) DeleteDC(dcb);
1681 if (hbm) DeleteObject(hbm);
1684 /* Context activation is done by the caller. */
1685 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1687 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1689 /* Under DirectX you can have texture stage operations even if no texture is
1690 bound, whereas opengl will only do texture operations when a valid texture is
1691 bound. We emulate this by creating dummy textures and binding them to each
1692 texture stage, but disable all stages by default. Hence if a stage is enabled
1693 then the default texture will kick in until replaced by a SetTexture call */
1696 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1698 /* The dummy texture does not have client storage backing */
1699 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1700 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1703 for (i = 0; i < gl_info->limits.textures; ++i)
1705 GLubyte white = 255;
1707 /* Make appropriate texture active */
1708 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1709 checkGLcall("glActiveTextureARB");
1711 /* Generate an opengl texture name */
1712 glGenTextures(1, &This->dummyTextureName[i]);
1713 checkGLcall("glGenTextures");
1714 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1716 /* Generate a dummy 2d texture (not using 1d because they cause many
1717 * DRI drivers fall back to sw) */
1718 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1719 checkGLcall("glBindTexture");
1721 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1722 checkGLcall("glTexImage2D");
1725 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1727 /* Reenable because if supported it is enabled by default */
1728 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1729 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1735 /* Context activation is done by the caller. */
1736 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1739 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1740 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1743 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1746 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1748 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1750 if (!wined3d_register_window(window, device))
1752 ERR("Failed to register window %p.\n", window);
1756 device->focus_window = window;
1757 SetForegroundWindow(window);
1762 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1764 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1766 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1767 device->focus_window = NULL;
1770 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1771 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1774 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1775 IWineD3DSwapChainImpl *swapchain = NULL;
1776 struct wined3d_context *context;
1781 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1783 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1784 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1786 TRACE("(%p) : Creating stateblock\n", This);
1787 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1790 WARN("Failed to create stateblock\n");
1793 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1794 This->updateStateBlock = This->stateBlock;
1795 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1797 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1798 sizeof(*This->render_targets) * gl_info->limits.buffers);
1800 This->NumberOfPalettes = 1;
1801 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1802 if (!This->palettes || !This->render_targets)
1804 ERR("Out of memory!\n");
1808 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1809 if(!This->palettes[0]) {
1810 ERR("Out of memory!\n");
1814 for (i = 0; i < 256; ++i) {
1815 This->palettes[0][i].peRed = 0xFF;
1816 This->palettes[0][i].peGreen = 0xFF;
1817 This->palettes[0][i].peBlue = 0xFF;
1818 This->palettes[0][i].peFlags = 0xFF;
1820 This->currentPalette = 0;
1822 /* Initialize the texture unit mapping to a 1:1 mapping */
1823 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1825 if (state < gl_info->limits.fragment_samplers)
1827 This->texUnitMap[state] = state;
1828 This->rev_tex_unit_map[state] = state;
1830 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1831 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1835 /* Setup the implicit swapchain. This also initializes a context. */
1836 TRACE("Creating implicit swapchain\n");
1837 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1838 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1841 WARN("Failed to create implicit swapchain\n");
1845 This->NumberOfSwapChains = 1;
1846 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1847 if(!This->swapchains) {
1848 ERR("Out of memory!\n");
1851 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1853 if (swapchain->back_buffers && swapchain->back_buffers[0])
1855 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1856 This->render_targets[0] = swapchain->back_buffers[0];
1860 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1861 This->render_targets[0] = swapchain->front_buffer;
1863 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1865 /* Depth Stencil support */
1866 This->depth_stencil = This->auto_depth_stencil;
1867 if (This->depth_stencil)
1868 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1870 hr = This->shader_backend->shader_alloc_private(iface);
1872 TRACE("Shader private data couldn't be allocated\n");
1875 hr = This->frag_pipe->alloc_private(iface);
1877 TRACE("Fragment pipeline private data couldn't be allocated\n");
1880 hr = This->blitter->alloc_private(iface);
1882 TRACE("Blitter private data couldn't be allocated\n");
1886 /* Set up some starting GL setup */
1888 /* Setup all the devices defaults */
1889 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1891 context = context_acquire(This, swapchain->front_buffer);
1893 create_dummy_textures(This);
1897 /* Initialize the current view state */
1898 This->view_ident = 1;
1899 This->contexts[0]->last_was_rhw = 0;
1900 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1901 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1903 switch(wined3d_settings.offscreen_rendering_mode) {
1905 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1908 case ORM_BACKBUFFER:
1910 if (context_get_current()->aux_buffers > 0)
1912 TRACE("Using auxilliary buffer for offscreen rendering\n");
1913 This->offscreenBuffer = GL_AUX0;
1915 TRACE("Using back buffer for offscreen rendering\n");
1916 This->offscreenBuffer = GL_BACK;
1921 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1924 context_release(context);
1926 /* Clear the screen */
1927 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1928 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1931 This->d3d_initialized = TRUE;
1933 if(wined3d_settings.logo) {
1934 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1936 This->highest_dirty_ps_const = 0;
1937 This->highest_dirty_vs_const = 0;
1941 HeapFree(GetProcessHeap(), 0, This->render_targets);
1942 HeapFree(GetProcessHeap(), 0, This->swapchains);
1943 This->NumberOfSwapChains = 0;
1944 if(This->palettes) {
1945 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1946 HeapFree(GetProcessHeap(), 0, This->palettes);
1948 This->NumberOfPalettes = 0;
1950 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1952 if(This->stateBlock) {
1953 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1954 This->stateBlock = NULL;
1956 if (This->blit_priv) {
1957 This->blitter->free_private(iface);
1959 if (This->fragment_priv) {
1960 This->frag_pipe->free_private(iface);
1962 if (This->shader_priv) {
1963 This->shader_backend->shader_free_private(iface);
1968 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1969 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1972 IWineD3DSwapChainImpl *swapchain = NULL;
1975 /* Setup the implicit swapchain */
1976 TRACE("Creating implicit swapchain\n");
1977 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1978 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1981 WARN("Failed to create implicit swapchain\n");
1985 This->NumberOfSwapChains = 1;
1986 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1987 if(!This->swapchains) {
1988 ERR("Out of memory!\n");
1991 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1995 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1999 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2001 IWineD3DResource_UnLoad(resource);
2002 IWineD3DResource_Release(resource);
2006 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2007 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2010 const struct wined3d_gl_info *gl_info;
2011 struct wined3d_context *context;
2014 TRACE("(%p)\n", This);
2016 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2018 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2019 * it was created. Thus make sure a context is active for the glDelete* calls
2021 context = context_acquire(This, NULL);
2022 gl_info = context->gl_info;
2024 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2026 /* Unload resources */
2027 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2029 TRACE("Deleting high order patches\n");
2030 for(i = 0; i < PATCHMAP_SIZE; i++) {
2031 struct list *e1, *e2;
2032 struct WineD3DRectPatch *patch;
2033 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2034 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2035 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2039 /* Delete the mouse cursor texture */
2040 if(This->cursorTexture) {
2042 glDeleteTextures(1, &This->cursorTexture);
2044 This->cursorTexture = 0;
2047 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2048 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2050 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2051 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2054 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2055 * private data, it might contain opengl pointers
2057 if(This->depth_blt_texture) {
2059 glDeleteTextures(1, &This->depth_blt_texture);
2061 This->depth_blt_texture = 0;
2063 if (This->depth_blt_rb) {
2065 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2067 This->depth_blt_rb = 0;
2068 This->depth_blt_rb_w = 0;
2069 This->depth_blt_rb_h = 0;
2072 /* Release the update stateblock */
2073 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2074 if(This->updateStateBlock != This->stateBlock)
2075 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2077 This->updateStateBlock = NULL;
2079 { /* because were not doing proper internal refcounts releasing the primary state block
2080 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2081 to set this->stateBlock = NULL; first */
2082 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2083 This->stateBlock = NULL;
2085 /* Release the stateblock */
2086 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2087 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2091 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2092 This->blitter->free_private(iface);
2093 This->frag_pipe->free_private(iface);
2094 This->shader_backend->shader_free_private(iface);
2096 /* Release the buffers (with sanity checks)*/
2097 if (This->onscreen_depth_stencil)
2099 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2100 This->onscreen_depth_stencil = NULL;
2103 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2104 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2106 if (This->auto_depth_stencil != This->depth_stencil)
2107 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2109 This->depth_stencil = NULL;
2111 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2112 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2114 TRACE("Setting rendertarget to NULL\n");
2115 This->render_targets[0] = NULL;
2117 if (This->auto_depth_stencil)
2119 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2121 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2123 This->auto_depth_stencil = NULL;
2126 context_release(context);
2128 for(i=0; i < This->NumberOfSwapChains; i++) {
2129 TRACE("Releasing the implicit swapchain %d\n", i);
2130 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2131 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2135 HeapFree(GetProcessHeap(), 0, This->swapchains);
2136 This->swapchains = NULL;
2137 This->NumberOfSwapChains = 0;
2139 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2140 HeapFree(GetProcessHeap(), 0, This->palettes);
2141 This->palettes = NULL;
2142 This->NumberOfPalettes = 0;
2144 HeapFree(GetProcessHeap(), 0, This->render_targets);
2145 This->render_targets = NULL;
2147 This->d3d_initialized = FALSE;
2152 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2156 for(i=0; i < This->NumberOfSwapChains; i++) {
2157 TRACE("Releasing the implicit swapchain %d\n", i);
2158 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2159 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2163 HeapFree(GetProcessHeap(), 0, This->swapchains);
2164 This->swapchains = NULL;
2165 This->NumberOfSwapChains = 0;
2169 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2170 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2171 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2173 * There is no way to deactivate thread safety once it is enabled.
2175 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2178 /*For now just store the flag(needed in case of ddraw) */
2179 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2182 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2183 const WINED3DDISPLAYMODE* pMode) {
2185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2186 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2190 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2192 /* Resize the screen even without a window:
2193 * The app could have unset it with SetCooperativeLevel, but not called
2194 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2195 * but we don't have any hwnd
2198 memset(&devmode, 0, sizeof(devmode));
2199 devmode.dmSize = sizeof(devmode);
2200 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2201 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2202 devmode.dmPelsWidth = pMode->Width;
2203 devmode.dmPelsHeight = pMode->Height;
2205 devmode.dmDisplayFrequency = pMode->RefreshRate;
2206 if (pMode->RefreshRate != 0) {
2207 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2210 /* Only change the mode if necessary */
2211 if( (This->ddraw_width == pMode->Width) &&
2212 (This->ddraw_height == pMode->Height) &&
2213 (This->ddraw_format == pMode->Format) &&
2214 (pMode->RefreshRate == 0) ) {
2218 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2219 if (ret != DISP_CHANGE_SUCCESSFUL) {
2220 if(devmode.dmDisplayFrequency != 0) {
2221 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2222 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2223 devmode.dmDisplayFrequency = 0;
2224 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2226 if(ret != DISP_CHANGE_SUCCESSFUL) {
2227 return WINED3DERR_NOTAVAILABLE;
2231 /* Store the new values */
2232 This->ddraw_width = pMode->Width;
2233 This->ddraw_height = pMode->Height;
2234 This->ddraw_format = pMode->Format;
2236 /* And finally clip mouse to our screen */
2237 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2238 ClipCursor(&clip_rc);
2243 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 *ppD3D = This->wined3d;
2246 TRACE("Returning %p.\n", *ppD3D);
2247 IWineD3D_AddRef(*ppD3D);
2251 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2254 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2255 (This->adapter->TextureRam/(1024*1024)),
2256 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2257 /* return simulated texture memory left */
2258 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2262 * Get / Set Stream Source
2264 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2265 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 IWineD3DBuffer *oldSrc;
2270 if (StreamNumber >= MAX_STREAMS) {
2271 WARN("Stream out of range %d\n", StreamNumber);
2272 return WINED3DERR_INVALIDCALL;
2273 } else if(OffsetInBytes & 0x3) {
2274 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2275 return WINED3DERR_INVALIDCALL;
2278 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2279 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2281 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2283 if(oldSrc == pStreamData &&
2284 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2285 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2286 TRACE("Application is setting the old values over, nothing to do\n");
2290 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2292 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2293 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2296 /* Handle recording of state blocks */
2297 if (This->isRecordingState) {
2298 TRACE("Recording... not performing anything\n");
2299 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2300 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2304 if (pStreamData != NULL) {
2305 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2306 IWineD3DBuffer_AddRef(pStreamData);
2308 if (oldSrc != NULL) {
2309 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2310 IWineD3DBuffer_Release(oldSrc);
2313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2318 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2319 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2323 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2324 This->stateBlock->streamSource[StreamNumber],
2325 This->stateBlock->streamOffset[StreamNumber],
2326 This->stateBlock->streamStride[StreamNumber]);
2328 if (StreamNumber >= MAX_STREAMS) {
2329 WARN("Stream out of range %d\n", StreamNumber);
2330 return WINED3DERR_INVALIDCALL;
2332 *pStream = This->stateBlock->streamSource[StreamNumber];
2333 *pStride = This->stateBlock->streamStride[StreamNumber];
2335 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2338 if (*pStream != NULL) {
2339 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2344 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2347 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2349 /* Verify input at least in d3d9 this is invalid*/
2350 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2351 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2352 return WINED3DERR_INVALIDCALL;
2354 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2355 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2356 return WINED3DERR_INVALIDCALL;
2359 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2360 return WINED3DERR_INVALIDCALL;
2363 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2364 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2366 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2367 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2369 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2370 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2377 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2381 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2383 TRACE("(%p) : returning %d\n", This, *Divider);
2389 * Get / Set & Multiply Transform
2391 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 /* Most of this routine, comments included copied from ddraw tree initially: */
2395 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2397 /* Handle recording of state blocks */
2398 if (This->isRecordingState) {
2399 TRACE("Recording... not performing anything\n");
2400 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2401 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2406 * If the new matrix is the same as the current one,
2407 * we cut off any further processing. this seems to be a reasonable
2408 * optimization because as was noticed, some apps (warcraft3 for example)
2409 * tend towards setting the same matrix repeatedly for some reason.
2411 * From here on we assume that the new matrix is different, wherever it matters.
2413 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2414 TRACE("The app is setting the same matrix over again\n");
2417 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2421 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2422 where ViewMat = Camera space, WorldMat = world space.
2424 In OpenGL, camera and world space is combined into GL_MODELVIEW
2425 matrix. The Projection matrix stay projection matrix.
2428 /* Capture the times we can just ignore the change for now */
2429 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2430 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2431 /* Handled by the state manager */
2434 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2440 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2443 *pMatrix = This->stateBlock->transforms[State];
2447 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2448 const WINED3DMATRIX *mat = NULL;
2451 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2452 * below means it will be recorded in a state block change, but it
2453 * works regardless where it is recorded.
2454 * If this is found to be wrong, change to StateBlock.
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2459 if (State <= HIGHEST_TRANSFORMSTATE)
2461 mat = &This->updateStateBlock->transforms[State];
2463 FIXME("Unhandled transform state!!\n");
2466 multiply_matrix(&temp, mat, pMatrix);
2468 /* Apply change via set transform - will reapply to eg. lights this way */
2469 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2475 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2476 you can reference any indexes you want as long as that number max are enabled at any
2477 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2478 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2479 but when recording, just build a chain pretty much of commands to be replayed. */
2481 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2483 struct wined3d_light_info *object = NULL;
2484 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2490 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2494 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2495 return WINED3DERR_INVALIDCALL;
2498 switch(pLight->Type) {
2499 case WINED3DLIGHT_POINT:
2500 case WINED3DLIGHT_SPOT:
2501 case WINED3DLIGHT_PARALLELPOINT:
2502 case WINED3DLIGHT_GLSPOT:
2503 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2506 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2508 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2509 return WINED3DERR_INVALIDCALL;
2513 case WINED3DLIGHT_DIRECTIONAL:
2514 /* Ignores attenuation */
2518 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2519 return WINED3DERR_INVALIDCALL;
2522 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2524 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2525 if(object->OriginalIndex == Index) break;
2530 TRACE("Adding new light\n");
2531 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2533 ERR("Out of memory error when allocating a light\n");
2534 return E_OUTOFMEMORY;
2536 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2537 object->glIndex = -1;
2538 object->OriginalIndex = Index;
2541 /* Initialize the object */
2542 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,
2543 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2544 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2545 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2546 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2547 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2548 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2550 /* Save away the information */
2551 object->OriginalParms = *pLight;
2553 switch (pLight->Type) {
2554 case WINED3DLIGHT_POINT:
2556 object->lightPosn[0] = pLight->Position.x;
2557 object->lightPosn[1] = pLight->Position.y;
2558 object->lightPosn[2] = pLight->Position.z;
2559 object->lightPosn[3] = 1.0f;
2560 object->cutoff = 180.0f;
2564 case WINED3DLIGHT_DIRECTIONAL:
2566 object->lightPosn[0] = -pLight->Direction.x;
2567 object->lightPosn[1] = -pLight->Direction.y;
2568 object->lightPosn[2] = -pLight->Direction.z;
2569 object->lightPosn[3] = 0.0f;
2570 object->exponent = 0.0f;
2571 object->cutoff = 180.0f;
2574 case WINED3DLIGHT_SPOT:
2576 object->lightPosn[0] = pLight->Position.x;
2577 object->lightPosn[1] = pLight->Position.y;
2578 object->lightPosn[2] = pLight->Position.z;
2579 object->lightPosn[3] = 1.0f;
2582 object->lightDirn[0] = pLight->Direction.x;
2583 object->lightDirn[1] = pLight->Direction.y;
2584 object->lightDirn[2] = pLight->Direction.z;
2585 object->lightDirn[3] = 1.0f;
2588 * opengl-ish and d3d-ish spot lights use too different models for the
2589 * light "intensity" as a function of the angle towards the main light direction,
2590 * so we only can approximate very roughly.
2591 * however spot lights are rather rarely used in games (if ever used at all).
2592 * furthermore if still used, probably nobody pays attention to such details.
2594 if (pLight->Falloff == 0) {
2595 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2596 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2597 * will always be 1.0 for both of them, and we don't have to care for the
2598 * rest of the rather complex calculation
2600 object->exponent = 0.0f;
2602 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2603 if (rho < 0.0001f) rho = 0.0001f;
2604 object->exponent = -0.3f/logf(cosf(rho/2));
2606 if (object->exponent > 128.0f)
2608 object->exponent = 128.0f;
2610 object->cutoff = (float) (pLight->Phi*90/M_PI);
2616 FIXME("Unrecognized light type %d\n", pLight->Type);
2619 /* Update the live definitions if the light is currently assigned a glIndex */
2620 if (object->glIndex != -1 && !This->isRecordingState) {
2621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2626 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2628 struct wined3d_light_info *lightInfo = NULL;
2629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2630 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2632 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2634 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2636 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2637 if(lightInfo->OriginalIndex == Index) break;
2641 if (lightInfo == NULL) {
2642 TRACE("Light information requested but light not defined\n");
2643 return WINED3DERR_INVALIDCALL;
2646 *pLight = lightInfo->OriginalParms;
2651 * Get / Set Light Enable
2652 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2654 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2656 struct wined3d_light_info *lightInfo = NULL;
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2660 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2662 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2664 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2665 if(lightInfo->OriginalIndex == Index) break;
2668 TRACE("Found light: %p\n", lightInfo);
2670 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2671 if (lightInfo == NULL) {
2673 TRACE("Light enabled requested but light not defined, so defining one!\n");
2674 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2676 /* Search for it again! Should be fairly quick as near head of list */
2677 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2679 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2680 if(lightInfo->OriginalIndex == Index) break;
2683 if (lightInfo == NULL) {
2684 FIXME("Adding default lights has failed dismally\n");
2685 return WINED3DERR_INVALIDCALL;
2690 if(lightInfo->glIndex != -1) {
2691 if(!This->isRecordingState) {
2692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2695 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2696 lightInfo->glIndex = -1;
2698 TRACE("Light already disabled, nothing to do\n");
2700 lightInfo->enabled = FALSE;
2702 lightInfo->enabled = TRUE;
2703 if (lightInfo->glIndex != -1) {
2705 TRACE("Nothing to do as light was enabled\n");
2708 /* Find a free gl light */
2709 for(i = 0; i < This->maxConcurrentLights; i++) {
2710 if(This->updateStateBlock->activeLights[i] == NULL) {
2711 This->updateStateBlock->activeLights[i] = lightInfo;
2712 lightInfo->glIndex = i;
2716 if(lightInfo->glIndex == -1) {
2717 /* Our tests show that Windows returns D3D_OK in this situation, even with
2718 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2719 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2720 * as well for those lights.
2722 * TODO: Test how this affects rendering
2724 WARN("Too many concurrently active lights\n");
2728 /* i == lightInfo->glIndex */
2729 if(!This->isRecordingState) {
2730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2738 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2740 struct wined3d_light_info *lightInfo = NULL;
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2744 TRACE("(%p) : for idx(%d)\n", This, Index);
2746 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2748 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2749 if(lightInfo->OriginalIndex == Index) break;
2753 if (lightInfo == NULL) {
2754 TRACE("Light enabled state requested but light not defined\n");
2755 return WINED3DERR_INVALIDCALL;
2757 /* true is 128 according to SetLightEnable */
2758 *pEnable = lightInfo->enabled ? 128 : 0;
2763 * Get / Set Clip Planes
2765 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2769 /* Validate Index */
2770 if (Index >= This->adapter->gl_info.limits.clipplanes)
2772 TRACE("Application has requested clipplane this device doesn't support\n");
2773 return WINED3DERR_INVALIDCALL;
2776 This->updateStateBlock->changed.clipplane |= 1 << Index;
2778 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2779 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2780 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2781 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2782 TRACE("Application is setting old values over, nothing to do\n");
2786 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2787 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2788 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2789 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2791 /* Handle recording of state blocks */
2792 if (This->isRecordingState) {
2793 TRACE("Recording... not performing anything\n");
2797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2802 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 TRACE("(%p) : for idx %d\n", This, Index);
2806 /* Validate Index */
2807 if (Index >= This->adapter->gl_info.limits.clipplanes)
2809 TRACE("Application has requested clipplane this device doesn't support\n");
2810 return WINED3DERR_INVALIDCALL;
2813 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2814 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2815 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2816 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2821 * Get / Set Clip Plane Status
2822 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2824 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 FIXME("(%p) : stub\n", This);
2827 if (NULL == pClipStatus) {
2828 return WINED3DERR_INVALIDCALL;
2830 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2831 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2835 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 FIXME("(%p) : stub\n", This);
2838 if (NULL == pClipStatus) {
2839 return WINED3DERR_INVALIDCALL;
2841 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2842 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2847 * Get / Set Material
2849 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 This->updateStateBlock->changed.material = TRUE;
2853 This->updateStateBlock->material = *pMaterial;
2855 /* Handle recording of state blocks */
2856 if (This->isRecordingState) {
2857 TRACE("Recording... not performing anything\n");
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2865 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2867 *pMaterial = This->updateStateBlock->material;
2868 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2869 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2870 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2871 pMaterial->Ambient.b, pMaterial->Ambient.a);
2872 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2873 pMaterial->Specular.b, pMaterial->Specular.a);
2874 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2875 pMaterial->Emissive.b, pMaterial->Emissive.a);
2876 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2884 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2885 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 IWineD3DBuffer *oldIdxs;
2890 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2891 oldIdxs = This->updateStateBlock->pIndexData;
2893 This->updateStateBlock->changed.indices = TRUE;
2894 This->updateStateBlock->pIndexData = pIndexData;
2895 This->updateStateBlock->IndexFmt = fmt;
2897 /* Handle recording of state blocks */
2898 if (This->isRecordingState) {
2899 TRACE("Recording... not performing anything\n");
2900 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2901 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2905 if(oldIdxs != pIndexData) {
2906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2908 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2909 IWineD3DBuffer_AddRef(pIndexData);
2912 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2913 IWineD3DBuffer_Release(oldIdxs);
2920 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 *ppIndexData = This->stateBlock->pIndexData;
2926 /* up ref count on ppindexdata */
2928 IWineD3DBuffer_AddRef(*ppIndexData);
2929 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2931 TRACE("(%p) No index data set\n", This);
2933 TRACE("Returning %p\n", *ppIndexData);
2938 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2939 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 TRACE("(%p)->(%d)\n", This, BaseIndex);
2943 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2944 TRACE("Application is setting the old value over, nothing to do\n");
2948 This->updateStateBlock->baseVertexIndex = BaseIndex;
2950 if (This->isRecordingState) {
2951 TRACE("Recording... not performing anything\n");
2954 /* The base vertex index affects the stream sources */
2955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2959 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 TRACE("(%p) : base_index %p\n", This, base_index);
2963 *base_index = This->stateBlock->baseVertexIndex;
2965 TRACE("Returning %u\n", *base_index);
2971 * Get / Set Viewports
2973 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2976 TRACE("(%p)\n", This);
2977 This->updateStateBlock->changed.viewport = TRUE;
2978 This->updateStateBlock->viewport = *pViewport;
2980 /* Handle recording of state blocks */
2981 if (This->isRecordingState) {
2982 TRACE("Recording... not performing anything\n");
2986 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2987 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2994 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 TRACE("(%p)\n", This);
2997 *pViewport = This->stateBlock->viewport;
3002 * Get / Set Render States
3003 * TODO: Verify against dx9 definitions
3005 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3008 DWORD oldValue = This->stateBlock->renderState[State];
3010 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3012 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3013 This->updateStateBlock->renderState[State] = Value;
3015 /* Handle recording of state blocks */
3016 if (This->isRecordingState) {
3017 TRACE("Recording... not performing anything\n");
3021 /* Compared here and not before the assignment to allow proper stateblock recording */
3022 if(Value == oldValue) {
3023 TRACE("Application is setting the old value over, nothing to do\n");
3025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3031 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3036 *pValue = This->stateBlock->renderState[State];
3041 * Get / Set Sampler States
3042 * TODO: Verify against dx9 definitions
3045 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3050 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3052 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3053 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3056 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3057 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3058 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3061 * SetSampler is designed to allow for more than the standard up to 8 textures
3062 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3063 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3065 * http://developer.nvidia.com/object/General_FAQ.html#t6
3067 * There are two new settings for GForce
3069 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3070 * and the texture one:
3071 * GL_MAX_TEXTURE_COORDS_ARB.
3072 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3075 oldValue = This->stateBlock->samplerState[Sampler][Type];
3076 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3077 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3079 /* Handle recording of state blocks */
3080 if (This->isRecordingState) {
3081 TRACE("Recording... not performing anything\n");
3085 if(oldValue == Value) {
3086 TRACE("Application is setting the old value over, nothing to do\n");
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3095 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3099 This, Sampler, debug_d3dsamplerstate(Type), Type);
3101 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3102 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3105 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3106 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3107 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3109 *Value = This->stateBlock->samplerState[Sampler][Type];
3110 TRACE("(%p) : Returning %#x\n", This, *Value);
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 This->updateStateBlock->changed.scissorRect = TRUE;
3119 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3120 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3123 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3125 if(This->isRecordingState) {
3126 TRACE("Recording... not performing anything\n");
3130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3135 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 *pRect = This->updateStateBlock->scissorRect;
3139 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3145 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3147 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3149 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3150 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3152 This->updateStateBlock->vertexDecl = pDecl;
3153 This->updateStateBlock->changed.vertexDecl = TRUE;
3155 if (This->isRecordingState) {
3156 TRACE("Recording... not performing anything\n");
3158 } else if(pDecl == oldDecl) {
3159 /* Checked after the assignment to allow proper stateblock recording */
3160 TRACE("Application is setting the old declaration over, nothing to do\n");
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3168 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3173 *ppDecl = This->stateBlock->vertexDecl;
3174 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3178 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3182 This->updateStateBlock->vertexShader = pShader;
3183 This->updateStateBlock->changed.vertexShader = TRUE;
3185 if (This->isRecordingState) {
3186 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3187 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3188 TRACE("Recording... not performing anything\n");
3190 } else if(oldShader == pShader) {
3191 /* Checked here to allow proper stateblock recording */
3192 TRACE("App is setting the old shader over, nothing to do\n");
3196 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3197 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3198 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 if (NULL == ppShader) {
3209 return WINED3DERR_INVALIDCALL;
3211 *ppShader = This->stateBlock->vertexShader;
3212 if( NULL != *ppShader)
3213 IWineD3DVertexShader_AddRef(*ppShader);
3215 TRACE("(%p) : returning %p\n", This, *ppShader);
3219 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3220 IWineD3DDevice *iface,
3222 CONST BOOL *srcData,
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3228 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3229 iface, srcData, start, count);
3231 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3233 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3234 for (i = 0; i < cnt; i++)
3235 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3237 for (i = start; i < cnt + start; ++i) {
3238 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3241 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3246 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3247 IWineD3DDevice *iface,
3252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 int cnt = min(count, MAX_CONST_B - start);
3255 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3256 iface, dstData, start, count);
3258 if (dstData == NULL || cnt < 0)
3259 return WINED3DERR_INVALIDCALL;
3261 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3265 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3266 IWineD3DDevice *iface,
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3274 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3275 iface, srcData, start, count);
3277 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3279 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3280 for (i = 0; i < cnt; i++)
3281 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3282 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3284 for (i = start; i < cnt + start; ++i) {
3285 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3288 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3293 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3294 IWineD3DDevice *iface,
3299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 int cnt = min(count, MAX_CONST_I - start);
3302 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3303 iface, dstData, start, count);
3305 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3306 return WINED3DERR_INVALIDCALL;
3308 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3313 IWineD3DDevice *iface,
3315 CONST float *srcData,
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3322 iface, srcData, start, count);
3324 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3325 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3326 return WINED3DERR_INVALIDCALL;
3328 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3330 for (i = 0; i < count; i++)
3331 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3332 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3335 if (!This->isRecordingState)
3337 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3341 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3342 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3347 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3348 IWineD3DDevice *iface,
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 int cnt = min(count, This->d3d_vshader_constantF - start);
3356 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3357 iface, dstData, start, count);
3359 if (dstData == NULL || cnt < 0)
3360 return WINED3DERR_INVALIDCALL;
3362 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3366 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3368 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3374 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3376 DWORD i = This->rev_tex_unit_map[unit];
3377 DWORD j = This->texUnitMap[stage];
3379 This->texUnitMap[stage] = unit;
3380 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3382 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3385 This->rev_tex_unit_map[unit] = stage;
3386 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3388 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3392 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3395 This->fixed_function_usage_map = 0;
3396 for (i = 0; i < MAX_TEXTURES; ++i) {
3397 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3398 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3399 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3400 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3401 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3402 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3403 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3404 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3406 if (color_op == WINED3DTOP_DISABLE) {
3407 /* Not used, and disable higher stages */
3411 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3412 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3413 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3414 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3415 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3416 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3417 This->fixed_function_usage_map |= (1 << i);
3420 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3421 This->fixed_function_usage_map |= (1 << (i + 1));
3426 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3428 unsigned int i, tex;
3431 device_update_fixed_function_usage_map(This);
3432 ffu_map = This->fixed_function_usage_map;
3434 if (This->max_ffp_textures == gl_info->limits.texture_stages
3435 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3437 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3439 if (!(ffu_map & 1)) continue;
3441 if (This->texUnitMap[i] != i) {
3442 device_map_stage(This, i, i);
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3444 markTextureStagesDirty(This, i);
3450 /* Now work out the mapping */
3452 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3454 if (!(ffu_map & 1)) continue;
3456 if (This->texUnitMap[i] != tex) {
3457 device_map_stage(This, i, tex);
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3459 markTextureStagesDirty(This, i);
3466 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3468 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3469 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3472 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3473 if (sampler_type[i] && This->texUnitMap[i] != i)
3475 device_map_stage(This, i, i);
3476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3477 if (i < gl_info->limits.texture_stages)
3479 markTextureStagesDirty(This, i);
3485 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3486 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3488 DWORD current_mapping = This->rev_tex_unit_map[unit];
3490 /* Not currently used */
3491 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3493 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3494 /* Used by a fragment sampler */
3496 if (!pshader_sampler_tokens) {
3497 /* No pixel shader, check fixed function */
3498 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3501 /* Pixel shader, check the shader's sampler map */
3502 return !pshader_sampler_tokens[current_mapping];
3505 /* Used by a vertex sampler */
3506 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3509 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3511 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3512 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3513 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3514 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3518 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3520 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3521 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3522 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3525 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3526 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3527 if (vshader_sampler_type[i])
3529 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3531 /* Already mapped somewhere */
3535 while (start >= 0) {
3536 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3538 device_map_stage(This, vsampler_idx, start);
3539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3551 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3553 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3554 BOOL vs = use_vs(This->stateBlock);
3555 BOOL ps = use_ps(This->stateBlock);
3558 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3559 * that would be really messy and require shader recompilation
3560 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3561 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3563 if (ps) device_map_psamplers(This, gl_info);
3564 else device_map_fixed_function_samplers(This, gl_info);
3566 if (vs) device_map_vsamplers(This, ps, gl_info);
3569 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3572 This->updateStateBlock->pixelShader = pShader;
3573 This->updateStateBlock->changed.pixelShader = TRUE;
3575 /* Handle recording of state blocks */
3576 if (This->isRecordingState) {
3577 TRACE("Recording... not performing anything\n");
3580 if (This->isRecordingState) {
3581 TRACE("Recording... not performing anything\n");
3582 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3583 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3587 if(pShader == oldShader) {
3588 TRACE("App is setting the old pixel shader over, nothing to do\n");
3592 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3593 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3595 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3601 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 if (NULL == ppShader) {
3605 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3606 return WINED3DERR_INVALIDCALL;
3609 *ppShader = This->stateBlock->pixelShader;
3610 if (NULL != *ppShader) {
3611 IWineD3DPixelShader_AddRef(*ppShader);
3613 TRACE("(%p) : returning %p\n", This, *ppShader);
3617 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3618 IWineD3DDevice *iface,
3620 CONST BOOL *srcData,
3623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3624 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3626 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3627 iface, srcData, start, count);
3629 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3631 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3632 for (i = 0; i < cnt; i++)
3633 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3635 for (i = start; i < cnt + start; ++i) {
3636 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3639 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3644 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3645 IWineD3DDevice *iface,
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 int cnt = min(count, MAX_CONST_B - start);
3653 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3654 iface, dstData, start, count);
3656 if (dstData == NULL || cnt < 0)
3657 return WINED3DERR_INVALIDCALL;
3659 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3663 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3664 IWineD3DDevice *iface,
3669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3670 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3672 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3673 iface, srcData, start, count);
3675 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3677 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3678 for (i = 0; i < cnt; i++)
3679 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3680 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3682 for (i = start; i < cnt + start; ++i) {
3683 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3686 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3691 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3692 IWineD3DDevice *iface,
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 int cnt = min(count, MAX_CONST_I - start);
3700 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3701 iface, dstData, start, count);
3703 if (dstData == NULL || cnt < 0)
3704 return WINED3DERR_INVALIDCALL;
3706 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3710 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3711 IWineD3DDevice *iface,
3713 CONST float *srcData,
3716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3720 iface, srcData, start, count);
3722 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3723 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3724 return WINED3DERR_INVALIDCALL;
3726 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3728 for (i = 0; i < count; i++)
3729 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3730 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3733 if (!This->isRecordingState)
3735 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3739 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3740 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3745 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3746 IWineD3DDevice *iface,
3751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3752 int cnt = min(count, This->d3d_pshader_constantF - start);
3754 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3755 iface, dstData, start, count);
3757 if (dstData == NULL || cnt < 0)
3758 return WINED3DERR_INVALIDCALL;
3760 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3764 /* Context activation is done by the caller. */
3765 /* Do not call while under the GL lock. */
3766 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3767 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3768 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3771 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3772 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3775 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3779 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3781 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3784 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3786 ERR("Source has no position mask\n");
3787 return WINED3DERR_INVALIDCALL;
3790 if (!dest->resource.allocatedMemory)
3791 buffer_get_sysmem(dest, gl_info);
3793 /* Get a pointer into the destination vbo(create one if none exists) and
3794 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3796 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3798 dest->flags |= WINED3D_BUFFER_CREATEBO;
3799 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3802 if (dest->buffer_object)
3804 unsigned char extrabytes = 0;
3805 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3806 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3807 * this may write 4 extra bytes beyond the area that should be written
3809 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3810 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3811 if(!dest_conv_addr) {
3812 ERR("Out of memory\n");
3813 /* Continue without storing converted vertices */
3815 dest_conv = dest_conv_addr;
3819 * a) WINED3DRS_CLIPPING is enabled
3820 * b) WINED3DVOP_CLIP is passed
3822 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3823 static BOOL warned = FALSE;
3825 * The clipping code is not quite correct. Some things need
3826 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3827 * so disable clipping for now.
3828 * (The graphics in Half-Life are broken, and my processvertices
3829 * test crashes with IDirect3DDevice3)
3835 FIXME("Clipping is broken and disabled for now\n");
3837 } else doClip = FALSE;
3838 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3840 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3843 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3844 WINED3DTS_PROJECTION,
3846 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3847 WINED3DTS_WORLDMATRIX(0),
3850 TRACE("View mat:\n");
3851 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);
3852 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);
3853 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);
3854 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);
3856 TRACE("Proj mat:\n");
3857 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);
3858 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);
3859 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);
3860 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);
3862 TRACE("World mat:\n");
3863 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);
3864 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);
3865 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);
3866 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);
3868 /* Get the viewport */
3869 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3870 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3871 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3873 multiply_matrix(&mat,&view_mat,&world_mat);
3874 multiply_matrix(&mat,&proj_mat,&mat);
3876 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3878 for (i = 0; i < dwCount; i+= 1) {
3879 unsigned int tex_index;
3881 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3882 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3883 /* The position first */
3884 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3885 const float *p = (const float *)(element->data + i * element->stride);
3887 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3889 /* Multiplication with world, view and projection matrix */
3890 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);
3891 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);
3892 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);
3893 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);
3895 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3897 /* WARNING: The following things are taken from d3d7 and were not yet checked
3898 * against d3d8 or d3d9!
3901 /* Clipping conditions: From msdn
3903 * A vertex is clipped if it does not match the following requirements
3907 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3909 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3910 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3915 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3916 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3919 /* "Normal" viewport transformation (not clipped)
3920 * 1) The values are divided by rhw
3921 * 2) The y axis is negative, so multiply it with -1
3922 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3923 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3924 * 4) Multiply x with Width/2 and add Width/2
3925 * 5) The same for the height
3926 * 6) Add the viewpoint X and Y to the 2D coordinates and
3927 * The minimum Z value to z
3928 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3930 * Well, basically it's simply a linear transformation into viewport
3942 z *= vp.MaxZ - vp.MinZ;
3944 x += vp.Width / 2 + vp.X;
3945 y += vp.Height / 2 + vp.Y;
3950 /* That vertex got clipped
3951 * Contrary to OpenGL it is not dropped completely, it just
3952 * undergoes a different calculation.
3954 TRACE("Vertex got clipped\n");
3961 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3962 * outside of the main vertex buffer memory. That needs some more
3967 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3970 ( (float *) dest_ptr)[0] = x;
3971 ( (float *) dest_ptr)[1] = y;
3972 ( (float *) dest_ptr)[2] = z;
3973 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3975 dest_ptr += 3 * sizeof(float);
3977 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3978 dest_ptr += sizeof(float);
3983 ( (float *) dest_conv)[0] = x * w;
3984 ( (float *) dest_conv)[1] = y * w;
3985 ( (float *) dest_conv)[2] = z * w;
3986 ( (float *) dest_conv)[3] = w;
3988 dest_conv += 3 * sizeof(float);
3990 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3991 dest_conv += sizeof(float);
3995 if (DestFVF & WINED3DFVF_PSIZE) {
3996 dest_ptr += sizeof(DWORD);
3997 if(dest_conv) dest_conv += sizeof(DWORD);
3999 if (DestFVF & WINED3DFVF_NORMAL) {
4000 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4001 const float *normal = (const float *)(element->data + i * element->stride);
4002 /* AFAIK this should go into the lighting information */
4003 FIXME("Didn't expect the destination to have a normal\n");
4004 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4006 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4010 if (DestFVF & WINED3DFVF_DIFFUSE) {
4011 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4012 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4013 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4015 static BOOL warned = FALSE;
4018 ERR("No diffuse color in source, but destination has one\n");
4022 *( (DWORD *) dest_ptr) = 0xffffffff;
4023 dest_ptr += sizeof(DWORD);
4026 *( (DWORD *) dest_conv) = 0xffffffff;
4027 dest_conv += sizeof(DWORD);
4031 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4033 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4034 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4035 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4036 dest_conv += sizeof(DWORD);
4041 if (DestFVF & WINED3DFVF_SPECULAR)
4043 /* What's the color value in the feedback buffer? */
4044 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4045 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4046 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4048 static BOOL warned = FALSE;
4051 ERR("No specular color in source, but destination has one\n");
4055 *( (DWORD *) dest_ptr) = 0xFF000000;
4056 dest_ptr += sizeof(DWORD);
4059 *( (DWORD *) dest_conv) = 0xFF000000;
4060 dest_conv += sizeof(DWORD);
4064 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4066 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4067 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4068 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4069 dest_conv += sizeof(DWORD);
4074 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4075 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4076 const float *tex_coord = (const float *)(element->data + i * element->stride);
4077 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4079 ERR("No source texture, but destination requests one\n");
4080 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4081 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4084 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4086 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4096 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4097 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4098 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4099 dwCount * get_flexible_vertex_size(DestFVF),
4101 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4105 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4110 #undef copy_and_next
4112 /* Do not call while under the GL lock. */
4113 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4114 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 struct wined3d_stream_info stream_info;
4119 const struct wined3d_gl_info *gl_info;
4120 struct wined3d_context *context;
4121 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4124 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4127 ERR("Output vertex declaration not implemented yet\n");
4130 /* Need any context to write to the vbo. */
4131 context = context_acquire(This, NULL);
4132 gl_info = context->gl_info;
4134 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4135 * control the streamIsUP flag, thus restore it afterwards.
4137 This->stateBlock->streamIsUP = FALSE;
4138 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4139 This->stateBlock->streamIsUP = streamWasUP;
4141 if(vbo || SrcStartIndex) {
4143 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4144 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4146 * Also get the start index in, but only loop over all elements if there's something to add at all.
4148 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4150 struct wined3d_stream_info_element *e;
4152 if (!(stream_info.use_map & (1 << i))) continue;
4154 e = &stream_info.elements[i];
4155 if (e->buffer_object)
4157 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4158 e->buffer_object = 0;
4159 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4161 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4162 vb->buffer_object = 0;
4165 if (e->data) e->data += e->stride * SrcStartIndex;
4169 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4170 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4172 context_release(context);
4178 * Get / Set Texture Stage States
4179 * TODO: Verify against dx9 definitions
4181 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4183 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4184 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4186 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4188 if (Stage >= gl_info->limits.texture_stages)
4190 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4191 Stage, gl_info->limits.texture_stages - 1);
4195 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4196 This->updateStateBlock->textureState[Stage][Type] = Value;
4198 if (This->isRecordingState) {
4199 TRACE("Recording... not performing anything\n");
4203 /* Checked after the assignments to allow proper stateblock recording */
4204 if(oldValue == Value) {
4205 TRACE("App is setting the old value over, nothing to do\n");
4209 if(Stage > This->stateBlock->lowest_disabled_stage &&
4210 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4211 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4212 * Changes in other states are important on disabled stages too
4217 if(Type == WINED3DTSS_COLOROP) {
4220 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4221 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4222 * they have to be disabled
4224 * The current stage is dirtified below.
4226 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4227 TRACE("Additionally dirtifying stage %u\n", i);
4228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4230 This->stateBlock->lowest_disabled_stage = Stage;
4231 TRACE("New lowest disabled: %u\n", Stage);
4232 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4233 /* Previously disabled stage enabled. Stages above it may need enabling
4234 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4235 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4237 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4240 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4242 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4245 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4248 This->stateBlock->lowest_disabled_stage = i;
4249 TRACE("New lowest disabled: %u\n", i);
4253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4258 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4260 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4261 *pValue = This->updateStateBlock->textureState[Stage][Type];
4268 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4269 DWORD stage, IWineD3DBaseTexture *texture)
4271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4272 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4273 IWineD3DBaseTexture *prev;
4275 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4277 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4278 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4280 /* Windows accepts overflowing this array... we do not. */
4281 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4283 WARN("Ignoring invalid stage %u.\n", stage);
4287 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4288 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4290 WARN("Rejecting attempt to set scratch texture.\n");
4291 return WINED3DERR_INVALIDCALL;
4294 This->updateStateBlock->changed.textures |= 1 << stage;
4296 prev = This->updateStateBlock->textures[stage];
4297 TRACE("Previous texture %p.\n", prev);
4299 if (texture == prev)
4301 TRACE("App is setting the same texture again, nothing to do.\n");
4305 TRACE("Setting new texture to %p.\n", texture);
4306 This->updateStateBlock->textures[stage] = texture;
4308 if (This->isRecordingState)
4310 TRACE("Recording... not performing anything\n");
4312 if (texture) IWineD3DBaseTexture_AddRef(texture);
4313 if (prev) IWineD3DBaseTexture_Release(prev);
4320 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4321 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4322 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4324 IWineD3DBaseTexture_AddRef(texture);
4326 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4331 if (!prev && stage < gl_info->limits.texture_stages)
4333 /* The source arguments for color and alpha ops have different
4334 * meanings when a NULL texture is bound, so the COLOROP and
4335 * ALPHAOP have to be dirtified. */
4336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4340 if (bind_count == 1) t->baseTexture.sampler = stage;
4345 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4346 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4348 IWineD3DBaseTexture_Release(prev);
4350 if (!texture && stage < gl_info->limits.texture_stages)
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4356 if (bind_count && t->baseTexture.sampler == stage)
4360 /* Search for other stages the texture is bound to. Shouldn't
4361 * happen if applications bind textures to a single stage only. */
4362 TRACE("Searching for other stages the texture is bound to.\n");
4363 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4365 if (This->updateStateBlock->textures[i] == prev)
4367 TRACE("Texture is also bound to stage %u.\n", i);
4368 t->baseTexture.sampler = i;
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4380 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4385 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4386 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4389 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4390 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4391 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4394 *ppTexture=This->stateBlock->textures[Stage];
4396 IWineD3DBaseTexture_AddRef(*ppTexture);
4398 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4406 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4407 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4409 IWineD3DSwapChain *swapchain;
4412 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4413 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4415 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4418 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4422 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4423 IWineD3DSwapChain_Release(swapchain);
4426 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4433 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 WARN("(%p) : stub, calling idirect3d for now\n", This);
4436 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4439 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 IWineD3DSwapChain *swapChain;
4444 if(iSwapChain > 0) {
4445 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4446 if (hr == WINED3D_OK) {
4447 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4448 IWineD3DSwapChain_Release(swapChain);
4450 FIXME("(%p) Error getting display mode\n", This);
4453 /* Don't read the real display mode,
4454 but return the stored mode instead. X11 can't change the color
4455 depth, and some apps are pretty angry if they SetDisplayMode from
4456 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4458 Also don't relay to the swapchain because with ddraw it's possible
4459 that there isn't a swapchain at all */
4460 pMode->Width = This->ddraw_width;
4461 pMode->Height = This->ddraw_height;
4462 pMode->Format = This->ddraw_format;
4463 pMode->RefreshRate = 0;
4471 * Stateblock related functions
4474 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 IWineD3DStateBlock *stateblock;
4479 TRACE("(%p)\n", This);
4481 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4483 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4484 if (FAILED(hr)) return hr;
4486 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4487 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4488 This->isRecordingState = TRUE;
4490 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4495 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4499 if (!This->isRecordingState) {
4500 WARN("(%p) not recording! returning error\n", This);
4501 *ppStateBlock = NULL;
4502 return WINED3DERR_INVALIDCALL;
4505 stateblock_init_contained_states(object);
4507 *ppStateBlock = (IWineD3DStateBlock*) object;
4508 This->isRecordingState = FALSE;
4509 This->updateStateBlock = This->stateBlock;
4510 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4511 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4512 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4517 * Scene related functions
4519 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4520 /* At the moment we have no need for any functionality at the beginning
4522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4523 TRACE("(%p)\n", This);
4526 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4527 return WINED3DERR_INVALIDCALL;
4529 This->inScene = TRUE;
4533 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4536 struct wined3d_context *context;
4538 TRACE("(%p)\n", This);
4540 if(!This->inScene) {
4541 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4542 return WINED3DERR_INVALIDCALL;
4545 context = context_acquire(This, NULL);
4546 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4548 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4550 context_release(context);
4552 This->inScene = FALSE;
4556 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4557 const RECT *pSourceRect, const RECT *pDestRect,
4558 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4560 IWineD3DSwapChain *swapChain = NULL;
4562 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4564 TRACE("iface %p.\n", iface);
4566 for(i = 0 ; i < swapchains ; i ++) {
4568 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4569 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4570 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4571 IWineD3DSwapChain_Release(swapChain);
4577 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4578 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4580 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4581 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4584 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4585 iface, rect_count, rects, flags, color, depth, stencil);
4587 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4589 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4590 /* TODO: What about depth stencil buffers without stencil bits? */
4591 return WINED3DERR_INVALIDCALL;
4594 device_get_draw_rect(device, &draw_rect);
4596 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4597 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4604 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4605 WINED3DPRIMITIVETYPE primitive_type)
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4609 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4611 This->updateStateBlock->changed.primitive_type = TRUE;
4612 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4615 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4616 WINED3DPRIMITIVETYPE *primitive_type)
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4622 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4624 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4627 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4631 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4633 if(!This->stateBlock->vertexDecl) {
4634 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4635 return WINED3DERR_INVALIDCALL;
4638 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4639 if(This->stateBlock->streamIsUP) {
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4641 This->stateBlock->streamIsUP = FALSE;
4644 if(This->stateBlock->loadBaseVertexIndex != 0) {
4645 This->stateBlock->loadBaseVertexIndex = 0;
4646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4648 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4649 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4653 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 IWineD3DBuffer *pIB;
4660 pIB = This->stateBlock->pIndexData;
4662 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4663 * without an index buffer set. (The first time at least...)
4664 * D3D8 simply dies, but I doubt it can do much harm to return
4665 * D3DERR_INVALIDCALL there as well. */
4666 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4667 return WINED3DERR_INVALIDCALL;
4670 if(!This->stateBlock->vertexDecl) {
4671 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4672 return WINED3DERR_INVALIDCALL;
4675 if(This->stateBlock->streamIsUP) {
4676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4677 This->stateBlock->streamIsUP = FALSE;
4679 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4681 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4683 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4689 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4690 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4691 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4694 drawPrimitive(iface, index_count, startIndex, idxStride,
4695 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4700 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4701 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4707 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4709 if(!This->stateBlock->vertexDecl) {
4710 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4711 return WINED3DERR_INVALIDCALL;
4714 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4715 vb = This->stateBlock->streamSource[0];
4716 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4717 if (vb) IWineD3DBuffer_Release(vb);
4718 This->stateBlock->streamOffset[0] = 0;
4719 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4720 This->stateBlock->streamIsUP = TRUE;
4721 This->stateBlock->loadBaseVertexIndex = 0;
4723 /* TODO: Only mark dirty if drawing from a different UP address */
4724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4726 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4728 /* MSDN specifies stream zero settings must be set to NULL */
4729 This->stateBlock->streamStride[0] = 0;
4730 This->stateBlock->streamSource[0] = NULL;
4732 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4733 * the new stream sources or use UP drawing again
4738 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4739 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4740 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4747 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4748 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4750 if(!This->stateBlock->vertexDecl) {
4751 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4752 return WINED3DERR_INVALIDCALL;
4755 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4761 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4762 vb = This->stateBlock->streamSource[0];
4763 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4764 if (vb) IWineD3DBuffer_Release(vb);
4765 This->stateBlock->streamIsUP = TRUE;
4766 This->stateBlock->streamOffset[0] = 0;
4767 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4769 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4770 This->stateBlock->baseVertexIndex = 0;
4771 This->stateBlock->loadBaseVertexIndex = 0;
4772 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4776 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4778 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4779 This->stateBlock->streamSource[0] = NULL;
4780 This->stateBlock->streamStride[0] = 0;
4781 ib = This->stateBlock->pIndexData;
4783 IWineD3DBuffer_Release(ib);
4784 This->stateBlock->pIndexData = NULL;
4786 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4787 * SetStreamSource to specify a vertex buffer
4793 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4794 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4798 /* Mark the state dirty until we have nicer tracking
4799 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4804 This->stateBlock->baseVertexIndex = 0;
4805 This->up_strided = DrawPrimStrideData;
4806 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4807 This->up_strided = NULL;
4811 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4812 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4813 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4816 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4818 /* Mark the state dirty until we have nicer tracking
4819 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4824 This->stateBlock->streamIsUP = TRUE;
4825 This->stateBlock->baseVertexIndex = 0;
4826 This->up_strided = DrawPrimStrideData;
4827 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4828 This->up_strided = NULL;
4832 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4833 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4834 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4836 WINED3DLOCKED_BOX src;
4837 WINED3DLOCKED_BOX dst;
4840 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4841 iface, pSourceVolume, pDestinationVolume);
4843 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4844 * dirtification to improve loading performance.
4846 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4847 if(FAILED(hr)) return hr;
4848 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4850 IWineD3DVolume_UnlockBox(pSourceVolume);
4854 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4856 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4858 IWineD3DVolume_UnlockBox(pSourceVolume);
4860 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4865 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4866 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4868 unsigned int level_count, i;
4869 WINED3DRESOURCETYPE type;
4872 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4874 /* Verify that the source and destination textures are non-NULL. */
4875 if (!src_texture || !dst_texture)
4877 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4878 return WINED3DERR_INVALIDCALL;
4881 if (src_texture == dst_texture)
4883 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4884 return WINED3DERR_INVALIDCALL;
4887 /* Verify that the source and destination textures are the same type. */
4888 type = IWineD3DBaseTexture_GetType(src_texture);
4889 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4891 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4892 return WINED3DERR_INVALIDCALL;
4895 /* Check that both textures have the identical numbers of levels. */
4896 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4897 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4899 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4900 return WINED3DERR_INVALIDCALL;
4903 /* Make sure that the destination texture is loaded. */
4904 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4906 /* Update every surface level of the texture. */
4909 case WINED3DRTYPE_TEXTURE:
4911 IWineD3DSurface *src_surface;
4912 IWineD3DSurface *dst_surface;
4914 for (i = 0; i < level_count; ++i)
4916 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4917 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4918 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4919 IWineD3DSurface_Release(dst_surface);
4920 IWineD3DSurface_Release(src_surface);
4923 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4930 case WINED3DRTYPE_CUBETEXTURE:
4932 IWineD3DSurface *src_surface;
4933 IWineD3DSurface *dst_surface;
4934 WINED3DCUBEMAP_FACES face;
4936 for (i = 0; i < level_count; ++i)
4938 /* Update each cube face. */
4939 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4941 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4942 face, i, &src_surface);
4943 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4944 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4945 face, i, &dst_surface);
4946 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4947 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4948 IWineD3DSurface_Release(dst_surface);
4949 IWineD3DSurface_Release(src_surface);
4952 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4960 case WINED3DRTYPE_VOLUMETEXTURE:
4962 IWineD3DVolume *src_volume;
4963 IWineD3DVolume *dst_volume;
4965 for (i = 0; i < level_count; ++i)
4967 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4968 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4969 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4970 IWineD3DVolume_Release(dst_volume);
4971 IWineD3DVolume_Release(src_volume);
4974 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4982 FIXME("Unsupported texture type %#x.\n", type);
4983 return WINED3DERR_INVALIDCALL;
4989 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4990 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4992 IWineD3DSwapChain *swapchain;
4995 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
4997 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4998 if (FAILED(hr)) return hr;
5000 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5001 IWineD3DSwapChain_Release(swapchain);
5006 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 IWineD3DBaseTextureImpl *texture;
5011 TRACE("(%p) : %p\n", This, pNumPasses);
5013 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5014 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5015 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5016 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5018 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5019 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5020 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5023 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5024 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5026 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5027 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5030 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5031 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5034 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5035 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5036 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5041 /* return a sensible default */
5044 TRACE("returning D3D_OK\n");
5048 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5052 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5054 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5055 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5056 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5058 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5063 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 PALETTEENTRY **palettes;
5069 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5071 if (PaletteNumber >= MAX_PALETTES) {
5072 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5073 return WINED3DERR_INVALIDCALL;
5076 if (PaletteNumber >= This->NumberOfPalettes) {
5077 NewSize = This->NumberOfPalettes;
5080 } while(PaletteNumber >= NewSize);
5081 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5083 ERR("Out of memory!\n");
5084 return E_OUTOFMEMORY;
5086 This->palettes = palettes;
5087 This->NumberOfPalettes = NewSize;
5090 if (!This->palettes[PaletteNumber]) {
5091 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5092 if (!This->palettes[PaletteNumber]) {
5093 ERR("Out of memory!\n");
5094 return E_OUTOFMEMORY;
5098 for (j = 0; j < 256; ++j) {
5099 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5100 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5101 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5102 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5104 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5105 TRACE("(%p) : returning\n", This);
5109 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5112 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5113 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5114 /* What happens in such situation isn't documented; Native seems to silently abort
5115 on such conditions. Return Invalid Call. */
5116 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5117 return WINED3DERR_INVALIDCALL;
5119 for (j = 0; j < 256; ++j) {
5120 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5121 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5122 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5123 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5125 TRACE("(%p) : returning\n", This);
5129 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5132 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5133 (tested with reference rasterizer). Return Invalid Call. */
5134 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5135 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5136 return WINED3DERR_INVALIDCALL;
5138 /*TODO: stateblocks */
5139 if (This->currentPalette != PaletteNumber) {
5140 This->currentPalette = PaletteNumber;
5141 dirtify_p8_texture_samplers(This);
5143 TRACE("(%p) : returning\n", This);
5147 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 if (PaletteNumber == NULL) {
5150 WARN("(%p) : returning Invalid Call\n", This);
5151 return WINED3DERR_INVALIDCALL;
5153 /*TODO: stateblocks */
5154 *PaletteNumber = This->currentPalette;
5155 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5159 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 FIXME("(%p) : stub\n", This);
5168 This->softwareVertexProcessing = bSoftware;
5173 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5178 FIXME("(%p) : stub\n", This);
5181 return This->softwareVertexProcessing;
5184 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5185 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5187 IWineD3DSwapChain *swapchain;
5190 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5191 iface, swapchain_idx, raster_status);
5193 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5196 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5200 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5201 IWineD3DSwapChain_Release(swapchain);
5204 WARN("Failed to get raster status, hr %#x.\n", hr);
5211 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5214 if(nSegments != 0.0f) {
5217 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5224 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5229 FIXME("iface %p stub!\n", iface);
5235 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5236 IWineD3DSurface *src_surface, const RECT *src_rect,
5237 IWineD3DSurface *dst_surface, const POINT *dst_point)
5239 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5240 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 const struct wined3d_format *src_format;
5243 const struct wined3d_format *dst_format;
5244 const struct wined3d_gl_info *gl_info;
5245 struct wined3d_context *context;
5246 const unsigned char *data;
5247 UINT update_w, update_h;
5248 CONVERT_TYPES convert;
5252 struct wined3d_format format;
5254 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5255 iface, src_surface, wine_dbgstr_rect(src_rect),
5256 dst_surface, wine_dbgstr_point(dst_point));
5258 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5260 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5261 src_surface, dst_surface);
5262 return WINED3DERR_INVALIDCALL;
5265 src_format = src_impl->resource.format;
5266 dst_format = dst_impl->resource.format;
5268 if (src_format->id != dst_format->id)
5270 WARN("Source and destination surfaces should have the same format.\n");
5271 return WINED3DERR_INVALIDCALL;
5274 dst_x = dst_point ? dst_point->x : 0;
5275 dst_y = dst_point ? dst_point->y : 0;
5277 /* This call loads the OpenGL surface directly, instead of copying the
5278 * surface to the destination's sysmem copy. If surface conversion is
5279 * needed, use BltFast instead to copy in sysmem and use regular surface
5281 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5282 if (convert != NO_CONVERSION || format.convert)
5283 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5285 context = context_acquire(This, NULL);
5286 gl_info = context->gl_info;
5289 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5290 checkGLcall("glActiveTextureARB");
5293 /* Make sure the surface is loaded and up to date */
5294 surface_internal_preload(dst_impl, SRGB_RGB);
5295 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5297 src_w = src_impl->currentDesc.Width;
5298 src_h = src_impl->currentDesc.Height;
5299 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5300 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5302 data = IWineD3DSurface_GetData(src_surface);
5303 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5307 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5309 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5310 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5311 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5315 data += (src_rect->top / src_format->block_height) * src_pitch;
5316 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5319 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5320 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5321 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5323 if (row_length == src_pitch)
5325 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5326 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5332 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5333 * can't use the unpack row length like below. */
5334 for (row = 0, y = dst_y; row < row_count; ++row)
5336 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5337 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5338 y += src_format->block_height;
5342 checkGLcall("glCompressedTexSubImage2DARB");
5348 data += src_rect->top * src_w * src_format->byte_count;
5349 data += src_rect->left * src_format->byte_count;
5352 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5353 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5354 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5356 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5357 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5358 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5359 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5360 checkGLcall("glTexSubImage2D");
5364 context_release(context);
5366 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5367 sampler = This->rev_tex_unit_map[0];
5368 if (sampler != WINED3D_UNMAPPED_STAGE)
5370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5376 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 struct WineD3DRectPatch *patch;
5379 GLenum old_primitive_type;
5383 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5385 if(!(Handle || pRectPatchInfo)) {
5386 /* TODO: Write a test for the return value, thus the FIXME */
5387 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5388 return WINED3DERR_INVALIDCALL;
5392 i = PATCHMAP_HASHFUNC(Handle);
5394 LIST_FOR_EACH(e, &This->patches[i]) {
5395 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5396 if(patch->Handle == Handle) {
5403 TRACE("Patch does not exist. Creating a new one\n");
5404 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5405 patch->Handle = Handle;
5406 list_add_head(&This->patches[i], &patch->entry);
5408 TRACE("Found existing patch %p\n", patch);
5411 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5412 * attributes we have to tesselate, read back, and draw. This needs a patch
5413 * management structure instance. Create one.
5415 * A possible improvement is to check if a vertex shader is used, and if not directly
5418 FIXME("Drawing an uncached patch. This is slow\n");
5419 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5422 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5423 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5424 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5426 TRACE("Tesselation density or patch info changed, retesselating\n");
5428 if(pRectPatchInfo) {
5429 patch->RectPatchInfo = *pRectPatchInfo;
5431 patch->numSegs[0] = pNumSegs[0];
5432 patch->numSegs[1] = pNumSegs[1];
5433 patch->numSegs[2] = pNumSegs[2];
5434 patch->numSegs[3] = pNumSegs[3];
5436 hr = tesselate_rectpatch(This, patch);
5438 WARN("Patch tesselation failed\n");
5440 /* Do not release the handle to store the params of the patch */
5442 HeapFree(GetProcessHeap(), 0, patch);
5448 This->currentPatch = patch;
5449 old_primitive_type = This->stateBlock->gl_primitive_type;
5450 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5451 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5452 This->stateBlock->gl_primitive_type = old_primitive_type;
5453 This->currentPatch = NULL;
5455 /* Destroy uncached patches */
5457 HeapFree(GetProcessHeap(), 0, patch->mem);
5458 HeapFree(GetProcessHeap(), 0, patch);
5463 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5464 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5466 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5467 iface, handle, segment_count, patch_info);
5472 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5475 struct WineD3DRectPatch *patch;
5477 TRACE("(%p) Handle(%d)\n", This, Handle);
5479 i = PATCHMAP_HASHFUNC(Handle);
5480 LIST_FOR_EACH(e, &This->patches[i]) {
5481 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5482 if(patch->Handle == Handle) {
5483 TRACE("Deleting patch %p\n", patch);
5484 list_remove(&patch->entry);
5485 HeapFree(GetProcessHeap(), 0, patch->mem);
5486 HeapFree(GetProcessHeap(), 0, patch);
5491 /* TODO: Write a test for the return value */
5492 FIXME("Attempt to destroy nonexistent patch\n");
5493 return WINED3DERR_INVALIDCALL;
5496 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5497 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5499 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5501 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5502 iface, surface, wine_dbgstr_rect(rect),
5503 color->r, color->g, color->b, color->a);
5505 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5507 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5508 return WINED3DERR_INVALIDCALL;
5511 return surface_color_fill(s, rect, color);
5514 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5515 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5517 IWineD3DResource *resource;
5520 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5523 ERR("Failed to get resource, hr %#x\n", hr);
5527 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5529 FIXME("Only supported on surface resources\n");
5530 IWineD3DResource_Release(resource);
5534 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5535 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5537 IWineD3DResource_Release(resource);
5540 /* rendertarget and depth stencil functions */
5541 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5542 DWORD render_target_idx, IWineD3DSurface **render_target)
5544 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5546 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5547 iface, render_target_idx, render_target);
5549 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5551 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5552 return WINED3DERR_INVALIDCALL;
5555 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5556 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5558 TRACE("Returning render target %p.\n", *render_target);
5563 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5564 IWineD3DSurface *front, IWineD3DSurface *back)
5566 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5567 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5568 IWineD3DSwapChainImpl *swapchain;
5571 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5573 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5575 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5579 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5581 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5582 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5583 return WINED3DERR_INVALIDCALL;
5588 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5590 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5591 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5592 return WINED3DERR_INVALIDCALL;
5595 if (!swapchain->back_buffers)
5597 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5598 if (!swapchain->back_buffers)
5600 ERR("Failed to allocate back buffer array memory.\n");
5601 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5602 return E_OUTOFMEMORY;
5607 if (swapchain->front_buffer != front_impl)
5609 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5611 if (swapchain->front_buffer)
5612 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5613 swapchain->front_buffer = front_impl;
5616 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5619 if (swapchain->back_buffers[0] != back_impl)
5621 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5623 if (swapchain->back_buffers[0])
5624 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5625 swapchain->back_buffers[0] = back_impl;
5629 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5630 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5631 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5632 swapchain->presentParms.BackBufferCount = 1;
5634 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5638 swapchain->presentParms.BackBufferCount = 0;
5639 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5640 swapchain->back_buffers = NULL;
5644 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5648 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5650 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5652 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5654 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5655 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5656 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5657 IWineD3DSurface_AddRef(*depth_stencil);
5662 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5663 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5665 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5666 IWineD3DSurfaceImpl *prev;
5668 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5669 iface, render_target_idx, render_target, set_viewport);
5671 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5673 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5674 return WINED3DERR_INVALIDCALL;
5677 prev = device->render_targets[render_target_idx];
5678 if (render_target == (IWineD3DSurface *)prev)
5680 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5684 /* Render target 0 can't be set to NULL. */
5685 if (!render_target && !render_target_idx)
5687 WARN("Trying to set render target 0 to NULL.\n");
5688 return WINED3DERR_INVALIDCALL;
5691 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5693 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5694 return WINED3DERR_INVALIDCALL;
5697 if (render_target) IWineD3DSurface_AddRef(render_target);
5698 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5699 /* Release after the assignment, to prevent device_resource_released()
5700 * from seeing the surface as still in use. */
5701 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5703 /* Render target 0 is special. */
5704 if (!render_target_idx && set_viewport)
5706 /* Set the viewport and scissor rectangles, if requested. Tests show
5707 * that stateblock recording is ignored, the change goes directly
5708 * into the primary stateblock. */
5709 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5710 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5711 device->stateBlock->viewport.X = 0;
5712 device->stateBlock->viewport.Y = 0;
5713 device->stateBlock->viewport.MaxZ = 1.0f;
5714 device->stateBlock->viewport.MinZ = 0.0f;
5715 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5717 device->stateBlock->scissorRect.top = 0;
5718 device->stateBlock->scissorRect.left = 0;
5719 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5720 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5721 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5727 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 IWineD3DSurfaceImpl *tmp;
5732 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5734 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5736 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5740 if (This->depth_stencil)
5742 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5743 || This->depth_stencil->Flags & SFLAG_DISCARD)
5745 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5746 This->depth_stencil->currentDesc.Width,
5747 This->depth_stencil->currentDesc.Height);
5748 if (This->depth_stencil == This->onscreen_depth_stencil)
5750 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5751 This->onscreen_depth_stencil = NULL;
5756 tmp = This->depth_stencil;
5757 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5758 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5759 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5761 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5763 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5772 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5773 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5777 WINED3DLOCKED_RECT lockedRect;
5779 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5780 iface, XHotSpot, YHotSpot, cursor_image);
5782 /* some basic validation checks */
5783 if (This->cursorTexture)
5785 struct wined3d_context *context = context_acquire(This, NULL);
5787 glDeleteTextures(1, &This->cursorTexture);
5789 context_release(context);
5790 This->cursorTexture = 0;
5793 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5794 This->haveHardwareCursor = TRUE;
5796 This->haveHardwareCursor = FALSE;
5800 WINED3DLOCKED_RECT rect;
5802 /* MSDN: Cursor must be A8R8G8B8 */
5803 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5805 WARN("surface %p has an invalid format.\n", cursor_image);
5806 return WINED3DERR_INVALIDCALL;
5809 /* MSDN: Cursor must be smaller than the display mode */
5810 if (s->currentDesc.Width > This->ddraw_width
5811 || s->currentDesc.Height > This->ddraw_height)
5813 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5814 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5815 return WINED3DERR_INVALIDCALL;
5818 if (!This->haveHardwareCursor) {
5819 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5821 /* Do not store the surface's pointer because the application may
5822 * release it after setting the cursor image. Windows doesn't
5823 * addref the set surface, so we can't do this either without
5824 * creating circular refcount dependencies. Copy out the gl texture
5827 This->cursorWidth = s->currentDesc.Width;
5828 This->cursorHeight = s->currentDesc.Height;
5829 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5831 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5832 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5833 struct wined3d_context *context;
5834 char *mem, *bits = rect.pBits;
5835 GLint intfmt = format->glInternal;
5836 GLint gl_format = format->glFormat;
5837 GLint type = format->glType;
5838 INT height = This->cursorHeight;
5839 INT width = This->cursorWidth;
5840 INT bpp = format->byte_count;
5844 /* Reformat the texture memory (pitch and width can be
5846 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5847 for(i = 0; i < height; i++)
5848 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5849 IWineD3DSurface_UnlockRect(cursor_image);
5851 context = context_acquire(This, NULL);
5855 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5857 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5858 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5861 /* Make sure that a proper texture unit is selected */
5862 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5863 checkGLcall("glActiveTextureARB");
5864 sampler = This->rev_tex_unit_map[0];
5865 if (sampler != WINED3D_UNMAPPED_STAGE)
5867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5869 /* Create a new cursor texture */
5870 glGenTextures(1, &This->cursorTexture);
5871 checkGLcall("glGenTextures");
5872 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5873 checkGLcall("glBindTexture");
5874 /* Copy the bitmap memory into the cursor texture */
5875 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5876 HeapFree(GetProcessHeap(), 0, mem);
5877 checkGLcall("glTexImage2D");
5879 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5881 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5882 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5887 context_release(context);
5891 FIXME("A cursor texture was not returned.\n");
5892 This->cursorTexture = 0;
5897 /* Draw a hardware cursor */
5898 ICONINFO cursorInfo;
5900 /* Create and clear maskBits because it is not needed for
5901 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5903 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5904 (s->currentDesc.Width * s->currentDesc.Height / 8));
5905 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5906 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5907 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5909 cursorInfo.fIcon = FALSE;
5910 cursorInfo.xHotspot = XHotSpot;
5911 cursorInfo.yHotspot = YHotSpot;
5912 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5913 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5914 IWineD3DSurface_UnlockRect(cursor_image);
5915 /* Create our cursor and clean up. */
5916 cursor = CreateIconIndirect(&cursorInfo);
5918 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5919 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5920 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5921 This->hardwareCursor = cursor;
5922 HeapFree(GetProcessHeap(), 0, maskBits);
5926 This->xHotSpot = XHotSpot;
5927 This->yHotSpot = YHotSpot;
5931 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5933 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5935 This->xScreenSpace = XScreenSpace;
5936 This->yScreenSpace = YScreenSpace;
5942 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5944 BOOL oldVisible = This->bCursorVisible;
5947 TRACE("(%p) : visible(%d)\n", This, bShow);
5950 * When ShowCursor is first called it should make the cursor appear at the OS's last
5951 * known cursor position. Because of this, some applications just repetitively call
5952 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5955 This->xScreenSpace = pt.x;
5956 This->yScreenSpace = pt.y;
5958 if (This->haveHardwareCursor) {
5959 This->bCursorVisible = bShow;
5961 SetCursor(This->hardwareCursor);
5967 if (This->cursorTexture)
5968 This->bCursorVisible = bShow;
5974 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5975 TRACE("checking resource %p for eviction\n", resource);
5976 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5977 TRACE("Evicting %p\n", resource);
5978 IWineD3DResource_UnLoad(resource);
5980 IWineD3DResource_Release(resource);
5984 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5986 TRACE("iface %p.\n", iface);
5988 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5989 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5990 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
5995 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
5997 IWineD3DDeviceImpl *device = surface->resource.device;
5998 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6000 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6001 if(surface->Flags & SFLAG_DIBSECTION) {
6002 /* Release the DC */
6003 SelectObject(surface->hDC, surface->dib.holdbitmap);
6004 DeleteDC(surface->hDC);
6005 /* Release the DIB section */
6006 DeleteObject(surface->dib.DIBsection);
6007 surface->dib.bitmap_data = NULL;
6008 surface->resource.allocatedMemory = NULL;
6009 surface->Flags &= ~SFLAG_DIBSECTION;
6011 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6012 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6013 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6014 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6016 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6017 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6019 surface->pow2Width = surface->pow2Height = 1;
6020 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6021 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6024 if (surface->texture_name)
6026 struct wined3d_context *context = context_acquire(device, NULL);
6028 glDeleteTextures(1, &surface->texture_name);
6030 context_release(context);
6031 surface->texture_name = 0;
6032 surface->Flags &= ~SFLAG_CLIENT;
6034 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6035 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6036 surface->Flags |= SFLAG_NONPOW2;
6038 surface->Flags &= ~SFLAG_NONPOW2;
6040 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6041 surface->resource.allocatedMemory = NULL;
6042 surface->resource.heapMemory = NULL;
6043 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6045 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6047 if (!surface_init_sysmem(surface))
6049 return E_OUTOFMEMORY;
6054 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6055 TRACE("Unloading resource %p\n", resource);
6056 IWineD3DResource_UnLoad(resource);
6057 IWineD3DResource_Release(resource);
6061 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6064 WINED3DDISPLAYMODE m;
6067 /* All Windowed modes are supported, as is leaving the current mode */
6068 if(pp->Windowed) return TRUE;
6069 if(!pp->BackBufferWidth) return TRUE;
6070 if(!pp->BackBufferHeight) return TRUE;
6072 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6073 for(i = 0; i < count; i++) {
6074 memset(&m, 0, sizeof(m));
6075 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6077 ERR("EnumAdapterModes failed\n");
6079 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6080 /* Mode found, it is supported */
6084 /* Mode not found -> not supported */
6088 /* Do not call while under the GL lock. */
6089 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6092 const struct wined3d_gl_info *gl_info;
6093 struct wined3d_context *context;
6094 IWineD3DBaseShaderImpl *shader;
6096 context = context_acquire(This, NULL);
6097 gl_info = context->gl_info;
6099 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6100 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6101 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6105 if(This->depth_blt_texture) {
6106 glDeleteTextures(1, &This->depth_blt_texture);
6107 This->depth_blt_texture = 0;
6109 if (This->depth_blt_rb) {
6110 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6111 This->depth_blt_rb = 0;
6112 This->depth_blt_rb_w = 0;
6113 This->depth_blt_rb_h = 0;
6117 This->blitter->free_private(iface);
6118 This->frag_pipe->free_private(iface);
6119 This->shader_backend->shader_free_private(iface);
6120 destroy_dummy_textures(This, gl_info);
6122 context_release(context);
6124 while (This->numContexts)
6126 context_destroy(This, This->contexts[0]);
6128 HeapFree(GetProcessHeap(), 0, swapchain->context);
6129 swapchain->context = NULL;
6130 swapchain->num_contexts = 0;
6133 /* Do not call while under the GL lock. */
6134 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6137 struct wined3d_context *context;
6139 IWineD3DSurfaceImpl *target;
6141 /* Recreate the primary swapchain's context */
6142 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6143 if (!swapchain->context)
6145 ERR("Failed to allocate memory for swapchain context array.\n");
6146 return E_OUTOFMEMORY;
6149 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6150 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6152 WARN("Failed to create context.\n");
6153 HeapFree(GetProcessHeap(), 0, swapchain->context);
6157 swapchain->context[0] = context;
6158 swapchain->num_contexts = 1;
6159 create_dummy_textures(This);
6160 context_release(context);
6162 hr = This->shader_backend->shader_alloc_private(iface);
6165 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6169 hr = This->frag_pipe->alloc_private(iface);
6172 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6173 This->shader_backend->shader_free_private(iface);
6177 hr = This->blitter->alloc_private(iface);
6180 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6181 This->frag_pipe->free_private(iface);
6182 This->shader_backend->shader_free_private(iface);
6189 context_acquire(This, NULL);
6190 destroy_dummy_textures(This, context->gl_info);
6191 context_release(context);
6192 context_destroy(This, context);
6193 HeapFree(GetProcessHeap(), 0, swapchain->context);
6194 swapchain->num_contexts = 0;
6198 /* Do not call while under the GL lock. */
6199 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6200 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 IWineD3DSwapChainImpl *swapchain;
6205 BOOL DisplayModeChanged = FALSE;
6206 WINED3DDISPLAYMODE mode;
6207 TRACE("(%p)\n", This);
6209 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6211 ERR("Failed to get the first implicit swapchain\n");
6215 if(!is_display_mode_supported(This, pPresentationParameters)) {
6216 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6217 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6218 pPresentationParameters->BackBufferHeight);
6219 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6220 return WINED3DERR_INVALIDCALL;
6223 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6224 * on an existing gl context, so there's no real need for recreation.
6226 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6228 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6230 TRACE("New params:\n");
6231 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6232 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6233 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6234 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6235 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6236 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6237 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6238 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6239 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6240 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6241 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6242 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6243 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6245 /* No special treatment of these parameters. Just store them */
6246 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6247 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6248 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6249 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6251 /* What to do about these? */
6252 if(pPresentationParameters->BackBufferCount != 0 &&
6253 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6254 ERR("Cannot change the back buffer count yet\n");
6256 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6257 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6258 ERR("Cannot change the back buffer format yet\n");
6260 if(pPresentationParameters->hDeviceWindow != NULL &&
6261 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6262 ERR("Cannot change the device window yet\n");
6264 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6268 TRACE("Creating the depth stencil buffer\n");
6270 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6271 pPresentationParameters->BackBufferWidth,
6272 pPresentationParameters->BackBufferHeight,
6273 pPresentationParameters->AutoDepthStencilFormat,
6274 pPresentationParameters->MultiSampleType,
6275 pPresentationParameters->MultiSampleQuality,
6277 (IWineD3DSurface **)&This->auto_depth_stencil);
6280 ERR("Failed to create the depth stencil buffer\n");
6281 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6282 return WINED3DERR_INVALIDCALL;
6286 if (This->onscreen_depth_stencil)
6288 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6289 This->onscreen_depth_stencil = NULL;
6292 /* Reset the depth stencil */
6293 if (pPresentationParameters->EnableAutoDepthStencil)
6294 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6296 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6298 TRACE("Resetting stateblock\n");
6299 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6300 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6302 delete_opengl_contexts(iface, swapchain);
6304 if(pPresentationParameters->Windowed) {
6305 mode.Width = swapchain->orig_width;
6306 mode.Height = swapchain->orig_height;
6307 mode.RefreshRate = 0;
6308 mode.Format = swapchain->presentParms.BackBufferFormat;
6310 mode.Width = pPresentationParameters->BackBufferWidth;
6311 mode.Height = pPresentationParameters->BackBufferHeight;
6312 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6313 mode.Format = swapchain->presentParms.BackBufferFormat;
6316 /* Should Width == 800 && Height == 0 set 800x600? */
6317 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6318 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6319 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6323 if(!pPresentationParameters->Windowed) {
6324 DisplayModeChanged = TRUE;
6326 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6327 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6329 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6332 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6336 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6338 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6341 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6345 if (This->auto_depth_stencil)
6347 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6350 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6356 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6357 || DisplayModeChanged)
6359 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6361 if (!pPresentationParameters->Windowed)
6363 if(swapchain->presentParms.Windowed) {
6364 /* switch from windowed to fs */
6365 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6366 pPresentationParameters->BackBufferHeight);
6368 /* Fullscreen -> fullscreen mode change */
6369 MoveWindow(swapchain->device_window, 0, 0,
6370 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6374 else if (!swapchain->presentParms.Windowed)
6376 /* Fullscreen -> windowed switch */
6377 swapchain_restore_fullscreen_window(swapchain);
6379 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6380 } else if(!pPresentationParameters->Windowed) {
6381 DWORD style = This->style, exStyle = This->exStyle;
6382 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6383 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6384 * Reset to clear up their mess. Guild Wars also loses the device during that.
6388 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6389 pPresentationParameters->BackBufferHeight);
6390 This->style = style;
6391 This->exStyle = exStyle;
6394 /* Note: No parent needed for initial internal stateblock */
6395 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6396 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6397 else TRACE("Created stateblock %p\n", This->stateBlock);
6398 This->updateStateBlock = This->stateBlock;
6399 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6401 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6403 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6406 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6409 GetClientRect(swapchain->win_handle, &client_rect);
6411 if(!swapchain->presentParms.BackBufferCount)
6413 TRACE("Single buffered rendering\n");
6414 swapchain->render_to_fbo = FALSE;
6416 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6417 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6419 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6420 swapchain->presentParms.BackBufferWidth,
6421 swapchain->presentParms.BackBufferHeight,
6422 client_rect.right, client_rect.bottom);
6423 swapchain->render_to_fbo = TRUE;
6427 TRACE("Rendering directly to GL_BACK\n");
6428 swapchain->render_to_fbo = FALSE;
6432 hr = create_primary_opengl_context(iface, swapchain);
6433 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6435 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6441 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6443 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6445 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6451 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6453 TRACE("(%p) : pParameters %p\n", This, pParameters);
6455 *pParameters = This->createParms;
6459 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6460 IWineD3DSwapChain *swapchain;
6462 TRACE("Relaying to swapchain\n");
6464 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6465 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6466 IWineD3DSwapChain_Release(swapchain);
6470 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6471 IWineD3DSwapChain *swapchain;
6473 TRACE("Relaying to swapchain\n");
6475 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6476 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6477 IWineD3DSwapChain_Release(swapchain);
6482 /** ********************************************************
6483 * Notification functions
6484 ** ********************************************************/
6485 /** This function must be called in the release of a resource when ref == 0,
6486 * the contents of resource must still be correct,
6487 * any handles to other resource held by the caller must be closed
6488 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6489 *****************************************************/
6490 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6492 TRACE("(%p) : Adding resource %p\n", This, resource);
6494 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6497 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6499 TRACE("(%p) : Removing resource %p\n", This, resource);
6501 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6504 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6506 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6509 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6511 context_resource_released(device, resource, type);
6515 case WINED3DRTYPE_SURFACE:
6516 if (!device->d3d_initialized) break;
6518 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6520 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6522 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6523 device->render_targets[i] = NULL;
6527 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6529 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6530 device->depth_stencil = NULL;
6534 case WINED3DRTYPE_TEXTURE:
6535 case WINED3DRTYPE_CUBETEXTURE:
6536 case WINED3DRTYPE_VOLUMETEXTURE:
6537 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6539 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6541 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6542 resource, device->stateBlock, i);
6543 device->stateBlock->textures[i] = NULL;
6546 if (device->updateStateBlock != device->stateBlock
6547 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6549 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6550 resource, device->updateStateBlock, i);
6551 device->updateStateBlock->textures[i] = NULL;
6556 case WINED3DRTYPE_BUFFER:
6557 for (i = 0; i < MAX_STREAMS; ++i)
6559 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6561 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6562 resource, device->stateBlock, i);
6563 device->stateBlock->streamSource[i] = NULL;
6566 if (device->updateStateBlock != device->stateBlock
6567 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6569 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6570 resource, device->updateStateBlock, i);
6571 device->updateStateBlock->streamSource[i] = NULL;
6576 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6578 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6579 resource, device->stateBlock);
6580 device->stateBlock->pIndexData = NULL;
6583 if (device->updateStateBlock != device->stateBlock
6584 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6586 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6587 resource, device->updateStateBlock);
6588 device->updateStateBlock->pIndexData = NULL;
6596 /* Remove the resource from the resourceStore */
6597 device_resource_remove(device, resource);
6599 TRACE("Resource released.\n");
6602 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6604 IWineD3DResourceImpl *resource, *cursor;
6606 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6608 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6609 TRACE("enumerating resource %p\n", resource);
6610 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6611 ret = pCallback((IWineD3DResource *) resource, pData);
6612 if(ret == S_FALSE) {
6613 TRACE("Canceling enumeration\n");
6620 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6623 IWineD3DResourceImpl *resource;
6625 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6627 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6628 if (type == WINED3DRTYPE_SURFACE)
6630 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6632 TRACE("Found surface %p for dc %p.\n", resource, dc);
6633 *surface = (IWineD3DSurface *)resource;
6639 return WINED3DERR_INVALIDCALL;
6642 /**********************************************************
6643 * IWineD3DDevice VTbl follows
6644 **********************************************************/
6646 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6648 /*** IUnknown methods ***/
6649 IWineD3DDeviceImpl_QueryInterface,
6650 IWineD3DDeviceImpl_AddRef,
6651 IWineD3DDeviceImpl_Release,
6652 /*** IWineD3DDevice methods ***/
6653 /*** Creation methods**/
6654 IWineD3DDeviceImpl_CreateBuffer,
6655 IWineD3DDeviceImpl_CreateVertexBuffer,
6656 IWineD3DDeviceImpl_CreateIndexBuffer,
6657 IWineD3DDeviceImpl_CreateStateBlock,
6658 IWineD3DDeviceImpl_CreateSurface,
6659 IWineD3DDeviceImpl_CreateRendertargetView,
6660 IWineD3DDeviceImpl_CreateTexture,
6661 IWineD3DDeviceImpl_CreateVolumeTexture,
6662 IWineD3DDeviceImpl_CreateVolume,
6663 IWineD3DDeviceImpl_CreateCubeTexture,
6664 IWineD3DDeviceImpl_CreateQuery,
6665 IWineD3DDeviceImpl_CreateSwapChain,
6666 IWineD3DDeviceImpl_CreateVertexDeclaration,
6667 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6668 IWineD3DDeviceImpl_CreateVertexShader,
6669 IWineD3DDeviceImpl_CreateGeometryShader,
6670 IWineD3DDeviceImpl_CreatePixelShader,
6671 IWineD3DDeviceImpl_CreatePalette,
6672 /*** Odd functions **/
6673 IWineD3DDeviceImpl_Init3D,
6674 IWineD3DDeviceImpl_InitGDI,
6675 IWineD3DDeviceImpl_Uninit3D,
6676 IWineD3DDeviceImpl_UninitGDI,
6677 IWineD3DDeviceImpl_SetMultithreaded,
6678 IWineD3DDeviceImpl_EvictManagedResources,
6679 IWineD3DDeviceImpl_GetAvailableTextureMem,
6680 IWineD3DDeviceImpl_GetBackBuffer,
6681 IWineD3DDeviceImpl_GetCreationParameters,
6682 IWineD3DDeviceImpl_GetDeviceCaps,
6683 IWineD3DDeviceImpl_GetDirect3D,
6684 IWineD3DDeviceImpl_GetDisplayMode,
6685 IWineD3DDeviceImpl_SetDisplayMode,
6686 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6687 IWineD3DDeviceImpl_GetRasterStatus,
6688 IWineD3DDeviceImpl_GetSwapChain,
6689 IWineD3DDeviceImpl_Reset,
6690 IWineD3DDeviceImpl_SetDialogBoxMode,
6691 IWineD3DDeviceImpl_SetCursorProperties,
6692 IWineD3DDeviceImpl_SetCursorPosition,
6693 IWineD3DDeviceImpl_ShowCursor,
6694 /*** Getters and setters **/
6695 IWineD3DDeviceImpl_SetClipPlane,
6696 IWineD3DDeviceImpl_GetClipPlane,
6697 IWineD3DDeviceImpl_SetClipStatus,
6698 IWineD3DDeviceImpl_GetClipStatus,
6699 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6700 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6701 IWineD3DDeviceImpl_SetDepthStencilSurface,
6702 IWineD3DDeviceImpl_GetDepthStencilSurface,
6703 IWineD3DDeviceImpl_SetGammaRamp,
6704 IWineD3DDeviceImpl_GetGammaRamp,
6705 IWineD3DDeviceImpl_SetIndexBuffer,
6706 IWineD3DDeviceImpl_GetIndexBuffer,
6707 IWineD3DDeviceImpl_SetBaseVertexIndex,
6708 IWineD3DDeviceImpl_GetBaseVertexIndex,
6709 IWineD3DDeviceImpl_SetLight,
6710 IWineD3DDeviceImpl_GetLight,
6711 IWineD3DDeviceImpl_SetLightEnable,
6712 IWineD3DDeviceImpl_GetLightEnable,
6713 IWineD3DDeviceImpl_SetMaterial,
6714 IWineD3DDeviceImpl_GetMaterial,
6715 IWineD3DDeviceImpl_SetNPatchMode,
6716 IWineD3DDeviceImpl_GetNPatchMode,
6717 IWineD3DDeviceImpl_SetPaletteEntries,
6718 IWineD3DDeviceImpl_GetPaletteEntries,
6719 IWineD3DDeviceImpl_SetPixelShader,
6720 IWineD3DDeviceImpl_GetPixelShader,
6721 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6722 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6723 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6724 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6725 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6726 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6727 IWineD3DDeviceImpl_SetRenderState,
6728 IWineD3DDeviceImpl_GetRenderState,
6729 IWineD3DDeviceImpl_SetRenderTarget,
6730 IWineD3DDeviceImpl_GetRenderTarget,
6731 IWineD3DDeviceImpl_SetFrontBackBuffers,
6732 IWineD3DDeviceImpl_SetSamplerState,
6733 IWineD3DDeviceImpl_GetSamplerState,
6734 IWineD3DDeviceImpl_SetScissorRect,
6735 IWineD3DDeviceImpl_GetScissorRect,
6736 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6737 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6738 IWineD3DDeviceImpl_SetStreamSource,
6739 IWineD3DDeviceImpl_GetStreamSource,
6740 IWineD3DDeviceImpl_SetStreamSourceFreq,
6741 IWineD3DDeviceImpl_GetStreamSourceFreq,
6742 IWineD3DDeviceImpl_SetTexture,
6743 IWineD3DDeviceImpl_GetTexture,
6744 IWineD3DDeviceImpl_SetTextureStageState,
6745 IWineD3DDeviceImpl_GetTextureStageState,
6746 IWineD3DDeviceImpl_SetTransform,
6747 IWineD3DDeviceImpl_GetTransform,
6748 IWineD3DDeviceImpl_SetVertexDeclaration,
6749 IWineD3DDeviceImpl_GetVertexDeclaration,
6750 IWineD3DDeviceImpl_SetVertexShader,
6751 IWineD3DDeviceImpl_GetVertexShader,
6752 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6753 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6754 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6755 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6756 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6757 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6758 IWineD3DDeviceImpl_SetViewport,
6759 IWineD3DDeviceImpl_GetViewport,
6760 IWineD3DDeviceImpl_MultiplyTransform,
6761 IWineD3DDeviceImpl_ValidateDevice,
6762 IWineD3DDeviceImpl_ProcessVertices,
6763 /*** State block ***/
6764 IWineD3DDeviceImpl_BeginStateBlock,
6765 IWineD3DDeviceImpl_EndStateBlock,
6766 /*** Scene management ***/
6767 IWineD3DDeviceImpl_BeginScene,
6768 IWineD3DDeviceImpl_EndScene,
6769 IWineD3DDeviceImpl_Present,
6770 IWineD3DDeviceImpl_Clear,
6771 IWineD3DDeviceImpl_ClearRendertargetView,
6773 IWineD3DDeviceImpl_SetPrimitiveType,
6774 IWineD3DDeviceImpl_GetPrimitiveType,
6775 IWineD3DDeviceImpl_DrawPrimitive,
6776 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6777 IWineD3DDeviceImpl_DrawPrimitiveUP,
6778 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6779 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6780 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6781 IWineD3DDeviceImpl_DrawRectPatch,
6782 IWineD3DDeviceImpl_DrawTriPatch,
6783 IWineD3DDeviceImpl_DeletePatch,
6784 IWineD3DDeviceImpl_ColorFill,
6785 IWineD3DDeviceImpl_UpdateTexture,
6786 IWineD3DDeviceImpl_UpdateSurface,
6787 IWineD3DDeviceImpl_GetFrontBufferData,
6788 /*** object tracking ***/
6789 IWineD3DDeviceImpl_EnumResources,
6790 IWineD3DDeviceImpl_GetSurfaceFromDC,
6791 IWineD3DDeviceImpl_AcquireFocusWindow,
6792 IWineD3DDeviceImpl_ReleaseFocusWindow,
6795 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6796 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6797 IWineD3DDeviceParent *device_parent)
6799 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6800 const struct fragment_pipeline *fragment_pipeline;
6801 struct shader_caps shader_caps;
6802 struct fragment_caps ffp_caps;
6803 WINED3DDISPLAYMODE mode;
6807 device->lpVtbl = &IWineD3DDevice_Vtbl;
6809 device->wined3d = (IWineD3D *)wined3d;
6810 IWineD3D_AddRef(device->wined3d);
6811 device->adapter = wined3d->adapter_count ? adapter : NULL;
6812 device->device_parent = device_parent;
6813 list_init(&device->resources);
6814 list_init(&device->shaders);
6816 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6817 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6819 /* Get the initial screen setup for ddraw. */
6820 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6823 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6824 IWineD3D_Release(device->wined3d);
6827 device->ddraw_width = mode.Width;
6828 device->ddraw_height = mode.Height;
6829 device->ddraw_format = mode.Format;
6831 /* Save the creation parameters. */
6832 device->createParms.AdapterOrdinal = adapter_idx;
6833 device->createParms.DeviceType = device_type;
6834 device->createParms.hFocusWindow = focus_window;
6835 device->createParms.BehaviorFlags = flags;
6837 device->devType = device_type;
6838 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6840 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6841 device->shader_backend = adapter->shader_backend;
6843 if (device->shader_backend)
6845 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6846 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6847 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6848 device->vs_clipping = shader_caps.VSClipping;
6850 fragment_pipeline = adapter->fragment_pipe;
6851 device->frag_pipe = fragment_pipeline;
6852 if (fragment_pipeline)
6854 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6855 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6857 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6858 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6861 ERR("Failed to compile state table, hr %#x.\n", hr);
6862 IWineD3D_Release(device->wined3d);
6866 device->blitter = adapter->blitter;
6872 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6873 DWORD rep = This->StateTable[state].representative;
6874 struct wined3d_context *context;
6879 for(i = 0; i < This->numContexts; i++) {
6880 context = This->contexts[i];
6881 if(isStateDirty(context, rep)) continue;
6883 context->dirtyArray[context->numDirtyEntries++] = rep;
6884 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6885 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6886 context->isStateDirty[idx] |= (1 << shift);
6890 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6892 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6893 *width = context->current_rt->pow2Width;
6894 *height = context->current_rt->pow2Height;
6897 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6899 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6900 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6901 * current context's drawable, which is the size of the back buffer of the swapchain
6902 * the active context belongs to. */
6903 *width = swapchain->presentParms.BackBufferWidth;
6904 *height = swapchain->presentParms.BackBufferHeight;
6907 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6908 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6910 if (device->filter_messages)
6912 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6913 window, message, wparam, lparam);
6914 return DefWindowProcW(window, message, wparam, lparam);
6917 if (message == WM_DESTROY)
6919 TRACE("unregister window %p.\n", window);
6920 wined3d_unregister_window(window);
6922 if (device->focus_window == window) device->focus_window = NULL;
6923 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6926 return CallWindowProcW(proc, window, message, wparam, lparam);