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 /* Do not call while under the GL lock. */
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
597 /* partial draw rect */
598 if (draw_rect->left || draw_rect->top
599 || draw_rect->right < target->currentDesc.Width
600 || draw_rect->bottom < target->currentDesc.Height)
603 /* partial clear rect */
604 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
605 || clear_rect->right < target->currentDesc.Width
606 || clear_rect->bottom < target->currentDesc.Height))
612 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
613 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
615 RECT current_rect, r;
617 if (ds->Flags & location)
618 SetRect(¤t_rect, 0, 0,
619 ds->ds_current_size.cx,
620 ds->ds_current_size.cy);
622 SetRectEmpty(¤t_rect);
624 IntersectRect(&r, draw_rect, ¤t_rect);
625 if (EqualRect(&r, draw_rect))
627 /* current_rect ⊇ draw_rect, modify only. */
628 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
632 if (EqualRect(&r, ¤t_rect))
634 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
638 /* Full clear, modify only. */
639 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 IntersectRect(&r, draw_rect, clear_rect);
644 if (EqualRect(&r, draw_rect))
646 /* clear_rect ⊇ draw_rect, modify only. */
647 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
653 surface_load_ds_location(ds, context, location);
654 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
657 /* Do not call while under the GL lock. */
658 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
659 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
660 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
662 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
663 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
664 IWineD3DSurfaceImpl *target = rts[0];
665 UINT drawable_width, drawable_height;
666 struct wined3d_context *context;
667 GLbitfield clear_mask = 0;
670 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
671 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
672 * for the cleared parts, and the untouched parts.
674 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
675 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
676 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
677 * checking all this if the dest surface is in the drawable anyway. */
678 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
680 for (i = 0; i < rt_count; ++i)
682 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
686 context = context_acquire(device, target);
689 context_release(context);
690 WARN("Invalid context, skipping clear.\n");
694 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
696 target->get_drawable_size(context, &drawable_width, &drawable_height);
700 /* Only set the values up once, as they are not changing. */
701 if (flags & WINED3DCLEAR_STENCIL)
703 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
706 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
710 glClearStencil(stencil);
711 checkGLcall("glClearStencil");
712 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
715 if (flags & WINED3DCLEAR_ZBUFFER)
717 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
719 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
722 device_switch_onscreen_ds(device, context, depth_stencil);
725 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
726 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
728 glDepthMask(GL_TRUE);
729 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
731 checkGLcall("glClearDepth");
732 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
735 if (flags & WINED3DCLEAR_TARGET)
737 for (i = 0; i < rt_count; ++i)
739 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
742 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
744 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
745 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
746 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
747 glClearColor(color->r, color->g, color->b, color->a);
748 checkGLcall("glClearColor");
749 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
754 if (context->render_offscreen)
756 glScissor(draw_rect->left, draw_rect->top,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
761 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
762 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i = 0; i < rect_count; ++i)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
779 wine_dbgstr_rect(&clear_rect[i]),
780 wine_dbgstr_rect(¤t_rect));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context->render_offscreen)
793 glScissor(current_rect.left, current_rect.top,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 glScissor(current_rect.left, drawable_height - current_rect.bottom,
799 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
811 && target->container.u.swapchain->front_buffer == target))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
826 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
828 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
829 || IsEqualGUID(riid, &IID_IUnknown))
831 IUnknown_AddRef(iface);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
839 return E_NOINTERFACE;
842 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
844 ULONG refCount = InterlockedIncrement(&This->ref);
846 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
850 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 ULONG refCount = InterlockedDecrement(&This->ref);
854 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
859 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
860 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
861 This->multistate_funcs[i] = NULL;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This->resources))
870 IWineD3DResourceImpl *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
875 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource, debug_d3dresourcetype(type), type);
881 if(This->contexts) ERR("Context array not freed!\n");
882 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
883 This->haveHardwareCursor = FALSE;
885 IWineD3D_Release(This->wined3d);
886 This->wined3d = NULL;
887 HeapFree(GetProcessHeap(), 0, This);
888 TRACE("Freed device %p\n", This);
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
895 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 struct wined3d_buffer *object;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY;
910 FIXME("Ignoring access flags (pool)\n");
912 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
913 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
916 WARN("Failed to initialize buffer, hr %#x.\n", hr);
917 HeapFree(GetProcessHeap(), 0, object);
920 object->desc = *desc;
922 TRACE("Created buffer %p.\n", object);
924 *buffer = (IWineD3DBuffer *)object;
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
930 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
931 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 struct wined3d_buffer *object;
937 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
938 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
940 if (Pool == WINED3DPOOL_SCRATCH)
942 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
943 * anyway, SCRATCH vertex buffers aren't usable anywhere
945 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 *ppVertexBuffer = NULL;
947 return WINED3DERR_INVALIDCALL;
950 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
953 ERR("Out of memory\n");
954 *ppVertexBuffer = NULL;
955 return WINED3DERR_OUTOFVIDEOMEMORY;
958 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
959 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
962 WARN("Failed to initialize buffer, hr %#x.\n", hr);
963 HeapFree(GetProcessHeap(), 0, object);
967 TRACE("Created buffer %p.\n", object);
968 *ppVertexBuffer = (IWineD3DBuffer *)object;
973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
974 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
975 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
978 struct wined3d_buffer *object;
981 TRACE("(%p) Creating index buffer\n", This);
983 /* Allocate the storage for the device */
984 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
987 ERR("Out of memory\n");
988 *ppIndexBuffer = NULL;
989 return WINED3DERR_OUTOFVIDEOMEMORY;
992 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
993 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
997 WARN("Failed to initialize buffer, hr %#x\n", hr);
998 HeapFree(GetProcessHeap(), 0, object);
1002 TRACE("Created buffer %p.\n", object);
1004 *ppIndexBuffer = (IWineD3DBuffer *) object;
1009 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1010 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 IWineD3DStateBlockImpl *object;
1016 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1019 ERR("Failed to allocate stateblock memory.\n");
1020 return E_OUTOFMEMORY;
1023 hr = stateblock_init(object, This, type);
1026 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1027 HeapFree(GetProcessHeap(), 0, object);
1031 TRACE("Created stateblock %p.\n", object);
1032 *stateblock = (IWineD3DStateBlock *)object;
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1038 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1039 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1040 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1043 IWineD3DSurfaceImpl *object;
1046 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1047 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1048 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1049 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1050 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1052 if (Impl == SURFACE_OPENGL && !This->adapter)
1054 ERR("OpenGL surfaces are not available without OpenGL.\n");
1055 return WINED3DERR_NOTAVAILABLE;
1058 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1061 ERR("Failed to allocate surface memory.\n");
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1066 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1069 WARN("Failed to initialize surface, returning %#x.\n", hr);
1070 HeapFree(GetProcessHeap(), 0, object);
1074 TRACE("(%p) : Created surface %p\n", This, object);
1076 *surface = (IWineD3DSurface *)object;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1082 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1084 struct wined3d_rendertarget_view *object;
1086 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1087 iface, resource, parent, rendertarget_view);
1089 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1092 ERR("Failed to allocate memory\n");
1093 return E_OUTOFMEMORY;
1096 wined3d_rendertarget_view_init(object, resource, parent);
1098 TRACE("Created render target view %p.\n", object);
1099 *rendertarget_view = (IWineD3DRendertargetView *)object;
1104 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1105 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1106 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1112 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1113 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1114 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1116 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1119 ERR("Out of memory\n");
1121 return WINED3DERR_OUTOFVIDEOMEMORY;
1124 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1127 WARN("Failed to initialize texture, returning %#x\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1133 *ppTexture = (IWineD3DTexture *)object;
1135 TRACE("(%p) : Created texture %p\n", This, object);
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1141 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1142 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DVolumeTextureImpl *object;
1148 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1149 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1151 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1154 ERR("Out of memory\n");
1155 *ppVolumeTexture = NULL;
1156 return WINED3DERR_OUTOFVIDEOMEMORY;
1159 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1162 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1163 HeapFree(GetProcessHeap(), 0, object);
1164 *ppVolumeTexture = NULL;
1168 TRACE("(%p) : Created volume texture %p.\n", This, object);
1169 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1175 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1176 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 IWineD3DVolumeImpl *object;
1182 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1183 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1185 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1188 ERR("Out of memory\n");
1190 return WINED3DERR_OUTOFVIDEOMEMORY;
1193 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1196 WARN("Failed to initialize volume, returning %#x.\n", hr);
1197 HeapFree(GetProcessHeap(), 0, object);
1201 TRACE("(%p) : Created volume %p.\n", This, object);
1202 *ppVolume = (IWineD3DVolume *)object;
1207 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1208 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1209 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1212 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1215 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1218 ERR("Out of memory\n");
1219 *ppCubeTexture = NULL;
1220 return WINED3DERR_OUTOFVIDEOMEMORY;
1223 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1226 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1227 HeapFree(GetProcessHeap(), 0, object);
1228 *ppCubeTexture = NULL;
1232 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1233 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1239 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1242 IWineD3DQueryImpl *object;
1245 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1247 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1250 ERR("Failed to allocate query memory.\n");
1251 return E_OUTOFMEMORY;
1254 hr = query_init(object, This, type);
1257 WARN("Failed to initialize query, hr %#x.\n", hr);
1258 HeapFree(GetProcessHeap(), 0, object);
1262 TRACE("Created query %p.\n", object);
1263 *query = (IWineD3DQuery *)object;
1268 /* Do not call while under the GL lock. */
1269 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1270 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1271 void *parent, IWineD3DSwapChain **swapchain)
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DSwapChainImpl *object;
1277 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1278 iface, present_parameters, swapchain, parent, surface_type);
1280 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1283 ERR("Failed to allocate swapchain memory.\n");
1284 return E_OUTOFMEMORY;
1287 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1290 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1291 HeapFree(GetProcessHeap(), 0, object);
1295 TRACE("Created swapchain %p.\n", object);
1296 *swapchain = (IWineD3DSwapChain *)object;
1301 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1302 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 TRACE("(%p)\n", This);
1306 return This->NumberOfSwapChains;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1311 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1313 if(iSwapChain < This->NumberOfSwapChains) {
1314 *pSwapChain = This->swapchains[iSwapChain];
1315 IWineD3DSwapChain_AddRef(*pSwapChain);
1316 TRACE("(%p) returning %p\n", This, *pSwapChain);
1319 TRACE("Swapchain out of range\n");
1321 return WINED3DERR_INVALIDCALL;
1325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1326 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1327 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1330 IWineD3DVertexDeclarationImpl *object = NULL;
1333 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1334 iface, declaration, parent, elements, element_count);
1336 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1339 ERR("Failed to allocate vertex declaration memory.\n");
1340 return E_OUTOFMEMORY;
1343 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1346 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1347 HeapFree(GetProcessHeap(), 0, object);
1351 TRACE("Created vertex declaration %p.\n", object);
1352 *declaration = (IWineD3DVertexDeclaration *)object;
1357 struct wined3d_fvf_convert_state
1359 const struct wined3d_gl_info *gl_info;
1360 WINED3DVERTEXELEMENT *elements;
1365 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1366 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1368 WINED3DVERTEXELEMENT *elements = state->elements;
1369 const struct wined3d_format *format;
1370 UINT offset = state->offset;
1371 UINT idx = state->idx;
1373 elements[idx].format = format_id;
1374 elements[idx].input_slot = 0;
1375 elements[idx].offset = offset;
1376 elements[idx].output_slot = 0;
1377 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1378 elements[idx].usage = usage;
1379 elements[idx].usage_idx = usage_idx;
1381 format = wined3d_get_format(state->gl_info, format_id);
1382 state->offset += format->component_count * format->component_size;
1386 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1387 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1389 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1390 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1391 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1392 BOOL has_blend_idx = has_blend &&
1393 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1394 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1395 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1396 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1397 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1398 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1399 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1401 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1402 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1403 struct wined3d_fvf_convert_state state;
1406 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1407 if (has_blend_idx) num_blends--;
1409 /* Compute declaration size */
1410 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1411 has_psize + has_diffuse + has_specular + num_textures;
1413 state.gl_info = gl_info;
1414 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1415 if (!state.elements) return ~0U;
1421 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1422 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1423 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1424 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1426 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1429 if (has_blend && (num_blends > 0))
1431 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1432 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1447 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1450 ERR("Unexpected amount of blend values: %u\n", num_blends);
1457 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1458 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1459 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1460 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1461 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1463 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1466 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1467 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1468 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1469 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1471 for (idx = 0; idx < num_textures; ++idx)
1473 switch ((texcoords >> (idx * 2)) & 0x03)
1475 case WINED3DFVF_TEXTUREFORMAT1:
1476 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 case WINED3DFVF_TEXTUREFORMAT2:
1479 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 case WINED3DFVF_TEXTUREFORMAT3:
1482 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1484 case WINED3DFVF_TEXTUREFORMAT4:
1485 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1490 *ppVertexElements = state.elements;
1494 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1495 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1496 IWineD3DVertexDeclaration **declaration)
1498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1499 WINED3DVERTEXELEMENT *elements;
1503 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1505 size = ConvertFvfToDeclaration(This, fvf, &elements);
1506 if (size == ~0U) return E_OUTOFMEMORY;
1508 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1509 HeapFree(GetProcessHeap(), 0, elements);
1513 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1514 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1515 void *parent, const struct wined3d_parent_ops *parent_ops,
1516 IWineD3DVertexShader **ppVertexShader)
1518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1519 IWineD3DVertexShaderImpl *object;
1522 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1525 ERR("Failed to allocate shader memory.\n");
1526 return E_OUTOFMEMORY;
1529 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1532 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1533 HeapFree(GetProcessHeap(), 0, object);
1537 TRACE("Created vertex shader %p.\n", object);
1538 *ppVertexShader = (IWineD3DVertexShader *)object;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1544 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1545 void *parent, const struct wined3d_parent_ops *parent_ops,
1546 IWineD3DGeometryShader **shader)
1548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1549 struct wined3d_geometryshader *object;
1552 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1555 ERR("Failed to allocate shader memory.\n");
1556 return E_OUTOFMEMORY;
1559 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1562 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1563 HeapFree(GetProcessHeap(), 0, object);
1567 TRACE("Created geometry shader %p.\n", object);
1568 *shader = (IWineD3DGeometryShader *)object;
1573 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1574 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1575 void *parent, const struct wined3d_parent_ops *parent_ops,
1576 IWineD3DPixelShader **ppPixelShader)
1578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1579 IWineD3DPixelShaderImpl *object;
1582 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1585 ERR("Failed to allocate shader memory.\n");
1586 return E_OUTOFMEMORY;
1589 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1592 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1593 HeapFree(GetProcessHeap(), 0, object);
1597 TRACE("Created pixel shader %p.\n", object);
1598 *ppPixelShader = (IWineD3DPixelShader *)object;
1603 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1604 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1607 IWineD3DPaletteImpl *object;
1610 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1611 iface, Flags, PalEnt, Palette, parent);
1613 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1616 ERR("Failed to allocate palette memory.\n");
1617 return E_OUTOFMEMORY;
1620 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1623 WARN("Failed to initialize palette, hr %#x.\n", hr);
1624 HeapFree(GetProcessHeap(), 0, object);
1628 TRACE("Created palette %p.\n", object);
1629 *Palette = (IWineD3DPalette *)object;
1634 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1638 HDC dcb = NULL, dcs = NULL;
1639 WINEDDCOLORKEY colorkey;
1641 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1644 GetObjectA(hbm, sizeof(BITMAP), &bm);
1645 dcb = CreateCompatibleDC(NULL);
1647 SelectObject(dcb, hbm);
1651 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1652 * couldn't be loaded
1654 memset(&bm, 0, sizeof(bm));
1659 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1660 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1661 &wined3d_null_parent_ops, &This->logo_surface);
1664 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1669 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1670 if(FAILED(hr)) goto out;
1671 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1672 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1674 colorkey.dwColorSpaceLowValue = 0;
1675 colorkey.dwColorSpaceHighValue = 0;
1676 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1680 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1681 /* Fill the surface with a white color to show that wined3d is there */
1682 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1686 if (dcb) DeleteDC(dcb);
1687 if (hbm) DeleteObject(hbm);
1690 /* Context activation is done by the caller. */
1691 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1693 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1695 /* Under DirectX you can have texture stage operations even if no texture is
1696 bound, whereas opengl will only do texture operations when a valid texture is
1697 bound. We emulate this by creating dummy textures and binding them to each
1698 texture stage, but disable all stages by default. Hence if a stage is enabled
1699 then the default texture will kick in until replaced by a SetTexture call */
1702 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1704 /* The dummy texture does not have client storage backing */
1705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1709 for (i = 0; i < gl_info->limits.textures; ++i)
1711 GLubyte white = 255;
1713 /* Make appropriate texture active */
1714 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1715 checkGLcall("glActiveTextureARB");
1717 /* Generate an opengl texture name */
1718 glGenTextures(1, &This->dummyTextureName[i]);
1719 checkGLcall("glGenTextures");
1720 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1722 /* Generate a dummy 2d texture (not using 1d because they cause many
1723 * DRI drivers fall back to sw) */
1724 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1725 checkGLcall("glBindTexture");
1727 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1728 checkGLcall("glTexImage2D");
1731 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1733 /* Reenable because if supported it is enabled by default */
1734 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1735 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1741 /* Context activation is done by the caller. */
1742 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1745 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1746 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1749 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1752 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1754 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1756 if (!wined3d_register_window(window, device))
1758 ERR("Failed to register window %p.\n", window);
1762 device->focus_window = window;
1763 SetForegroundWindow(window);
1768 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1770 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1772 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1773 device->focus_window = NULL;
1776 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1777 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1780 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1781 IWineD3DSwapChainImpl *swapchain = NULL;
1782 struct wined3d_context *context;
1787 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1789 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1790 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1792 TRACE("(%p) : Creating stateblock\n", This);
1793 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1796 WARN("Failed to create stateblock\n");
1799 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1800 This->updateStateBlock = This->stateBlock;
1801 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1803 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1804 sizeof(*This->render_targets) * gl_info->limits.buffers);
1806 This->NumberOfPalettes = 1;
1807 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1808 if (!This->palettes || !This->render_targets)
1810 ERR("Out of memory!\n");
1814 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1815 if(!This->palettes[0]) {
1816 ERR("Out of memory!\n");
1820 for (i = 0; i < 256; ++i) {
1821 This->palettes[0][i].peRed = 0xFF;
1822 This->palettes[0][i].peGreen = 0xFF;
1823 This->palettes[0][i].peBlue = 0xFF;
1824 This->palettes[0][i].peFlags = 0xFF;
1826 This->currentPalette = 0;
1828 /* Initialize the texture unit mapping to a 1:1 mapping */
1829 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1831 if (state < gl_info->limits.fragment_samplers)
1833 This->texUnitMap[state] = state;
1834 This->rev_tex_unit_map[state] = state;
1836 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1837 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1841 /* Setup the implicit swapchain. This also initializes a context. */
1842 TRACE("Creating implicit swapchain\n");
1843 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1844 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1847 WARN("Failed to create implicit swapchain\n");
1851 This->NumberOfSwapChains = 1;
1852 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1853 if(!This->swapchains) {
1854 ERR("Out of memory!\n");
1857 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1859 if (swapchain->back_buffers && swapchain->back_buffers[0])
1861 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1862 This->render_targets[0] = swapchain->back_buffers[0];
1866 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1867 This->render_targets[0] = swapchain->front_buffer;
1869 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1871 /* Depth Stencil support */
1872 This->depth_stencil = This->auto_depth_stencil;
1873 if (This->depth_stencil)
1874 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1876 hr = This->shader_backend->shader_alloc_private(iface);
1878 TRACE("Shader private data couldn't be allocated\n");
1881 hr = This->frag_pipe->alloc_private(iface);
1883 TRACE("Fragment pipeline private data couldn't be allocated\n");
1886 hr = This->blitter->alloc_private(iface);
1888 TRACE("Blitter private data couldn't be allocated\n");
1892 /* Set up some starting GL setup */
1894 /* Setup all the devices defaults */
1895 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1897 context = context_acquire(This, swapchain->front_buffer);
1899 create_dummy_textures(This);
1903 /* Initialize the current view state */
1904 This->view_ident = 1;
1905 This->contexts[0]->last_was_rhw = 0;
1906 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1907 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1909 switch(wined3d_settings.offscreen_rendering_mode) {
1911 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1914 case ORM_BACKBUFFER:
1916 if (context_get_current()->aux_buffers > 0)
1918 TRACE("Using auxilliary buffer for offscreen rendering\n");
1919 This->offscreenBuffer = GL_AUX0;
1921 TRACE("Using back buffer for offscreen rendering\n");
1922 This->offscreenBuffer = GL_BACK;
1927 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1930 context_release(context);
1932 /* Clear the screen */
1933 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1934 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1937 This->d3d_initialized = TRUE;
1939 if(wined3d_settings.logo) {
1940 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1942 This->highest_dirty_ps_const = 0;
1943 This->highest_dirty_vs_const = 0;
1947 HeapFree(GetProcessHeap(), 0, This->render_targets);
1948 HeapFree(GetProcessHeap(), 0, This->swapchains);
1949 This->NumberOfSwapChains = 0;
1950 if(This->palettes) {
1951 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1952 HeapFree(GetProcessHeap(), 0, This->palettes);
1954 This->NumberOfPalettes = 0;
1956 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1958 if(This->stateBlock) {
1959 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1960 This->stateBlock = NULL;
1962 if (This->blit_priv) {
1963 This->blitter->free_private(iface);
1965 if (This->fragment_priv) {
1966 This->frag_pipe->free_private(iface);
1968 if (This->shader_priv) {
1969 This->shader_backend->shader_free_private(iface);
1974 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1975 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1978 IWineD3DSwapChainImpl *swapchain = NULL;
1981 /* Setup the implicit swapchain */
1982 TRACE("Creating implicit swapchain\n");
1983 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1984 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1987 WARN("Failed to create implicit swapchain\n");
1991 This->NumberOfSwapChains = 1;
1992 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1993 if(!This->swapchains) {
1994 ERR("Out of memory!\n");
1997 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2001 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2005 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2007 IWineD3DResource_UnLoad(resource);
2008 IWineD3DResource_Release(resource);
2012 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2013 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2016 const struct wined3d_gl_info *gl_info;
2017 struct wined3d_context *context;
2020 TRACE("(%p)\n", This);
2022 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2025 * it was created. Thus make sure a context is active for the glDelete* calls
2027 context = context_acquire(This, NULL);
2028 gl_info = context->gl_info;
2030 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2032 /* Unload resources */
2033 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2035 TRACE("Deleting high order patches\n");
2036 for(i = 0; i < PATCHMAP_SIZE; i++) {
2037 struct list *e1, *e2;
2038 struct WineD3DRectPatch *patch;
2039 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2040 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2041 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2045 /* Delete the mouse cursor texture */
2046 if(This->cursorTexture) {
2048 glDeleteTextures(1, &This->cursorTexture);
2050 This->cursorTexture = 0;
2053 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2054 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2056 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2057 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2060 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2061 * private data, it might contain opengl pointers
2063 if(This->depth_blt_texture) {
2065 glDeleteTextures(1, &This->depth_blt_texture);
2067 This->depth_blt_texture = 0;
2069 if (This->depth_blt_rb) {
2071 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2073 This->depth_blt_rb = 0;
2074 This->depth_blt_rb_w = 0;
2075 This->depth_blt_rb_h = 0;
2078 /* Release the update stateblock */
2079 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2080 if(This->updateStateBlock != This->stateBlock)
2081 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2083 This->updateStateBlock = NULL;
2085 { /* because were not doing proper internal refcounts releasing the primary state block
2086 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2087 to set this->stateBlock = NULL; first */
2088 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2089 This->stateBlock = NULL;
2091 /* Release the stateblock */
2092 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2093 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2097 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2098 This->blitter->free_private(iface);
2099 This->frag_pipe->free_private(iface);
2100 This->shader_backend->shader_free_private(iface);
2102 /* Release the buffers (with sanity checks)*/
2103 if (This->onscreen_depth_stencil)
2105 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2106 This->onscreen_depth_stencil = NULL;
2109 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2110 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2112 if (This->auto_depth_stencil != This->depth_stencil)
2113 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2115 This->depth_stencil = NULL;
2117 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2118 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2120 TRACE("Setting rendertarget to NULL\n");
2121 This->render_targets[0] = NULL;
2123 if (This->auto_depth_stencil)
2125 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2127 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2129 This->auto_depth_stencil = NULL;
2132 context_release(context);
2134 for(i=0; i < This->NumberOfSwapChains; i++) {
2135 TRACE("Releasing the implicit swapchain %d\n", i);
2136 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2137 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2141 HeapFree(GetProcessHeap(), 0, This->swapchains);
2142 This->swapchains = NULL;
2143 This->NumberOfSwapChains = 0;
2145 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2146 HeapFree(GetProcessHeap(), 0, This->palettes);
2147 This->palettes = NULL;
2148 This->NumberOfPalettes = 0;
2150 HeapFree(GetProcessHeap(), 0, This->render_targets);
2151 This->render_targets = NULL;
2153 This->d3d_initialized = FALSE;
2158 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2162 for(i=0; i < This->NumberOfSwapChains; i++) {
2163 TRACE("Releasing the implicit swapchain %d\n", i);
2164 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2165 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2169 HeapFree(GetProcessHeap(), 0, This->swapchains);
2170 This->swapchains = NULL;
2171 This->NumberOfSwapChains = 0;
2175 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2176 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2177 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2179 * There is no way to deactivate thread safety once it is enabled.
2181 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2184 /*For now just store the flag(needed in case of ddraw) */
2185 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2188 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2189 const WINED3DDISPLAYMODE* pMode) {
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2192 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2196 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2198 /* Resize the screen even without a window:
2199 * The app could have unset it with SetCooperativeLevel, but not called
2200 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2201 * but we don't have any hwnd
2204 memset(&devmode, 0, sizeof(devmode));
2205 devmode.dmSize = sizeof(devmode);
2206 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2207 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2208 devmode.dmPelsWidth = pMode->Width;
2209 devmode.dmPelsHeight = pMode->Height;
2211 devmode.dmDisplayFrequency = pMode->RefreshRate;
2212 if (pMode->RefreshRate != 0) {
2213 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2216 /* Only change the mode if necessary */
2217 if( (This->ddraw_width == pMode->Width) &&
2218 (This->ddraw_height == pMode->Height) &&
2219 (This->ddraw_format == pMode->Format) &&
2220 (pMode->RefreshRate == 0) ) {
2224 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2225 if (ret != DISP_CHANGE_SUCCESSFUL) {
2226 if(devmode.dmDisplayFrequency != 0) {
2227 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2228 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2229 devmode.dmDisplayFrequency = 0;
2230 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2232 if(ret != DISP_CHANGE_SUCCESSFUL) {
2233 return WINED3DERR_NOTAVAILABLE;
2237 /* Store the new values */
2238 This->ddraw_width = pMode->Width;
2239 This->ddraw_height = pMode->Height;
2240 This->ddraw_format = pMode->Format;
2242 /* And finally clip mouse to our screen */
2243 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2244 ClipCursor(&clip_rc);
2249 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 *ppD3D = This->wined3d;
2252 TRACE("Returning %p.\n", *ppD3D);
2253 IWineD3D_AddRef(*ppD3D);
2257 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2261 (This->adapter->TextureRam/(1024*1024)),
2262 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2263 /* return simulated texture memory left */
2264 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2268 * Get / Set Stream Source
2270 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2271 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 IWineD3DBuffer *oldSrc;
2276 if (StreamNumber >= MAX_STREAMS) {
2277 WARN("Stream out of range %d\n", StreamNumber);
2278 return WINED3DERR_INVALIDCALL;
2279 } else if(OffsetInBytes & 0x3) {
2280 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2281 return WINED3DERR_INVALIDCALL;
2284 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2285 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2287 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2289 if(oldSrc == pStreamData &&
2290 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2291 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2292 TRACE("Application is setting the old values over, nothing to do\n");
2296 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2298 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2299 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2302 /* Handle recording of state blocks */
2303 if (This->isRecordingState) {
2304 TRACE("Recording... not performing anything\n");
2305 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2306 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2310 if (pStreamData != NULL) {
2311 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2312 IWineD3DBuffer_AddRef(pStreamData);
2314 if (oldSrc != NULL) {
2315 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2316 IWineD3DBuffer_Release(oldSrc);
2319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2324 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2325 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2330 This->stateBlock->streamSource[StreamNumber],
2331 This->stateBlock->streamOffset[StreamNumber],
2332 This->stateBlock->streamStride[StreamNumber]);
2334 if (StreamNumber >= MAX_STREAMS) {
2335 WARN("Stream out of range %d\n", StreamNumber);
2336 return WINED3DERR_INVALIDCALL;
2338 *pStream = This->stateBlock->streamSource[StreamNumber];
2339 *pStride = This->stateBlock->streamStride[StreamNumber];
2341 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2344 if (*pStream != NULL) {
2345 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2350 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2353 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2355 /* Verify input at least in d3d9 this is invalid*/
2356 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2357 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2358 return WINED3DERR_INVALIDCALL;
2360 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2361 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2362 return WINED3DERR_INVALIDCALL;
2365 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2369 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2370 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2372 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2373 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2375 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2376 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2383 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2386 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2387 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2389 TRACE("(%p) : returning %d\n", This, *Divider);
2395 * Get / Set & Multiply Transform
2397 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2400 /* Most of this routine, comments included copied from ddraw tree initially: */
2401 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2403 /* Handle recording of state blocks */
2404 if (This->isRecordingState) {
2405 TRACE("Recording... not performing anything\n");
2406 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2407 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2412 * If the new matrix is the same as the current one,
2413 * we cut off any further processing. this seems to be a reasonable
2414 * optimization because as was noticed, some apps (warcraft3 for example)
2415 * tend towards setting the same matrix repeatedly for some reason.
2417 * From here on we assume that the new matrix is different, wherever it matters.
2419 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2420 TRACE("The app is setting the same matrix over again\n");
2423 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2427 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2428 where ViewMat = Camera space, WorldMat = world space.
2430 In OpenGL, camera and world space is combined into GL_MODELVIEW
2431 matrix. The Projection matrix stay projection matrix.
2434 /* Capture the times we can just ignore the change for now */
2435 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2436 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2437 /* Handled by the state manager */
2440 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2446 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2448 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2449 *pMatrix = This->stateBlock->transforms[State];
2453 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2454 const WINED3DMATRIX *mat = NULL;
2457 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2458 * below means it will be recorded in a state block change, but it
2459 * works regardless where it is recorded.
2460 * If this is found to be wrong, change to StateBlock.
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2463 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2465 if (State <= HIGHEST_TRANSFORMSTATE)
2467 mat = &This->updateStateBlock->transforms[State];
2469 FIXME("Unhandled transform state!!\n");
2472 multiply_matrix(&temp, mat, pMatrix);
2474 /* Apply change via set transform - will reapply to eg. lights this way */
2475 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2481 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2482 you can reference any indexes you want as long as that number max are enabled at any
2483 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2484 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2485 but when recording, just build a chain pretty much of commands to be replayed. */
2487 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2489 struct wined3d_light_info *object = NULL;
2490 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2494 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2496 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2500 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2501 return WINED3DERR_INVALIDCALL;
2504 switch(pLight->Type) {
2505 case WINED3DLIGHT_POINT:
2506 case WINED3DLIGHT_SPOT:
2507 case WINED3DLIGHT_PARALLELPOINT:
2508 case WINED3DLIGHT_GLSPOT:
2509 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2512 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2514 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2515 return WINED3DERR_INVALIDCALL;
2519 case WINED3DLIGHT_DIRECTIONAL:
2520 /* Ignores attenuation */
2524 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2525 return WINED3DERR_INVALIDCALL;
2528 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2530 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2531 if(object->OriginalIndex == Index) break;
2536 TRACE("Adding new light\n");
2537 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2539 ERR("Out of memory error when allocating a light\n");
2540 return E_OUTOFMEMORY;
2542 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2543 object->glIndex = -1;
2544 object->OriginalIndex = Index;
2547 /* Initialize the object */
2548 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,
2549 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2550 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2551 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2552 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2553 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2554 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2556 /* Save away the information */
2557 object->OriginalParms = *pLight;
2559 switch (pLight->Type) {
2560 case WINED3DLIGHT_POINT:
2562 object->lightPosn[0] = pLight->Position.x;
2563 object->lightPosn[1] = pLight->Position.y;
2564 object->lightPosn[2] = pLight->Position.z;
2565 object->lightPosn[3] = 1.0f;
2566 object->cutoff = 180.0f;
2570 case WINED3DLIGHT_DIRECTIONAL:
2572 object->lightPosn[0] = -pLight->Direction.x;
2573 object->lightPosn[1] = -pLight->Direction.y;
2574 object->lightPosn[2] = -pLight->Direction.z;
2575 object->lightPosn[3] = 0.0f;
2576 object->exponent = 0.0f;
2577 object->cutoff = 180.0f;
2580 case WINED3DLIGHT_SPOT:
2582 object->lightPosn[0] = pLight->Position.x;
2583 object->lightPosn[1] = pLight->Position.y;
2584 object->lightPosn[2] = pLight->Position.z;
2585 object->lightPosn[3] = 1.0f;
2588 object->lightDirn[0] = pLight->Direction.x;
2589 object->lightDirn[1] = pLight->Direction.y;
2590 object->lightDirn[2] = pLight->Direction.z;
2591 object->lightDirn[3] = 1.0f;
2594 * opengl-ish and d3d-ish spot lights use too different models for the
2595 * light "intensity" as a function of the angle towards the main light direction,
2596 * so we only can approximate very roughly.
2597 * however spot lights are rather rarely used in games (if ever used at all).
2598 * furthermore if still used, probably nobody pays attention to such details.
2600 if (pLight->Falloff == 0) {
2601 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2602 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2603 * will always be 1.0 for both of them, and we don't have to care for the
2604 * rest of the rather complex calculation
2606 object->exponent = 0.0f;
2608 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2609 if (rho < 0.0001f) rho = 0.0001f;
2610 object->exponent = -0.3f/logf(cosf(rho/2));
2612 if (object->exponent > 128.0f)
2614 object->exponent = 128.0f;
2616 object->cutoff = (float) (pLight->Phi*90/M_PI);
2622 FIXME("Unrecognized light type %d\n", pLight->Type);
2625 /* Update the live definitions if the light is currently assigned a glIndex */
2626 if (object->glIndex != -1 && !This->isRecordingState) {
2627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2632 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2634 struct wined3d_light_info *lightInfo = NULL;
2635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2636 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2638 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2640 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2642 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2643 if(lightInfo->OriginalIndex == Index) break;
2647 if (lightInfo == NULL) {
2648 TRACE("Light information requested but light not defined\n");
2649 return WINED3DERR_INVALIDCALL;
2652 *pLight = lightInfo->OriginalParms;
2657 * Get / Set Light Enable
2658 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2660 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2662 struct wined3d_light_info *lightInfo = NULL;
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2666 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2668 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2670 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2671 if(lightInfo->OriginalIndex == Index) break;
2674 TRACE("Found light: %p\n", lightInfo);
2676 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2677 if (lightInfo == NULL) {
2679 TRACE("Light enabled requested but light not defined, so defining one!\n");
2680 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2682 /* Search for it again! Should be fairly quick as near head of list */
2683 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2685 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2686 if(lightInfo->OriginalIndex == Index) break;
2689 if (lightInfo == NULL) {
2690 FIXME("Adding default lights has failed dismally\n");
2691 return WINED3DERR_INVALIDCALL;
2696 if(lightInfo->glIndex != -1) {
2697 if(!This->isRecordingState) {
2698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2701 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2702 lightInfo->glIndex = -1;
2704 TRACE("Light already disabled, nothing to do\n");
2706 lightInfo->enabled = FALSE;
2708 lightInfo->enabled = TRUE;
2709 if (lightInfo->glIndex != -1) {
2711 TRACE("Nothing to do as light was enabled\n");
2714 /* Find a free gl light */
2715 for(i = 0; i < This->maxConcurrentLights; i++) {
2716 if(This->updateStateBlock->activeLights[i] == NULL) {
2717 This->updateStateBlock->activeLights[i] = lightInfo;
2718 lightInfo->glIndex = i;
2722 if(lightInfo->glIndex == -1) {
2723 /* Our tests show that Windows returns D3D_OK in this situation, even with
2724 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2725 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2726 * as well for those lights.
2728 * TODO: Test how this affects rendering
2730 WARN("Too many concurrently active lights\n");
2734 /* i == lightInfo->glIndex */
2735 if(!This->isRecordingState) {
2736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2744 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2746 struct wined3d_light_info *lightInfo = NULL;
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2750 TRACE("(%p) : for idx(%d)\n", This, Index);
2752 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2754 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2755 if(lightInfo->OriginalIndex == Index) break;
2759 if (lightInfo == NULL) {
2760 TRACE("Light enabled state requested but light not defined\n");
2761 return WINED3DERR_INVALIDCALL;
2763 /* true is 128 according to SetLightEnable */
2764 *pEnable = lightInfo->enabled ? 128 : 0;
2769 * Get / Set Clip Planes
2771 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2775 /* Validate Index */
2776 if (Index >= This->adapter->gl_info.limits.clipplanes)
2778 TRACE("Application has requested clipplane this device doesn't support\n");
2779 return WINED3DERR_INVALIDCALL;
2782 This->updateStateBlock->changed.clipplane |= 1 << Index;
2784 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2785 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2786 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2787 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2788 TRACE("Application is setting old values over, nothing to do\n");
2792 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2793 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2794 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2795 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2797 /* Handle recording of state blocks */
2798 if (This->isRecordingState) {
2799 TRACE("Recording... not performing anything\n");
2803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2808 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2810 TRACE("(%p) : for idx %d\n", This, Index);
2812 /* Validate Index */
2813 if (Index >= This->adapter->gl_info.limits.clipplanes)
2815 TRACE("Application has requested clipplane this device doesn't support\n");
2816 return WINED3DERR_INVALIDCALL;
2819 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2820 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2821 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2822 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2827 * Get / Set Clip Plane Status
2828 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2830 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 FIXME("(%p) : stub\n", This);
2833 if (NULL == pClipStatus) {
2834 return WINED3DERR_INVALIDCALL;
2836 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2837 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2841 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2843 FIXME("(%p) : stub\n", This);
2844 if (NULL == pClipStatus) {
2845 return WINED3DERR_INVALIDCALL;
2847 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2848 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2853 * Get / Set Material
2855 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 This->updateStateBlock->changed.material = TRUE;
2859 This->updateStateBlock->material = *pMaterial;
2861 /* Handle recording of state blocks */
2862 if (This->isRecordingState) {
2863 TRACE("Recording... not performing anything\n");
2867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2871 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 *pMaterial = This->updateStateBlock->material;
2874 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2875 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2876 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2877 pMaterial->Ambient.b, pMaterial->Ambient.a);
2878 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2879 pMaterial->Specular.b, pMaterial->Specular.a);
2880 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2881 pMaterial->Emissive.b, pMaterial->Emissive.a);
2882 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2890 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2891 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2894 IWineD3DBuffer *oldIdxs;
2896 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2897 oldIdxs = This->updateStateBlock->pIndexData;
2899 This->updateStateBlock->changed.indices = TRUE;
2900 This->updateStateBlock->pIndexData = pIndexData;
2901 This->updateStateBlock->IndexFmt = fmt;
2903 /* Handle recording of state blocks */
2904 if (This->isRecordingState) {
2905 TRACE("Recording... not performing anything\n");
2906 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2907 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2911 if(oldIdxs != pIndexData) {
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2914 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2915 IWineD3DBuffer_AddRef(pIndexData);
2918 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2919 IWineD3DBuffer_Release(oldIdxs);
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 *ppIndexData = This->stateBlock->pIndexData;
2932 /* up ref count on ppindexdata */
2934 IWineD3DBuffer_AddRef(*ppIndexData);
2935 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2937 TRACE("(%p) No index data set\n", This);
2939 TRACE("Returning %p\n", *ppIndexData);
2944 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 TRACE("(%p)->(%d)\n", This, BaseIndex);
2949 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2950 TRACE("Application is setting the old value over, nothing to do\n");
2954 This->updateStateBlock->baseVertexIndex = BaseIndex;
2956 if (This->isRecordingState) {
2957 TRACE("Recording... not performing anything\n");
2960 /* The base vertex index affects the stream sources */
2961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2965 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 TRACE("(%p) : base_index %p\n", This, base_index);
2969 *base_index = This->stateBlock->baseVertexIndex;
2971 TRACE("Returning %u\n", *base_index);
2977 * Get / Set Viewports
2979 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 TRACE("(%p)\n", This);
2983 This->updateStateBlock->changed.viewport = TRUE;
2984 This->updateStateBlock->viewport = *pViewport;
2986 /* Handle recording of state blocks */
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2992 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2993 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3002 TRACE("(%p)\n", This);
3003 *pViewport = This->stateBlock->viewport;
3008 * Get / Set Render States
3009 * TODO: Verify against dx9 definitions
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 DWORD oldValue = This->stateBlock->renderState[State];
3016 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3018 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3019 This->updateStateBlock->renderState[State] = Value;
3021 /* Handle recording of state blocks */
3022 if (This->isRecordingState) {
3023 TRACE("Recording... not performing anything\n");
3027 /* Compared here and not before the assignment to allow proper stateblock recording */
3028 if(Value == oldValue) {
3029 TRACE("Application is setting the old value over, nothing to do\n");
3031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3042 *pValue = This->stateBlock->renderState[State];
3047 * Get / Set Sampler States
3048 * TODO: Verify against dx9 definitions
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3056 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3058 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3059 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3062 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3063 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3064 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3067 * SetSampler is designed to allow for more than the standard up to 8 textures
3068 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3069 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3071 * http://developer.nvidia.com/object/General_FAQ.html#t6
3073 * There are two new settings for GForce
3075 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3076 * and the texture one:
3077 * GL_MAX_TEXTURE_COORDS_ARB.
3078 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3081 oldValue = This->stateBlock->samplerState[Sampler][Type];
3082 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3083 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3085 /* Handle recording of state blocks */
3086 if (This->isRecordingState) {
3087 TRACE("Recording... not performing anything\n");
3091 if(oldValue == Value) {
3092 TRACE("Application is setting the old value over, nothing to do\n");
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3101 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3105 This, Sampler, debug_d3dsamplerstate(Type), Type);
3107 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3108 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3111 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3112 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3113 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3115 *Value = This->stateBlock->samplerState[Sampler][Type];
3116 TRACE("(%p) : Returning %#x\n", This, *Value);
3121 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 This->updateStateBlock->changed.scissorRect = TRUE;
3125 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3126 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3129 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3131 if(This->isRecordingState) {
3132 TRACE("Recording... not performing anything\n");
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 *pRect = This->updateStateBlock->scissorRect;
3145 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3149 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3151 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3153 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3155 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3156 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3158 This->updateStateBlock->vertexDecl = pDecl;
3159 This->updateStateBlock->changed.vertexDecl = TRUE;
3161 if (This->isRecordingState) {
3162 TRACE("Recording... not performing anything\n");
3164 } else if(pDecl == oldDecl) {
3165 /* Checked after the assignment to allow proper stateblock recording */
3166 TRACE("Application is setting the old declaration over, nothing to do\n");
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3179 *ppDecl = This->stateBlock->vertexDecl;
3180 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3184 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3188 This->updateStateBlock->vertexShader = pShader;
3189 This->updateStateBlock->changed.vertexShader = TRUE;
3191 if (This->isRecordingState) {
3192 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3193 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3194 TRACE("Recording... not performing anything\n");
3196 } else if(oldShader == pShader) {
3197 /* Checked here to allow proper stateblock recording */
3198 TRACE("App is setting the old shader over, nothing to do\n");
3202 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3203 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3204 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3211 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3213 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3214 IWineD3DVertexShader *shader;
3216 TRACE("iface %p.\n", iface);
3218 shader = device->stateBlock->vertexShader;
3219 if (shader) IWineD3DVertexShader_AddRef(shader);
3221 TRACE("Returning %p.\n", shader);
3225 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3226 IWineD3DDevice *iface,
3228 CONST BOOL *srcData,
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3234 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3235 iface, srcData, start, count);
3237 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3239 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3240 for (i = 0; i < cnt; i++)
3241 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3243 for (i = start; i < cnt + start; ++i) {
3244 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3247 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3252 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3253 IWineD3DDevice *iface,
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 int cnt = min(count, MAX_CONST_B - start);
3261 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3262 iface, dstData, start, count);
3264 if (dstData == NULL || cnt < 0)
3265 return WINED3DERR_INVALIDCALL;
3267 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3272 IWineD3DDevice *iface,
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3278 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3280 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3281 iface, srcData, start, count);
3283 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3285 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3286 for (i = 0; i < cnt; i++)
3287 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3288 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3290 for (i = start; i < cnt + start; ++i) {
3291 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3294 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3299 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3300 IWineD3DDevice *iface,
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 int cnt = min(count, MAX_CONST_I - start);
3308 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3309 iface, dstData, start, count);
3311 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3312 return WINED3DERR_INVALIDCALL;
3314 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3319 IWineD3DDevice *iface,
3321 CONST float *srcData,
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3328 iface, srcData, start, count);
3330 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3331 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3332 return WINED3DERR_INVALIDCALL;
3334 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3336 for (i = 0; i < count; i++)
3337 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3338 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3341 if (!This->isRecordingState)
3343 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3347 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3348 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3353 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3354 IWineD3DDevice *iface,
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3360 int cnt = min(count, This->d3d_vshader_constantF - start);
3362 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3363 iface, dstData, start, count);
3365 if (dstData == NULL || cnt < 0)
3366 return WINED3DERR_INVALIDCALL;
3368 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3372 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3374 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3380 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3382 DWORD i = This->rev_tex_unit_map[unit];
3383 DWORD j = This->texUnitMap[stage];
3385 This->texUnitMap[stage] = unit;
3386 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3388 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3391 This->rev_tex_unit_map[unit] = stage;
3392 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3394 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3398 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3401 This->fixed_function_usage_map = 0;
3402 for (i = 0; i < MAX_TEXTURES; ++i) {
3403 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3404 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3405 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3406 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3407 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3408 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3409 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3410 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3412 if (color_op == WINED3DTOP_DISABLE) {
3413 /* Not used, and disable higher stages */
3417 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3418 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3419 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3420 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3421 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3422 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3423 This->fixed_function_usage_map |= (1 << i);
3426 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3427 This->fixed_function_usage_map |= (1 << (i + 1));
3432 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3434 unsigned int i, tex;
3437 device_update_fixed_function_usage_map(This);
3438 ffu_map = This->fixed_function_usage_map;
3440 if (This->max_ffp_textures == gl_info->limits.texture_stages
3441 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3443 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3445 if (!(ffu_map & 1)) continue;
3447 if (This->texUnitMap[i] != i) {
3448 device_map_stage(This, i, i);
3449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3450 markTextureStagesDirty(This, i);
3456 /* Now work out the mapping */
3458 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3460 if (!(ffu_map & 1)) continue;
3462 if (This->texUnitMap[i] != tex) {
3463 device_map_stage(This, i, tex);
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3465 markTextureStagesDirty(This, i);
3472 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3474 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3475 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3478 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3479 if (sampler_type[i] && This->texUnitMap[i] != i)
3481 device_map_stage(This, i, i);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3483 if (i < gl_info->limits.texture_stages)
3485 markTextureStagesDirty(This, i);
3491 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3492 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3494 DWORD current_mapping = This->rev_tex_unit_map[unit];
3496 /* Not currently used */
3497 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3499 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3500 /* Used by a fragment sampler */
3502 if (!pshader_sampler_tokens) {
3503 /* No pixel shader, check fixed function */
3504 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3507 /* Pixel shader, check the shader's sampler map */
3508 return !pshader_sampler_tokens[current_mapping];
3511 /* Used by a vertex sampler */
3512 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3515 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3517 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3518 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3519 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3520 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3524 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3526 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3527 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3528 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3531 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3532 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3533 if (vshader_sampler_type[i])
3535 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3537 /* Already mapped somewhere */
3541 while (start >= 0) {
3542 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3544 device_map_stage(This, vsampler_idx, start);
3545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3557 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3559 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3560 BOOL vs = use_vs(This->stateBlock);
3561 BOOL ps = use_ps(This->stateBlock);
3564 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3565 * that would be really messy and require shader recompilation
3566 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3567 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3569 if (ps) device_map_psamplers(This, gl_info);
3570 else device_map_fixed_function_samplers(This, gl_info);
3572 if (vs) device_map_vsamplers(This, ps, gl_info);
3575 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3578 This->updateStateBlock->pixelShader = pShader;
3579 This->updateStateBlock->changed.pixelShader = TRUE;
3581 /* Handle recording of state blocks */
3582 if (This->isRecordingState) {
3583 TRACE("Recording... not performing anything\n");
3586 if (This->isRecordingState) {
3587 TRACE("Recording... not performing anything\n");
3588 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3589 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3593 if(pShader == oldShader) {
3594 TRACE("App is setting the old pixel shader over, nothing to do\n");
3598 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3599 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3601 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3607 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3609 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3610 IWineD3DPixelShader *shader;
3612 TRACE("iface %p.\n", iface);
3614 shader = device->stateBlock->pixelShader;
3615 if (shader) IWineD3DPixelShader_AddRef(shader);
3617 TRACE("Returning %p.\n", shader);
3621 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3622 IWineD3DDevice *iface,
3624 CONST BOOL *srcData,
3627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3628 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3630 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3631 iface, srcData, start, count);
3633 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3635 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3636 for (i = 0; i < cnt; i++)
3637 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3639 for (i = start; i < cnt + start; ++i) {
3640 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3643 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3648 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3649 IWineD3DDevice *iface,
3654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655 int cnt = min(count, MAX_CONST_B - start);
3657 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3658 iface, dstData, start, count);
3660 if (dstData == NULL || cnt < 0)
3661 return WINED3DERR_INVALIDCALL;
3663 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3667 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3668 IWineD3DDevice *iface,
3673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3674 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3676 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3677 iface, srcData, start, count);
3679 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3681 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3682 for (i = 0; i < cnt; i++)
3683 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3684 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3686 for (i = start; i < cnt + start; ++i) {
3687 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3690 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3695 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3696 IWineD3DDevice *iface,
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 int cnt = min(count, MAX_CONST_I - start);
3704 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3705 iface, dstData, start, count);
3707 if (dstData == NULL || cnt < 0)
3708 return WINED3DERR_INVALIDCALL;
3710 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3714 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3715 IWineD3DDevice *iface,
3717 CONST float *srcData,
3720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3723 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3724 iface, srcData, start, count);
3726 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3727 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3728 return WINED3DERR_INVALIDCALL;
3730 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3732 for (i = 0; i < count; i++)
3733 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3734 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3737 if (!This->isRecordingState)
3739 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3743 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3744 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3749 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3750 IWineD3DDevice *iface,
3755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3756 int cnt = min(count, This->d3d_pshader_constantF - start);
3758 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3759 iface, dstData, start, count);
3761 if (dstData == NULL || cnt < 0)
3762 return WINED3DERR_INVALIDCALL;
3764 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3768 /* Context activation is done by the caller. */
3769 /* Do not call while under the GL lock. */
3770 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3771 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3772 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3776 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3779 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3783 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3785 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3788 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3790 ERR("Source has no position mask\n");
3791 return WINED3DERR_INVALIDCALL;
3794 if (!dest->resource.allocatedMemory)
3795 buffer_get_sysmem(dest, gl_info);
3797 /* Get a pointer into the destination vbo(create one if none exists) and
3798 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3800 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3802 dest->flags |= WINED3D_BUFFER_CREATEBO;
3803 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3806 if (dest->buffer_object)
3808 unsigned char extrabytes = 0;
3809 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3810 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3811 * this may write 4 extra bytes beyond the area that should be written
3813 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3814 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3815 if(!dest_conv_addr) {
3816 ERR("Out of memory\n");
3817 /* Continue without storing converted vertices */
3819 dest_conv = dest_conv_addr;
3823 * a) WINED3DRS_CLIPPING is enabled
3824 * b) WINED3DVOP_CLIP is passed
3826 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3827 static BOOL warned = FALSE;
3829 * The clipping code is not quite correct. Some things need
3830 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3831 * so disable clipping for now.
3832 * (The graphics in Half-Life are broken, and my processvertices
3833 * test crashes with IDirect3DDevice3)
3839 FIXME("Clipping is broken and disabled for now\n");
3841 } else doClip = FALSE;
3842 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3844 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3847 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3848 WINED3DTS_PROJECTION,
3850 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3851 WINED3DTS_WORLDMATRIX(0),
3854 TRACE("View mat:\n");
3855 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3856 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3857 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3858 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3860 TRACE("Proj mat:\n");
3861 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3862 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3863 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3864 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3866 TRACE("World mat:\n");
3867 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3868 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3869 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3870 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3872 /* Get the viewport */
3873 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3874 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3875 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3877 multiply_matrix(&mat,&view_mat,&world_mat);
3878 multiply_matrix(&mat,&proj_mat,&mat);
3880 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3882 for (i = 0; i < dwCount; i+= 1) {
3883 unsigned int tex_index;
3885 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3886 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3887 /* The position first */
3888 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3889 const float *p = (const float *)(element->data + i * element->stride);
3891 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3893 /* Multiplication with world, view and projection matrix */
3894 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
3895 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
3896 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
3897 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
3899 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3901 /* WARNING: The following things are taken from d3d7 and were not yet checked
3902 * against d3d8 or d3d9!
3905 /* Clipping conditions: From msdn
3907 * A vertex is clipped if it does not match the following requirements
3911 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3913 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3914 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3919 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3920 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3923 /* "Normal" viewport transformation (not clipped)
3924 * 1) The values are divided by rhw
3925 * 2) The y axis is negative, so multiply it with -1
3926 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3927 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3928 * 4) Multiply x with Width/2 and add Width/2
3929 * 5) The same for the height
3930 * 6) Add the viewpoint X and Y to the 2D coordinates and
3931 * The minimum Z value to z
3932 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3934 * Well, basically it's simply a linear transformation into viewport
3946 z *= vp.MaxZ - vp.MinZ;
3948 x += vp.Width / 2 + vp.X;
3949 y += vp.Height / 2 + vp.Y;
3954 /* That vertex got clipped
3955 * Contrary to OpenGL it is not dropped completely, it just
3956 * undergoes a different calculation.
3958 TRACE("Vertex got clipped\n");
3965 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3966 * outside of the main vertex buffer memory. That needs some more
3971 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3974 ( (float *) dest_ptr)[0] = x;
3975 ( (float *) dest_ptr)[1] = y;
3976 ( (float *) dest_ptr)[2] = z;
3977 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3979 dest_ptr += 3 * sizeof(float);
3981 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3982 dest_ptr += sizeof(float);
3987 ( (float *) dest_conv)[0] = x * w;
3988 ( (float *) dest_conv)[1] = y * w;
3989 ( (float *) dest_conv)[2] = z * w;
3990 ( (float *) dest_conv)[3] = w;
3992 dest_conv += 3 * sizeof(float);
3994 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3995 dest_conv += sizeof(float);
3999 if (DestFVF & WINED3DFVF_PSIZE) {
4000 dest_ptr += sizeof(DWORD);
4001 if(dest_conv) dest_conv += sizeof(DWORD);
4003 if (DestFVF & WINED3DFVF_NORMAL) {
4004 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4005 const float *normal = (const float *)(element->data + i * element->stride);
4006 /* AFAIK this should go into the lighting information */
4007 FIXME("Didn't expect the destination to have a normal\n");
4008 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4010 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4014 if (DestFVF & WINED3DFVF_DIFFUSE) {
4015 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4016 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4017 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4019 static BOOL warned = FALSE;
4022 ERR("No diffuse color in source, but destination has one\n");
4026 *( (DWORD *) dest_ptr) = 0xffffffff;
4027 dest_ptr += sizeof(DWORD);
4030 *( (DWORD *) dest_conv) = 0xffffffff;
4031 dest_conv += sizeof(DWORD);
4035 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4037 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4038 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4039 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4040 dest_conv += sizeof(DWORD);
4045 if (DestFVF & WINED3DFVF_SPECULAR)
4047 /* What's the color value in the feedback buffer? */
4048 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4049 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4050 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4052 static BOOL warned = FALSE;
4055 ERR("No specular color in source, but destination has one\n");
4059 *( (DWORD *) dest_ptr) = 0xFF000000;
4060 dest_ptr += sizeof(DWORD);
4063 *( (DWORD *) dest_conv) = 0xFF000000;
4064 dest_conv += sizeof(DWORD);
4068 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4070 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4071 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4072 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4073 dest_conv += sizeof(DWORD);
4078 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4079 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4080 const float *tex_coord = (const float *)(element->data + i * element->stride);
4081 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4083 ERR("No source texture, but destination requests one\n");
4084 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4085 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4088 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4090 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4100 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4101 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4102 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4103 dwCount * get_flexible_vertex_size(DestFVF),
4105 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4109 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4114 #undef copy_and_next
4116 /* Do not call while under the GL lock. */
4117 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4118 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4122 struct wined3d_stream_info stream_info;
4123 const struct wined3d_gl_info *gl_info;
4124 struct wined3d_context *context;
4125 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4128 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4131 ERR("Output vertex declaration not implemented yet\n");
4134 /* Need any context to write to the vbo. */
4135 context = context_acquire(This, NULL);
4136 gl_info = context->gl_info;
4138 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4139 * control the streamIsUP flag, thus restore it afterwards.
4141 This->stateBlock->streamIsUP = FALSE;
4142 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4143 This->stateBlock->streamIsUP = streamWasUP;
4145 if(vbo || SrcStartIndex) {
4147 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4148 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4150 * Also get the start index in, but only loop over all elements if there's something to add at all.
4152 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4154 struct wined3d_stream_info_element *e;
4156 if (!(stream_info.use_map & (1 << i))) continue;
4158 e = &stream_info.elements[i];
4159 if (e->buffer_object)
4161 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4162 e->buffer_object = 0;
4163 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4165 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4166 vb->buffer_object = 0;
4169 if (e->data) e->data += e->stride * SrcStartIndex;
4173 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4174 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4176 context_release(context);
4182 * Get / Set Texture Stage States
4183 * TODO: Verify against dx9 definitions
4185 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4187 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4188 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4190 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4192 if (Stage >= gl_info->limits.texture_stages)
4194 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4195 Stage, gl_info->limits.texture_stages - 1);
4199 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4200 This->updateStateBlock->textureState[Stage][Type] = Value;
4202 if (This->isRecordingState) {
4203 TRACE("Recording... not performing anything\n");
4207 /* Checked after the assignments to allow proper stateblock recording */
4208 if(oldValue == Value) {
4209 TRACE("App is setting the old value over, nothing to do\n");
4213 if(Stage > This->stateBlock->lowest_disabled_stage &&
4214 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4215 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4216 * Changes in other states are important on disabled stages too
4221 if(Type == WINED3DTSS_COLOROP) {
4224 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4225 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4226 * they have to be disabled
4228 * The current stage is dirtified below.
4230 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4231 TRACE("Additionally dirtifying stage %u\n", i);
4232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4234 This->stateBlock->lowest_disabled_stage = Stage;
4235 TRACE("New lowest disabled: %u\n", Stage);
4236 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4237 /* Previously disabled stage enabled. Stages above it may need enabling
4238 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4239 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4241 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4244 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4246 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4249 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4252 This->stateBlock->lowest_disabled_stage = i;
4253 TRACE("New lowest disabled: %u\n", i);
4257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4262 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4264 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4265 *pValue = This->updateStateBlock->textureState[Stage][Type];
4272 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4273 DWORD stage, IWineD3DBaseTexture *texture)
4275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4277 IWineD3DBaseTexture *prev;
4279 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4281 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4282 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4284 /* Windows accepts overflowing this array... we do not. */
4285 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4287 WARN("Ignoring invalid stage %u.\n", stage);
4291 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4292 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4294 WARN("Rejecting attempt to set scratch texture.\n");
4295 return WINED3DERR_INVALIDCALL;
4298 This->updateStateBlock->changed.textures |= 1 << stage;
4300 prev = This->updateStateBlock->textures[stage];
4301 TRACE("Previous texture %p.\n", prev);
4303 if (texture == prev)
4305 TRACE("App is setting the same texture again, nothing to do.\n");
4309 TRACE("Setting new texture to %p.\n", texture);
4310 This->updateStateBlock->textures[stage] = texture;
4312 if (This->isRecordingState)
4314 TRACE("Recording... not performing anything\n");
4316 if (texture) IWineD3DBaseTexture_AddRef(texture);
4317 if (prev) IWineD3DBaseTexture_Release(prev);
4324 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4325 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4326 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4328 IWineD3DBaseTexture_AddRef(texture);
4330 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4335 if (!prev && stage < gl_info->limits.texture_stages)
4337 /* The source arguments for color and alpha ops have different
4338 * meanings when a NULL texture is bound, so the COLOROP and
4339 * ALPHAOP have to be dirtified. */
4340 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4344 if (bind_count == 1) t->baseTexture.sampler = stage;
4349 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4350 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4352 IWineD3DBaseTexture_Release(prev);
4354 if (!texture && stage < gl_info->limits.texture_stages)
4356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4360 if (bind_count && t->baseTexture.sampler == stage)
4364 /* Search for other stages the texture is bound to. Shouldn't
4365 * happen if applications bind textures to a single stage only. */
4366 TRACE("Searching for other stages the texture is bound to.\n");
4367 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4369 if (This->updateStateBlock->textures[i] == prev)
4371 TRACE("Texture is also bound to stage %u.\n", i);
4372 t->baseTexture.sampler = i;
4379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4384 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4387 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4389 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4390 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4393 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4394 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4395 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4398 *ppTexture=This->stateBlock->textures[Stage];
4400 IWineD3DBaseTexture_AddRef(*ppTexture);
4402 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4410 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4411 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4413 IWineD3DSwapChain *swapchain;
4416 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4417 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4419 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4422 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4426 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4427 IWineD3DSwapChain_Release(swapchain);
4430 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4437 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 WARN("(%p) : stub, calling idirect3d for now\n", This);
4440 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4443 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4445 IWineD3DSwapChain *swapChain;
4448 if(iSwapChain > 0) {
4449 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4450 if (hr == WINED3D_OK) {
4451 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4452 IWineD3DSwapChain_Release(swapChain);
4454 FIXME("(%p) Error getting display mode\n", This);
4457 /* Don't read the real display mode,
4458 but return the stored mode instead. X11 can't change the color
4459 depth, and some apps are pretty angry if they SetDisplayMode from
4460 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4462 Also don't relay to the swapchain because with ddraw it's possible
4463 that there isn't a swapchain at all */
4464 pMode->Width = This->ddraw_width;
4465 pMode->Height = This->ddraw_height;
4466 pMode->Format = This->ddraw_format;
4467 pMode->RefreshRate = 0;
4475 * Stateblock related functions
4478 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 IWineD3DStateBlock *stateblock;
4483 TRACE("(%p)\n", This);
4485 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4487 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4488 if (FAILED(hr)) return hr;
4490 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4491 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4492 This->isRecordingState = TRUE;
4494 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4499 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4501 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4503 if (!This->isRecordingState) {
4504 WARN("(%p) not recording! returning error\n", This);
4505 *ppStateBlock = NULL;
4506 return WINED3DERR_INVALIDCALL;
4509 stateblock_init_contained_states(object);
4511 *ppStateBlock = (IWineD3DStateBlock*) object;
4512 This->isRecordingState = FALSE;
4513 This->updateStateBlock = This->stateBlock;
4514 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4515 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4516 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4521 * Scene related functions
4523 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4524 /* At the moment we have no need for any functionality at the beginning
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 TRACE("(%p)\n", This);
4530 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4531 return WINED3DERR_INVALIDCALL;
4533 This->inScene = TRUE;
4537 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 struct wined3d_context *context;
4542 TRACE("(%p)\n", This);
4544 if(!This->inScene) {
4545 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4546 return WINED3DERR_INVALIDCALL;
4549 context = context_acquire(This, NULL);
4550 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4552 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4554 context_release(context);
4556 This->inScene = FALSE;
4560 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4561 const RECT *pSourceRect, const RECT *pDestRect,
4562 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4564 IWineD3DSwapChain *swapChain = NULL;
4566 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4568 TRACE("iface %p.\n", iface);
4570 for(i = 0 ; i < swapchains ; i ++) {
4572 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4573 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4574 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4575 IWineD3DSwapChain_Release(swapChain);
4581 /* Do not call while under the GL lock. */
4582 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4583 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4585 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4586 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4589 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4590 iface, rect_count, rects, flags, color, depth, stencil);
4592 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4594 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4595 /* TODO: What about depth stencil buffers without stencil bits? */
4596 return WINED3DERR_INVALIDCALL;
4599 device_get_draw_rect(device, &draw_rect);
4601 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4602 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4609 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4610 WINED3DPRIMITIVETYPE primitive_type)
4612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4616 This->updateStateBlock->changed.primitive_type = TRUE;
4617 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4620 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4621 WINED3DPRIMITIVETYPE *primitive_type)
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4627 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4629 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4632 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4636 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4638 if(!This->stateBlock->vertexDecl) {
4639 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4640 return WINED3DERR_INVALIDCALL;
4643 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4644 if(This->stateBlock->streamIsUP) {
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4646 This->stateBlock->streamIsUP = FALSE;
4649 if(This->stateBlock->loadBaseVertexIndex != 0) {
4650 This->stateBlock->loadBaseVertexIndex = 0;
4651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4653 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4654 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4658 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 IWineD3DBuffer *pIB;
4665 pIB = This->stateBlock->pIndexData;
4667 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4668 * without an index buffer set. (The first time at least...)
4669 * D3D8 simply dies, but I doubt it can do much harm to return
4670 * D3DERR_INVALIDCALL there as well. */
4671 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4672 return WINED3DERR_INVALIDCALL;
4675 if(!This->stateBlock->vertexDecl) {
4676 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4677 return WINED3DERR_INVALIDCALL;
4680 if(This->stateBlock->streamIsUP) {
4681 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4682 This->stateBlock->streamIsUP = FALSE;
4684 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4686 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4688 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4694 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4695 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4699 drawPrimitive(iface, index_count, startIndex, idxStride,
4700 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4705 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4706 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4712 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4714 if(!This->stateBlock->vertexDecl) {
4715 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4716 return WINED3DERR_INVALIDCALL;
4719 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4720 vb = This->stateBlock->streamSource[0];
4721 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4722 if (vb) IWineD3DBuffer_Release(vb);
4723 This->stateBlock->streamOffset[0] = 0;
4724 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4725 This->stateBlock->streamIsUP = TRUE;
4726 This->stateBlock->loadBaseVertexIndex = 0;
4728 /* TODO: Only mark dirty if drawing from a different UP address */
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4731 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4733 /* MSDN specifies stream zero settings must be set to NULL */
4734 This->stateBlock->streamStride[0] = 0;
4735 This->stateBlock->streamSource[0] = NULL;
4737 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4738 * the new stream sources or use UP drawing again
4743 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4744 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4745 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4752 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4753 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4755 if(!This->stateBlock->vertexDecl) {
4756 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4757 return WINED3DERR_INVALIDCALL;
4760 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4766 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4767 vb = This->stateBlock->streamSource[0];
4768 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4769 if (vb) IWineD3DBuffer_Release(vb);
4770 This->stateBlock->streamIsUP = TRUE;
4771 This->stateBlock->streamOffset[0] = 0;
4772 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4774 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4775 This->stateBlock->baseVertexIndex = 0;
4776 This->stateBlock->loadBaseVertexIndex = 0;
4777 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4781 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4783 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4784 This->stateBlock->streamSource[0] = NULL;
4785 This->stateBlock->streamStride[0] = 0;
4786 ib = This->stateBlock->pIndexData;
4788 IWineD3DBuffer_Release(ib);
4789 This->stateBlock->pIndexData = NULL;
4791 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4792 * SetStreamSource to specify a vertex buffer
4798 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4799 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4803 /* Mark the state dirty until we have nicer tracking
4804 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4809 This->stateBlock->baseVertexIndex = 0;
4810 This->up_strided = DrawPrimStrideData;
4811 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4812 This->up_strided = NULL;
4816 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4817 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4818 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4821 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4823 /* Mark the state dirty until we have nicer tracking
4824 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4829 This->stateBlock->streamIsUP = TRUE;
4830 This->stateBlock->baseVertexIndex = 0;
4831 This->up_strided = DrawPrimStrideData;
4832 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4833 This->up_strided = NULL;
4837 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4838 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4839 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4841 WINED3DLOCKED_BOX src;
4842 WINED3DLOCKED_BOX dst;
4845 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4846 iface, pSourceVolume, pDestinationVolume);
4848 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4849 * dirtification to improve loading performance.
4851 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4852 if(FAILED(hr)) return hr;
4853 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4855 IWineD3DVolume_UnlockBox(pSourceVolume);
4859 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4861 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4863 IWineD3DVolume_UnlockBox(pSourceVolume);
4865 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4870 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4871 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4873 unsigned int level_count, i;
4874 WINED3DRESOURCETYPE type;
4877 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4879 /* Verify that the source and destination textures are non-NULL. */
4880 if (!src_texture || !dst_texture)
4882 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4883 return WINED3DERR_INVALIDCALL;
4886 if (src_texture == dst_texture)
4888 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4889 return WINED3DERR_INVALIDCALL;
4892 /* Verify that the source and destination textures are the same type. */
4893 type = IWineD3DBaseTexture_GetType(src_texture);
4894 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4896 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4897 return WINED3DERR_INVALIDCALL;
4900 /* Check that both textures have the identical numbers of levels. */
4901 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4902 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4904 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4905 return WINED3DERR_INVALIDCALL;
4908 /* Make sure that the destination texture is loaded. */
4909 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4911 /* Update every surface level of the texture. */
4914 case WINED3DRTYPE_TEXTURE:
4916 IWineD3DSurface *src_surface;
4917 IWineD3DSurface *dst_surface;
4919 for (i = 0; i < level_count; ++i)
4921 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4922 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4923 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4924 IWineD3DSurface_Release(dst_surface);
4925 IWineD3DSurface_Release(src_surface);
4928 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4935 case WINED3DRTYPE_CUBETEXTURE:
4937 IWineD3DSurface *src_surface;
4938 IWineD3DSurface *dst_surface;
4939 WINED3DCUBEMAP_FACES face;
4941 for (i = 0; i < level_count; ++i)
4943 /* Update each cube face. */
4944 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4946 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4947 face, i, &src_surface);
4948 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4949 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4950 face, i, &dst_surface);
4951 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4952 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4953 IWineD3DSurface_Release(dst_surface);
4954 IWineD3DSurface_Release(src_surface);
4957 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4965 case WINED3DRTYPE_VOLUMETEXTURE:
4967 IWineD3DVolume *src_volume;
4968 IWineD3DVolume *dst_volume;
4970 for (i = 0; i < level_count; ++i)
4972 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4973 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4974 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4975 IWineD3DVolume_Release(dst_volume);
4976 IWineD3DVolume_Release(src_volume);
4979 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4987 FIXME("Unsupported texture type %#x.\n", type);
4988 return WINED3DERR_INVALIDCALL;
4994 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4995 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4997 IWineD3DSwapChain *swapchain;
5000 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5002 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5003 if (FAILED(hr)) return hr;
5005 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5006 IWineD3DSwapChain_Release(swapchain);
5011 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5013 IWineD3DBaseTextureImpl *texture;
5016 TRACE("(%p) : %p\n", This, pNumPasses);
5018 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5019 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5020 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5021 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5023 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5024 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5025 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5028 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5029 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5031 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5032 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5035 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5036 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5039 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5040 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5041 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5046 /* return a sensible default */
5049 TRACE("returning D3D_OK\n");
5053 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5057 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5059 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5060 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5061 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5063 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5068 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 PALETTEENTRY **palettes;
5074 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5076 if (PaletteNumber >= MAX_PALETTES) {
5077 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5078 return WINED3DERR_INVALIDCALL;
5081 if (PaletteNumber >= This->NumberOfPalettes) {
5082 NewSize = This->NumberOfPalettes;
5085 } while(PaletteNumber >= NewSize);
5086 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5088 ERR("Out of memory!\n");
5089 return E_OUTOFMEMORY;
5091 This->palettes = palettes;
5092 This->NumberOfPalettes = NewSize;
5095 if (!This->palettes[PaletteNumber]) {
5096 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5097 if (!This->palettes[PaletteNumber]) {
5098 ERR("Out of memory!\n");
5099 return E_OUTOFMEMORY;
5103 for (j = 0; j < 256; ++j) {
5104 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5105 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5106 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5107 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5109 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5110 TRACE("(%p) : returning\n", This);
5114 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5118 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5119 /* What happens in such situation isn't documented; Native seems to silently abort
5120 on such conditions. Return Invalid Call. */
5121 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5122 return WINED3DERR_INVALIDCALL;
5124 for (j = 0; j < 256; ++j) {
5125 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5126 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5127 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5128 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5130 TRACE("(%p) : returning\n", This);
5134 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5137 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5138 (tested with reference rasterizer). Return Invalid Call. */
5139 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5140 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5141 return WINED3DERR_INVALIDCALL;
5143 /*TODO: stateblocks */
5144 if (This->currentPalette != PaletteNumber) {
5145 This->currentPalette = PaletteNumber;
5146 dirtify_p8_texture_samplers(This);
5148 TRACE("(%p) : returning\n", This);
5152 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5154 if (PaletteNumber == NULL) {
5155 WARN("(%p) : returning Invalid Call\n", This);
5156 return WINED3DERR_INVALIDCALL;
5158 /*TODO: stateblocks */
5159 *PaletteNumber = This->currentPalette;
5160 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5164 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 FIXME("(%p) : stub\n", This);
5173 This->softwareVertexProcessing = bSoftware;
5178 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5183 FIXME("(%p) : stub\n", This);
5186 return This->softwareVertexProcessing;
5189 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5190 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5192 IWineD3DSwapChain *swapchain;
5195 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5196 iface, swapchain_idx, raster_status);
5198 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5201 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5205 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5206 IWineD3DSwapChain_Release(swapchain);
5209 WARN("Failed to get raster status, hr %#x.\n", hr);
5216 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5219 if(nSegments != 0.0f) {
5222 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5229 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5234 FIXME("iface %p stub!\n", iface);
5240 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5241 IWineD3DSurface *src_surface, const RECT *src_rect,
5242 IWineD3DSurface *dst_surface, const POINT *dst_point)
5244 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5245 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5247 const struct wined3d_format *src_format;
5248 const struct wined3d_format *dst_format;
5249 const struct wined3d_gl_info *gl_info;
5250 struct wined3d_context *context;
5251 const unsigned char *data;
5252 UINT update_w, update_h;
5253 CONVERT_TYPES convert;
5257 struct wined3d_format format;
5259 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5260 iface, src_surface, wine_dbgstr_rect(src_rect),
5261 dst_surface, wine_dbgstr_point(dst_point));
5263 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5265 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5266 src_surface, dst_surface);
5267 return WINED3DERR_INVALIDCALL;
5270 src_format = src_impl->resource.format;
5271 dst_format = dst_impl->resource.format;
5273 if (src_format->id != dst_format->id)
5275 WARN("Source and destination surfaces should have the same format.\n");
5276 return WINED3DERR_INVALIDCALL;
5279 dst_x = dst_point ? dst_point->x : 0;
5280 dst_y = dst_point ? dst_point->y : 0;
5282 /* This call loads the OpenGL surface directly, instead of copying the
5283 * surface to the destination's sysmem copy. If surface conversion is
5284 * needed, use BltFast instead to copy in sysmem and use regular surface
5286 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5287 if (convert != NO_CONVERSION || format.convert)
5288 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5290 context = context_acquire(This, NULL);
5291 gl_info = context->gl_info;
5294 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5295 checkGLcall("glActiveTextureARB");
5298 /* Make sure the surface is loaded and up to date */
5299 surface_internal_preload(dst_impl, SRGB_RGB);
5300 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5302 src_w = src_impl->currentDesc.Width;
5303 src_h = src_impl->currentDesc.Height;
5304 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5305 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5307 data = IWineD3DSurface_GetData(src_surface);
5308 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5312 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5314 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5315 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5316 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5320 data += (src_rect->top / src_format->block_height) * src_pitch;
5321 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5324 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5325 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5326 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5328 if (row_length == src_pitch)
5330 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5331 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5337 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5338 * can't use the unpack row length like below. */
5339 for (row = 0, y = dst_y; row < row_count; ++row)
5341 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5342 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5343 y += src_format->block_height;
5347 checkGLcall("glCompressedTexSubImage2DARB");
5353 data += src_rect->top * src_w * src_format->byte_count;
5354 data += src_rect->left * src_format->byte_count;
5357 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5358 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5359 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5361 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5362 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5363 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5364 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5365 checkGLcall("glTexSubImage2D");
5369 context_release(context);
5371 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5372 sampler = This->rev_tex_unit_map[0];
5373 if (sampler != WINED3D_UNMAPPED_STAGE)
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5381 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5383 struct WineD3DRectPatch *patch;
5384 GLenum old_primitive_type;
5388 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5390 if(!(Handle || pRectPatchInfo)) {
5391 /* TODO: Write a test for the return value, thus the FIXME */
5392 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5393 return WINED3DERR_INVALIDCALL;
5397 i = PATCHMAP_HASHFUNC(Handle);
5399 LIST_FOR_EACH(e, &This->patches[i]) {
5400 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5401 if(patch->Handle == Handle) {
5408 TRACE("Patch does not exist. Creating a new one\n");
5409 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5410 patch->Handle = Handle;
5411 list_add_head(&This->patches[i], &patch->entry);
5413 TRACE("Found existing patch %p\n", patch);
5416 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5417 * attributes we have to tesselate, read back, and draw. This needs a patch
5418 * management structure instance. Create one.
5420 * A possible improvement is to check if a vertex shader is used, and if not directly
5423 FIXME("Drawing an uncached patch. This is slow\n");
5424 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5427 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5428 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5429 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5431 TRACE("Tesselation density or patch info changed, retesselating\n");
5433 if(pRectPatchInfo) {
5434 patch->RectPatchInfo = *pRectPatchInfo;
5436 patch->numSegs[0] = pNumSegs[0];
5437 patch->numSegs[1] = pNumSegs[1];
5438 patch->numSegs[2] = pNumSegs[2];
5439 patch->numSegs[3] = pNumSegs[3];
5441 hr = tesselate_rectpatch(This, patch);
5443 WARN("Patch tesselation failed\n");
5445 /* Do not release the handle to store the params of the patch */
5447 HeapFree(GetProcessHeap(), 0, patch);
5453 This->currentPatch = patch;
5454 old_primitive_type = This->stateBlock->gl_primitive_type;
5455 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5456 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5457 This->stateBlock->gl_primitive_type = old_primitive_type;
5458 This->currentPatch = NULL;
5460 /* Destroy uncached patches */
5462 HeapFree(GetProcessHeap(), 0, patch->mem);
5463 HeapFree(GetProcessHeap(), 0, patch);
5468 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5469 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5471 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5472 iface, handle, segment_count, patch_info);
5477 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5480 struct WineD3DRectPatch *patch;
5482 TRACE("(%p) Handle(%d)\n", This, Handle);
5484 i = PATCHMAP_HASHFUNC(Handle);
5485 LIST_FOR_EACH(e, &This->patches[i]) {
5486 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5487 if(patch->Handle == Handle) {
5488 TRACE("Deleting patch %p\n", patch);
5489 list_remove(&patch->entry);
5490 HeapFree(GetProcessHeap(), 0, patch->mem);
5491 HeapFree(GetProcessHeap(), 0, patch);
5496 /* TODO: Write a test for the return value */
5497 FIXME("Attempt to destroy nonexistent patch\n");
5498 return WINED3DERR_INVALIDCALL;
5501 /* Do not call while under the GL lock. */
5502 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5503 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5505 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5507 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5508 iface, surface, wine_dbgstr_rect(rect),
5509 color->r, color->g, color->b, color->a);
5511 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5513 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5514 return WINED3DERR_INVALIDCALL;
5517 return surface_color_fill(s, rect, color);
5520 /* Do not call while under the GL lock. */
5521 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5522 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5524 IWineD3DResource *resource;
5527 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5530 ERR("Failed to get resource, hr %#x\n", hr);
5534 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5536 FIXME("Only supported on surface resources\n");
5537 IWineD3DResource_Release(resource);
5541 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5542 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5544 IWineD3DResource_Release(resource);
5547 /* rendertarget and depth stencil functions */
5548 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5549 DWORD render_target_idx, IWineD3DSurface **render_target)
5551 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5553 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5554 iface, render_target_idx, render_target);
5556 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5558 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5559 return WINED3DERR_INVALIDCALL;
5562 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5563 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5565 TRACE("Returning render target %p.\n", *render_target);
5570 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5571 IWineD3DSurface *front, IWineD3DSurface *back)
5573 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5574 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5575 IWineD3DSwapChainImpl *swapchain;
5578 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5580 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5582 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5586 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5588 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5589 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5590 return WINED3DERR_INVALIDCALL;
5595 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5597 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5598 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5599 return WINED3DERR_INVALIDCALL;
5602 if (!swapchain->back_buffers)
5604 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5605 if (!swapchain->back_buffers)
5607 ERR("Failed to allocate back buffer array memory.\n");
5608 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5609 return E_OUTOFMEMORY;
5614 if (swapchain->front_buffer != front_impl)
5616 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5618 if (swapchain->front_buffer)
5619 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5620 swapchain->front_buffer = front_impl;
5623 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5626 if (swapchain->back_buffers[0] != back_impl)
5628 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5630 if (swapchain->back_buffers[0])
5631 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5632 swapchain->back_buffers[0] = back_impl;
5636 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5637 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5638 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5639 swapchain->presentParms.BackBufferCount = 1;
5641 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5645 swapchain->presentParms.BackBufferCount = 0;
5646 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5647 swapchain->back_buffers = NULL;
5651 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5655 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5657 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5659 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5661 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5662 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5663 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5664 IWineD3DSurface_AddRef(*depth_stencil);
5669 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5670 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5672 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5673 IWineD3DSurfaceImpl *prev;
5675 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5676 iface, render_target_idx, render_target, set_viewport);
5678 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5680 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5681 return WINED3DERR_INVALIDCALL;
5684 prev = device->render_targets[render_target_idx];
5685 if (render_target == (IWineD3DSurface *)prev)
5687 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5691 /* Render target 0 can't be set to NULL. */
5692 if (!render_target && !render_target_idx)
5694 WARN("Trying to set render target 0 to NULL.\n");
5695 return WINED3DERR_INVALIDCALL;
5698 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5700 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5701 return WINED3DERR_INVALIDCALL;
5704 if (render_target) IWineD3DSurface_AddRef(render_target);
5705 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5706 /* Release after the assignment, to prevent device_resource_released()
5707 * from seeing the surface as still in use. */
5708 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5710 /* Render target 0 is special. */
5711 if (!render_target_idx && set_viewport)
5713 /* Set the viewport and scissor rectangles, if requested. Tests show
5714 * that stateblock recording is ignored, the change goes directly
5715 * into the primary stateblock. */
5716 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5717 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5718 device->stateBlock->viewport.X = 0;
5719 device->stateBlock->viewport.Y = 0;
5720 device->stateBlock->viewport.MaxZ = 1.0f;
5721 device->stateBlock->viewport.MinZ = 0.0f;
5722 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5724 device->stateBlock->scissorRect.top = 0;
5725 device->stateBlock->scissorRect.left = 0;
5726 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5727 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5728 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5734 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 IWineD3DSurfaceImpl *tmp;
5739 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5741 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5743 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5747 if (This->depth_stencil)
5749 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5750 || This->depth_stencil->Flags & SFLAG_DISCARD)
5752 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5753 This->depth_stencil->currentDesc.Width,
5754 This->depth_stencil->currentDesc.Height);
5755 if (This->depth_stencil == This->onscreen_depth_stencil)
5757 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5758 This->onscreen_depth_stencil = NULL;
5763 tmp = This->depth_stencil;
5764 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5765 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5766 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5768 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5770 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5779 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5780 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5783 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5784 WINED3DLOCKED_RECT lockedRect;
5786 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5787 iface, XHotSpot, YHotSpot, cursor_image);
5789 /* some basic validation checks */
5790 if (This->cursorTexture)
5792 struct wined3d_context *context = context_acquire(This, NULL);
5794 glDeleteTextures(1, &This->cursorTexture);
5796 context_release(context);
5797 This->cursorTexture = 0;
5800 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5801 This->haveHardwareCursor = TRUE;
5803 This->haveHardwareCursor = FALSE;
5807 WINED3DLOCKED_RECT rect;
5809 /* MSDN: Cursor must be A8R8G8B8 */
5810 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5812 WARN("surface %p has an invalid format.\n", cursor_image);
5813 return WINED3DERR_INVALIDCALL;
5816 /* MSDN: Cursor must be smaller than the display mode */
5817 if (s->currentDesc.Width > This->ddraw_width
5818 || s->currentDesc.Height > This->ddraw_height)
5820 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5821 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5822 return WINED3DERR_INVALIDCALL;
5825 if (!This->haveHardwareCursor) {
5826 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5828 /* Do not store the surface's pointer because the application may
5829 * release it after setting the cursor image. Windows doesn't
5830 * addref the set surface, so we can't do this either without
5831 * creating circular refcount dependencies. Copy out the gl texture
5834 This->cursorWidth = s->currentDesc.Width;
5835 This->cursorHeight = s->currentDesc.Height;
5836 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5838 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5839 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5840 struct wined3d_context *context;
5841 char *mem, *bits = rect.pBits;
5842 GLint intfmt = format->glInternal;
5843 GLint gl_format = format->glFormat;
5844 GLint type = format->glType;
5845 INT height = This->cursorHeight;
5846 INT width = This->cursorWidth;
5847 INT bpp = format->byte_count;
5851 /* Reformat the texture memory (pitch and width can be
5853 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5854 for(i = 0; i < height; i++)
5855 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5856 IWineD3DSurface_UnlockRect(cursor_image);
5858 context = context_acquire(This, NULL);
5862 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5864 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5865 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5868 /* Make sure that a proper texture unit is selected */
5869 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5870 checkGLcall("glActiveTextureARB");
5871 sampler = This->rev_tex_unit_map[0];
5872 if (sampler != WINED3D_UNMAPPED_STAGE)
5874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5876 /* Create a new cursor texture */
5877 glGenTextures(1, &This->cursorTexture);
5878 checkGLcall("glGenTextures");
5879 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5880 checkGLcall("glBindTexture");
5881 /* Copy the bitmap memory into the cursor texture */
5882 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5883 HeapFree(GetProcessHeap(), 0, mem);
5884 checkGLcall("glTexImage2D");
5886 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5888 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5889 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5894 context_release(context);
5898 FIXME("A cursor texture was not returned.\n");
5899 This->cursorTexture = 0;
5904 /* Draw a hardware cursor */
5905 ICONINFO cursorInfo;
5907 /* Create and clear maskBits because it is not needed for
5908 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5910 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5911 (s->currentDesc.Width * s->currentDesc.Height / 8));
5912 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5913 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5914 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5916 cursorInfo.fIcon = FALSE;
5917 cursorInfo.xHotspot = XHotSpot;
5918 cursorInfo.yHotspot = YHotSpot;
5919 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5920 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5921 IWineD3DSurface_UnlockRect(cursor_image);
5922 /* Create our cursor and clean up. */
5923 cursor = CreateIconIndirect(&cursorInfo);
5925 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5926 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5927 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5928 This->hardwareCursor = cursor;
5929 HeapFree(GetProcessHeap(), 0, maskBits);
5933 This->xHotSpot = XHotSpot;
5934 This->yHotSpot = YHotSpot;
5938 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5940 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5942 This->xScreenSpace = XScreenSpace;
5943 This->yScreenSpace = YScreenSpace;
5949 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5951 BOOL oldVisible = This->bCursorVisible;
5954 TRACE("(%p) : visible(%d)\n", This, bShow);
5957 * When ShowCursor is first called it should make the cursor appear at the OS's last
5958 * known cursor position. Because of this, some applications just repetitively call
5959 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5962 This->xScreenSpace = pt.x;
5963 This->yScreenSpace = pt.y;
5965 if (This->haveHardwareCursor) {
5966 This->bCursorVisible = bShow;
5968 SetCursor(This->hardwareCursor);
5974 if (This->cursorTexture)
5975 This->bCursorVisible = bShow;
5981 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5982 TRACE("checking resource %p for eviction\n", resource);
5983 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5984 TRACE("Evicting %p\n", resource);
5985 IWineD3DResource_UnLoad(resource);
5987 IWineD3DResource_Release(resource);
5991 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5993 TRACE("iface %p.\n", iface);
5995 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5996 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5997 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6002 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6004 IWineD3DDeviceImpl *device = surface->resource.device;
6005 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6007 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6008 if(surface->Flags & SFLAG_DIBSECTION) {
6009 /* Release the DC */
6010 SelectObject(surface->hDC, surface->dib.holdbitmap);
6011 DeleteDC(surface->hDC);
6012 /* Release the DIB section */
6013 DeleteObject(surface->dib.DIBsection);
6014 surface->dib.bitmap_data = NULL;
6015 surface->resource.allocatedMemory = NULL;
6016 surface->Flags &= ~SFLAG_DIBSECTION;
6018 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6019 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6020 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6021 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6023 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6024 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6026 surface->pow2Width = surface->pow2Height = 1;
6027 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6028 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6031 if (surface->texture_name)
6033 struct wined3d_context *context = context_acquire(device, NULL);
6035 glDeleteTextures(1, &surface->texture_name);
6037 context_release(context);
6038 surface->texture_name = 0;
6039 surface->Flags &= ~SFLAG_CLIENT;
6041 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6042 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6043 surface->Flags |= SFLAG_NONPOW2;
6045 surface->Flags &= ~SFLAG_NONPOW2;
6047 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6048 surface->resource.allocatedMemory = NULL;
6049 surface->resource.heapMemory = NULL;
6050 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6052 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6054 if (!surface_init_sysmem(surface))
6056 return E_OUTOFMEMORY;
6061 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6062 TRACE("Unloading resource %p\n", resource);
6063 IWineD3DResource_UnLoad(resource);
6064 IWineD3DResource_Release(resource);
6068 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6071 WINED3DDISPLAYMODE m;
6074 /* All Windowed modes are supported, as is leaving the current mode */
6075 if(pp->Windowed) return TRUE;
6076 if(!pp->BackBufferWidth) return TRUE;
6077 if(!pp->BackBufferHeight) return TRUE;
6079 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6080 for(i = 0; i < count; i++) {
6081 memset(&m, 0, sizeof(m));
6082 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6084 ERR("EnumAdapterModes failed\n");
6086 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6087 /* Mode found, it is supported */
6091 /* Mode not found -> not supported */
6095 /* Do not call while under the GL lock. */
6096 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6099 const struct wined3d_gl_info *gl_info;
6100 struct wined3d_context *context;
6101 IWineD3DBaseShaderImpl *shader;
6103 context = context_acquire(This, NULL);
6104 gl_info = context->gl_info;
6106 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6107 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6108 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6112 if(This->depth_blt_texture) {
6113 glDeleteTextures(1, &This->depth_blt_texture);
6114 This->depth_blt_texture = 0;
6116 if (This->depth_blt_rb) {
6117 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6118 This->depth_blt_rb = 0;
6119 This->depth_blt_rb_w = 0;
6120 This->depth_blt_rb_h = 0;
6124 This->blitter->free_private(iface);
6125 This->frag_pipe->free_private(iface);
6126 This->shader_backend->shader_free_private(iface);
6127 destroy_dummy_textures(This, gl_info);
6129 context_release(context);
6131 while (This->numContexts)
6133 context_destroy(This, This->contexts[0]);
6135 HeapFree(GetProcessHeap(), 0, swapchain->context);
6136 swapchain->context = NULL;
6137 swapchain->num_contexts = 0;
6140 /* Do not call while under the GL lock. */
6141 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6144 struct wined3d_context *context;
6146 IWineD3DSurfaceImpl *target;
6148 /* Recreate the primary swapchain's context */
6149 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6150 if (!swapchain->context)
6152 ERR("Failed to allocate memory for swapchain context array.\n");
6153 return E_OUTOFMEMORY;
6156 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6157 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6159 WARN("Failed to create context.\n");
6160 HeapFree(GetProcessHeap(), 0, swapchain->context);
6164 swapchain->context[0] = context;
6165 swapchain->num_contexts = 1;
6166 create_dummy_textures(This);
6167 context_release(context);
6169 hr = This->shader_backend->shader_alloc_private(iface);
6172 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6176 hr = This->frag_pipe->alloc_private(iface);
6179 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6180 This->shader_backend->shader_free_private(iface);
6184 hr = This->blitter->alloc_private(iface);
6187 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6188 This->frag_pipe->free_private(iface);
6189 This->shader_backend->shader_free_private(iface);
6196 context_acquire(This, NULL);
6197 destroy_dummy_textures(This, context->gl_info);
6198 context_release(context);
6199 context_destroy(This, context);
6200 HeapFree(GetProcessHeap(), 0, swapchain->context);
6201 swapchain->num_contexts = 0;
6205 /* Do not call while under the GL lock. */
6206 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6207 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6210 IWineD3DSwapChainImpl *swapchain;
6212 BOOL DisplayModeChanged = FALSE;
6213 WINED3DDISPLAYMODE mode;
6214 TRACE("(%p)\n", This);
6216 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6218 ERR("Failed to get the first implicit swapchain\n");
6222 if(!is_display_mode_supported(This, pPresentationParameters)) {
6223 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6224 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6225 pPresentationParameters->BackBufferHeight);
6226 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6227 return WINED3DERR_INVALIDCALL;
6230 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6231 * on an existing gl context, so there's no real need for recreation.
6233 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6235 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6237 TRACE("New params:\n");
6238 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6239 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6240 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6241 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6242 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6243 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6244 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6245 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6246 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6247 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6248 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6249 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6250 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6252 /* No special treatment of these parameters. Just store them */
6253 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6254 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6255 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6256 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6258 /* What to do about these? */
6259 if(pPresentationParameters->BackBufferCount != 0 &&
6260 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6261 ERR("Cannot change the back buffer count yet\n");
6263 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6264 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6265 ERR("Cannot change the back buffer format yet\n");
6267 if(pPresentationParameters->hDeviceWindow != NULL &&
6268 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6269 ERR("Cannot change the device window yet\n");
6271 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6275 TRACE("Creating the depth stencil buffer\n");
6277 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6278 pPresentationParameters->BackBufferWidth,
6279 pPresentationParameters->BackBufferHeight,
6280 pPresentationParameters->AutoDepthStencilFormat,
6281 pPresentationParameters->MultiSampleType,
6282 pPresentationParameters->MultiSampleQuality,
6284 (IWineD3DSurface **)&This->auto_depth_stencil);
6287 ERR("Failed to create the depth stencil buffer\n");
6288 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6289 return WINED3DERR_INVALIDCALL;
6293 if (This->onscreen_depth_stencil)
6295 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6296 This->onscreen_depth_stencil = NULL;
6299 /* Reset the depth stencil */
6300 if (pPresentationParameters->EnableAutoDepthStencil)
6301 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6303 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6305 TRACE("Resetting stateblock\n");
6306 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6307 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6309 delete_opengl_contexts(iface, swapchain);
6311 if(pPresentationParameters->Windowed) {
6312 mode.Width = swapchain->orig_width;
6313 mode.Height = swapchain->orig_height;
6314 mode.RefreshRate = 0;
6315 mode.Format = swapchain->presentParms.BackBufferFormat;
6317 mode.Width = pPresentationParameters->BackBufferWidth;
6318 mode.Height = pPresentationParameters->BackBufferHeight;
6319 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6320 mode.Format = swapchain->presentParms.BackBufferFormat;
6323 /* Should Width == 800 && Height == 0 set 800x600? */
6324 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6325 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6326 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6330 if(!pPresentationParameters->Windowed) {
6331 DisplayModeChanged = TRUE;
6333 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6334 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6336 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6339 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6343 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6345 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6352 if (This->auto_depth_stencil)
6354 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6357 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6363 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6364 || DisplayModeChanged)
6366 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6368 if (!pPresentationParameters->Windowed)
6370 if(swapchain->presentParms.Windowed) {
6371 /* switch from windowed to fs */
6372 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6373 pPresentationParameters->BackBufferHeight);
6375 /* Fullscreen -> fullscreen mode change */
6376 MoveWindow(swapchain->device_window, 0, 0,
6377 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6381 else if (!swapchain->presentParms.Windowed)
6383 /* Fullscreen -> windowed switch */
6384 swapchain_restore_fullscreen_window(swapchain);
6386 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6387 } else if(!pPresentationParameters->Windowed) {
6388 DWORD style = This->style, exStyle = This->exStyle;
6389 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6390 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6391 * Reset to clear up their mess. Guild Wars also loses the device during that.
6395 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6396 pPresentationParameters->BackBufferHeight);
6397 This->style = style;
6398 This->exStyle = exStyle;
6401 /* Note: No parent needed for initial internal stateblock */
6402 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6403 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6404 else TRACE("Created stateblock %p\n", This->stateBlock);
6405 This->updateStateBlock = This->stateBlock;
6406 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6408 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6410 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6413 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6416 GetClientRect(swapchain->win_handle, &client_rect);
6418 if(!swapchain->presentParms.BackBufferCount)
6420 TRACE("Single buffered rendering\n");
6421 swapchain->render_to_fbo = FALSE;
6423 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6424 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6426 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6427 swapchain->presentParms.BackBufferWidth,
6428 swapchain->presentParms.BackBufferHeight,
6429 client_rect.right, client_rect.bottom);
6430 swapchain->render_to_fbo = TRUE;
6434 TRACE("Rendering directly to GL_BACK\n");
6435 swapchain->render_to_fbo = FALSE;
6439 hr = create_primary_opengl_context(iface, swapchain);
6440 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6442 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6448 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6450 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6452 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6458 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6460 TRACE("(%p) : pParameters %p\n", This, pParameters);
6462 *pParameters = This->createParms;
6466 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6467 IWineD3DSwapChain *swapchain;
6469 TRACE("Relaying to swapchain\n");
6471 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6472 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6473 IWineD3DSwapChain_Release(swapchain);
6477 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6478 IWineD3DSwapChain *swapchain;
6480 TRACE("Relaying to swapchain\n");
6482 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6483 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6484 IWineD3DSwapChain_Release(swapchain);
6489 /** ********************************************************
6490 * Notification functions
6491 ** ********************************************************/
6492 /** This function must be called in the release of a resource when ref == 0,
6493 * the contents of resource must still be correct,
6494 * any handles to other resource held by the caller must be closed
6495 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6496 *****************************************************/
6497 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6499 TRACE("(%p) : Adding resource %p\n", This, resource);
6501 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6504 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6506 TRACE("(%p) : Removing resource %p\n", This, resource);
6508 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6511 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6513 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6516 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6518 context_resource_released(device, resource, type);
6522 case WINED3DRTYPE_SURFACE:
6523 if (!device->d3d_initialized) break;
6525 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6527 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6529 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6530 device->render_targets[i] = NULL;
6534 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6536 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6537 device->depth_stencil = NULL;
6541 case WINED3DRTYPE_TEXTURE:
6542 case WINED3DRTYPE_CUBETEXTURE:
6543 case WINED3DRTYPE_VOLUMETEXTURE:
6544 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6546 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6548 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6549 resource, device->stateBlock, i);
6550 device->stateBlock->textures[i] = NULL;
6553 if (device->updateStateBlock != device->stateBlock
6554 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6556 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6557 resource, device->updateStateBlock, i);
6558 device->updateStateBlock->textures[i] = NULL;
6563 case WINED3DRTYPE_BUFFER:
6564 for (i = 0; i < MAX_STREAMS; ++i)
6566 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6568 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6569 resource, device->stateBlock, i);
6570 device->stateBlock->streamSource[i] = NULL;
6573 if (device->updateStateBlock != device->stateBlock
6574 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6576 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6577 resource, device->updateStateBlock, i);
6578 device->updateStateBlock->streamSource[i] = NULL;
6583 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6585 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6586 resource, device->stateBlock);
6587 device->stateBlock->pIndexData = NULL;
6590 if (device->updateStateBlock != device->stateBlock
6591 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6593 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6594 resource, device->updateStateBlock);
6595 device->updateStateBlock->pIndexData = NULL;
6603 /* Remove the resource from the resourceStore */
6604 device_resource_remove(device, resource);
6606 TRACE("Resource released.\n");
6609 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6611 IWineD3DResourceImpl *resource, *cursor;
6613 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6615 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6616 TRACE("enumerating resource %p\n", resource);
6617 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6618 ret = pCallback((IWineD3DResource *) resource, pData);
6619 if(ret == S_FALSE) {
6620 TRACE("Canceling enumeration\n");
6627 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6630 IWineD3DResourceImpl *resource;
6632 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6634 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6635 if (type == WINED3DRTYPE_SURFACE)
6637 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6639 TRACE("Found surface %p for dc %p.\n", resource, dc);
6640 *surface = (IWineD3DSurface *)resource;
6646 return WINED3DERR_INVALIDCALL;
6649 /**********************************************************
6650 * IWineD3DDevice VTbl follows
6651 **********************************************************/
6653 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6655 /*** IUnknown methods ***/
6656 IWineD3DDeviceImpl_QueryInterface,
6657 IWineD3DDeviceImpl_AddRef,
6658 IWineD3DDeviceImpl_Release,
6659 /*** IWineD3DDevice methods ***/
6660 /*** Creation methods**/
6661 IWineD3DDeviceImpl_CreateBuffer,
6662 IWineD3DDeviceImpl_CreateVertexBuffer,
6663 IWineD3DDeviceImpl_CreateIndexBuffer,
6664 IWineD3DDeviceImpl_CreateStateBlock,
6665 IWineD3DDeviceImpl_CreateSurface,
6666 IWineD3DDeviceImpl_CreateRendertargetView,
6667 IWineD3DDeviceImpl_CreateTexture,
6668 IWineD3DDeviceImpl_CreateVolumeTexture,
6669 IWineD3DDeviceImpl_CreateVolume,
6670 IWineD3DDeviceImpl_CreateCubeTexture,
6671 IWineD3DDeviceImpl_CreateQuery,
6672 IWineD3DDeviceImpl_CreateSwapChain,
6673 IWineD3DDeviceImpl_CreateVertexDeclaration,
6674 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6675 IWineD3DDeviceImpl_CreateVertexShader,
6676 IWineD3DDeviceImpl_CreateGeometryShader,
6677 IWineD3DDeviceImpl_CreatePixelShader,
6678 IWineD3DDeviceImpl_CreatePalette,
6679 /*** Odd functions **/
6680 IWineD3DDeviceImpl_Init3D,
6681 IWineD3DDeviceImpl_InitGDI,
6682 IWineD3DDeviceImpl_Uninit3D,
6683 IWineD3DDeviceImpl_UninitGDI,
6684 IWineD3DDeviceImpl_SetMultithreaded,
6685 IWineD3DDeviceImpl_EvictManagedResources,
6686 IWineD3DDeviceImpl_GetAvailableTextureMem,
6687 IWineD3DDeviceImpl_GetBackBuffer,
6688 IWineD3DDeviceImpl_GetCreationParameters,
6689 IWineD3DDeviceImpl_GetDeviceCaps,
6690 IWineD3DDeviceImpl_GetDirect3D,
6691 IWineD3DDeviceImpl_GetDisplayMode,
6692 IWineD3DDeviceImpl_SetDisplayMode,
6693 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6694 IWineD3DDeviceImpl_GetRasterStatus,
6695 IWineD3DDeviceImpl_GetSwapChain,
6696 IWineD3DDeviceImpl_Reset,
6697 IWineD3DDeviceImpl_SetDialogBoxMode,
6698 IWineD3DDeviceImpl_SetCursorProperties,
6699 IWineD3DDeviceImpl_SetCursorPosition,
6700 IWineD3DDeviceImpl_ShowCursor,
6701 /*** Getters and setters **/
6702 IWineD3DDeviceImpl_SetClipPlane,
6703 IWineD3DDeviceImpl_GetClipPlane,
6704 IWineD3DDeviceImpl_SetClipStatus,
6705 IWineD3DDeviceImpl_GetClipStatus,
6706 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6707 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6708 IWineD3DDeviceImpl_SetDepthStencilSurface,
6709 IWineD3DDeviceImpl_GetDepthStencilSurface,
6710 IWineD3DDeviceImpl_SetGammaRamp,
6711 IWineD3DDeviceImpl_GetGammaRamp,
6712 IWineD3DDeviceImpl_SetIndexBuffer,
6713 IWineD3DDeviceImpl_GetIndexBuffer,
6714 IWineD3DDeviceImpl_SetBaseVertexIndex,
6715 IWineD3DDeviceImpl_GetBaseVertexIndex,
6716 IWineD3DDeviceImpl_SetLight,
6717 IWineD3DDeviceImpl_GetLight,
6718 IWineD3DDeviceImpl_SetLightEnable,
6719 IWineD3DDeviceImpl_GetLightEnable,
6720 IWineD3DDeviceImpl_SetMaterial,
6721 IWineD3DDeviceImpl_GetMaterial,
6722 IWineD3DDeviceImpl_SetNPatchMode,
6723 IWineD3DDeviceImpl_GetNPatchMode,
6724 IWineD3DDeviceImpl_SetPaletteEntries,
6725 IWineD3DDeviceImpl_GetPaletteEntries,
6726 IWineD3DDeviceImpl_SetPixelShader,
6727 IWineD3DDeviceImpl_GetPixelShader,
6728 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6729 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6730 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6731 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6732 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6733 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6734 IWineD3DDeviceImpl_SetRenderState,
6735 IWineD3DDeviceImpl_GetRenderState,
6736 IWineD3DDeviceImpl_SetRenderTarget,
6737 IWineD3DDeviceImpl_GetRenderTarget,
6738 IWineD3DDeviceImpl_SetFrontBackBuffers,
6739 IWineD3DDeviceImpl_SetSamplerState,
6740 IWineD3DDeviceImpl_GetSamplerState,
6741 IWineD3DDeviceImpl_SetScissorRect,
6742 IWineD3DDeviceImpl_GetScissorRect,
6743 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6744 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6745 IWineD3DDeviceImpl_SetStreamSource,
6746 IWineD3DDeviceImpl_GetStreamSource,
6747 IWineD3DDeviceImpl_SetStreamSourceFreq,
6748 IWineD3DDeviceImpl_GetStreamSourceFreq,
6749 IWineD3DDeviceImpl_SetTexture,
6750 IWineD3DDeviceImpl_GetTexture,
6751 IWineD3DDeviceImpl_SetTextureStageState,
6752 IWineD3DDeviceImpl_GetTextureStageState,
6753 IWineD3DDeviceImpl_SetTransform,
6754 IWineD3DDeviceImpl_GetTransform,
6755 IWineD3DDeviceImpl_SetVertexDeclaration,
6756 IWineD3DDeviceImpl_GetVertexDeclaration,
6757 IWineD3DDeviceImpl_SetVertexShader,
6758 IWineD3DDeviceImpl_GetVertexShader,
6759 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6760 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6761 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6762 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6763 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6764 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6765 IWineD3DDeviceImpl_SetViewport,
6766 IWineD3DDeviceImpl_GetViewport,
6767 IWineD3DDeviceImpl_MultiplyTransform,
6768 IWineD3DDeviceImpl_ValidateDevice,
6769 IWineD3DDeviceImpl_ProcessVertices,
6770 /*** State block ***/
6771 IWineD3DDeviceImpl_BeginStateBlock,
6772 IWineD3DDeviceImpl_EndStateBlock,
6773 /*** Scene management ***/
6774 IWineD3DDeviceImpl_BeginScene,
6775 IWineD3DDeviceImpl_EndScene,
6776 IWineD3DDeviceImpl_Present,
6777 IWineD3DDeviceImpl_Clear,
6778 IWineD3DDeviceImpl_ClearRendertargetView,
6780 IWineD3DDeviceImpl_SetPrimitiveType,
6781 IWineD3DDeviceImpl_GetPrimitiveType,
6782 IWineD3DDeviceImpl_DrawPrimitive,
6783 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6784 IWineD3DDeviceImpl_DrawPrimitiveUP,
6785 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6786 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6787 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6788 IWineD3DDeviceImpl_DrawRectPatch,
6789 IWineD3DDeviceImpl_DrawTriPatch,
6790 IWineD3DDeviceImpl_DeletePatch,
6791 IWineD3DDeviceImpl_ColorFill,
6792 IWineD3DDeviceImpl_UpdateTexture,
6793 IWineD3DDeviceImpl_UpdateSurface,
6794 IWineD3DDeviceImpl_GetFrontBufferData,
6795 /*** object tracking ***/
6796 IWineD3DDeviceImpl_EnumResources,
6797 IWineD3DDeviceImpl_GetSurfaceFromDC,
6798 IWineD3DDeviceImpl_AcquireFocusWindow,
6799 IWineD3DDeviceImpl_ReleaseFocusWindow,
6802 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6803 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6804 IWineD3DDeviceParent *device_parent)
6806 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6807 const struct fragment_pipeline *fragment_pipeline;
6808 struct shader_caps shader_caps;
6809 struct fragment_caps ffp_caps;
6810 WINED3DDISPLAYMODE mode;
6814 device->lpVtbl = &IWineD3DDevice_Vtbl;
6816 device->wined3d = (IWineD3D *)wined3d;
6817 IWineD3D_AddRef(device->wined3d);
6818 device->adapter = wined3d->adapter_count ? adapter : NULL;
6819 device->device_parent = device_parent;
6820 list_init(&device->resources);
6821 list_init(&device->shaders);
6823 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6824 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6826 /* Get the initial screen setup for ddraw. */
6827 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6830 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6831 IWineD3D_Release(device->wined3d);
6834 device->ddraw_width = mode.Width;
6835 device->ddraw_height = mode.Height;
6836 device->ddraw_format = mode.Format;
6838 /* Save the creation parameters. */
6839 device->createParms.AdapterOrdinal = adapter_idx;
6840 device->createParms.DeviceType = device_type;
6841 device->createParms.hFocusWindow = focus_window;
6842 device->createParms.BehaviorFlags = flags;
6844 device->devType = device_type;
6845 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6847 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6848 device->shader_backend = adapter->shader_backend;
6850 if (device->shader_backend)
6852 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6853 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6854 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6855 device->vs_clipping = shader_caps.VSClipping;
6857 fragment_pipeline = adapter->fragment_pipe;
6858 device->frag_pipe = fragment_pipeline;
6859 if (fragment_pipeline)
6861 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6862 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6864 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6865 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6868 ERR("Failed to compile state table, hr %#x.\n", hr);
6869 IWineD3D_Release(device->wined3d);
6873 device->blitter = adapter->blitter;
6879 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6880 DWORD rep = This->StateTable[state].representative;
6881 struct wined3d_context *context;
6886 for(i = 0; i < This->numContexts; i++) {
6887 context = This->contexts[i];
6888 if(isStateDirty(context, rep)) continue;
6890 context->dirtyArray[context->numDirtyEntries++] = rep;
6891 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6892 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6893 context->isStateDirty[idx] |= (1 << shift);
6897 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6899 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6900 *width = context->current_rt->pow2Width;
6901 *height = context->current_rt->pow2Height;
6904 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6906 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6907 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6908 * current context's drawable, which is the size of the back buffer of the swapchain
6909 * the active context belongs to. */
6910 *width = swapchain->presentParms.BackBufferWidth;
6911 *height = swapchain->presentParms.BackBufferHeight;
6914 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6915 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6917 if (device->filter_messages)
6919 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6920 window, message, wparam, lparam);
6921 return DefWindowProcW(window, message, wparam, lparam);
6924 if (message == WM_DESTROY)
6926 TRACE("unregister window %p.\n", window);
6927 wined3d_unregister_window(window);
6929 if (device->focus_window == window) device->focus_window = NULL;
6930 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6933 return CallWindowProcW(proc, window, message, wparam, lparam);