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 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3610 if (NULL == ppShader) {
3611 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3612 return WINED3DERR_INVALIDCALL;
3615 *ppShader = This->stateBlock->pixelShader;
3616 if (NULL != *ppShader) {
3617 IWineD3DPixelShader_AddRef(*ppShader);
3619 TRACE("(%p) : returning %p\n", This, *ppShader);
3623 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3624 IWineD3DDevice *iface,
3626 CONST BOOL *srcData,
3629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3630 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3632 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3633 iface, srcData, start, count);
3635 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3637 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3638 for (i = 0; i < cnt; i++)
3639 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3641 for (i = start; i < cnt + start; ++i) {
3642 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3645 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3650 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3651 IWineD3DDevice *iface,
3656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3657 int cnt = min(count, MAX_CONST_B - start);
3659 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3660 iface, dstData, start, count);
3662 if (dstData == NULL || cnt < 0)
3663 return WINED3DERR_INVALIDCALL;
3665 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3669 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3670 IWineD3DDevice *iface,
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3678 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3679 iface, srcData, start, count);
3681 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3683 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3684 for (i = 0; i < cnt; i++)
3685 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3686 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3688 for (i = start; i < cnt + start; ++i) {
3689 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3692 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3697 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3698 IWineD3DDevice *iface,
3703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 int cnt = min(count, MAX_CONST_I - start);
3706 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3707 iface, dstData, start, count);
3709 if (dstData == NULL || cnt < 0)
3710 return WINED3DERR_INVALIDCALL;
3712 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3716 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3717 IWineD3DDevice *iface,
3719 CONST float *srcData,
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3725 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3726 iface, srcData, start, count);
3728 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3729 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3730 return WINED3DERR_INVALIDCALL;
3732 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3734 for (i = 0; i < count; i++)
3735 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3736 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3739 if (!This->isRecordingState)
3741 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3745 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3746 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3752 IWineD3DDevice *iface,
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 int cnt = min(count, This->d3d_pshader_constantF - start);
3760 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3761 iface, dstData, start, count);
3763 if (dstData == NULL || cnt < 0)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3770 /* Context activation is done by the caller. */
3771 /* Do not call while under the GL lock. */
3772 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3773 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3774 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3777 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3778 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3781 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3785 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3787 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3790 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3792 ERR("Source has no position mask\n");
3793 return WINED3DERR_INVALIDCALL;
3796 if (!dest->resource.allocatedMemory)
3797 buffer_get_sysmem(dest, gl_info);
3799 /* Get a pointer into the destination vbo(create one if none exists) and
3800 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3802 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3804 dest->flags |= WINED3D_BUFFER_CREATEBO;
3805 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3808 if (dest->buffer_object)
3810 unsigned char extrabytes = 0;
3811 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3812 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3813 * this may write 4 extra bytes beyond the area that should be written
3815 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3816 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3817 if(!dest_conv_addr) {
3818 ERR("Out of memory\n");
3819 /* Continue without storing converted vertices */
3821 dest_conv = dest_conv_addr;
3825 * a) WINED3DRS_CLIPPING is enabled
3826 * b) WINED3DVOP_CLIP is passed
3828 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3829 static BOOL warned = FALSE;
3831 * The clipping code is not quite correct. Some things need
3832 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3833 * so disable clipping for now.
3834 * (The graphics in Half-Life are broken, and my processvertices
3835 * test crashes with IDirect3DDevice3)
3841 FIXME("Clipping is broken and disabled for now\n");
3843 } else doClip = FALSE;
3844 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3846 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3849 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3850 WINED3DTS_PROJECTION,
3852 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3853 WINED3DTS_WORLDMATRIX(0),
3856 TRACE("View mat:\n");
3857 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);
3858 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);
3859 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);
3860 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);
3862 TRACE("Proj mat:\n");
3863 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);
3864 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);
3865 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);
3866 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);
3868 TRACE("World mat:\n");
3869 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);
3870 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);
3871 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);
3872 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);
3874 /* Get the viewport */
3875 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3876 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3877 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3879 multiply_matrix(&mat,&view_mat,&world_mat);
3880 multiply_matrix(&mat,&proj_mat,&mat);
3882 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3884 for (i = 0; i < dwCount; i+= 1) {
3885 unsigned int tex_index;
3887 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3888 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3889 /* The position first */
3890 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3891 const float *p = (const float *)(element->data + i * element->stride);
3893 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3895 /* Multiplication with world, view and projection matrix */
3896 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);
3897 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);
3898 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);
3899 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);
3901 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3903 /* WARNING: The following things are taken from d3d7 and were not yet checked
3904 * against d3d8 or d3d9!
3907 /* Clipping conditions: From msdn
3909 * A vertex is clipped if it does not match the following requirements
3913 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3915 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3916 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3921 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3922 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3925 /* "Normal" viewport transformation (not clipped)
3926 * 1) The values are divided by rhw
3927 * 2) The y axis is negative, so multiply it with -1
3928 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3929 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3930 * 4) Multiply x with Width/2 and add Width/2
3931 * 5) The same for the height
3932 * 6) Add the viewpoint X and Y to the 2D coordinates and
3933 * The minimum Z value to z
3934 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3936 * Well, basically it's simply a linear transformation into viewport
3948 z *= vp.MaxZ - vp.MinZ;
3950 x += vp.Width / 2 + vp.X;
3951 y += vp.Height / 2 + vp.Y;
3956 /* That vertex got clipped
3957 * Contrary to OpenGL it is not dropped completely, it just
3958 * undergoes a different calculation.
3960 TRACE("Vertex got clipped\n");
3967 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3968 * outside of the main vertex buffer memory. That needs some more
3973 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3976 ( (float *) dest_ptr)[0] = x;
3977 ( (float *) dest_ptr)[1] = y;
3978 ( (float *) dest_ptr)[2] = z;
3979 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3981 dest_ptr += 3 * sizeof(float);
3983 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3984 dest_ptr += sizeof(float);
3989 ( (float *) dest_conv)[0] = x * w;
3990 ( (float *) dest_conv)[1] = y * w;
3991 ( (float *) dest_conv)[2] = z * w;
3992 ( (float *) dest_conv)[3] = w;
3994 dest_conv += 3 * sizeof(float);
3996 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3997 dest_conv += sizeof(float);
4001 if (DestFVF & WINED3DFVF_PSIZE) {
4002 dest_ptr += sizeof(DWORD);
4003 if(dest_conv) dest_conv += sizeof(DWORD);
4005 if (DestFVF & WINED3DFVF_NORMAL) {
4006 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4007 const float *normal = (const float *)(element->data + i * element->stride);
4008 /* AFAIK this should go into the lighting information */
4009 FIXME("Didn't expect the destination to have a normal\n");
4010 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4012 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4016 if (DestFVF & WINED3DFVF_DIFFUSE) {
4017 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4018 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4019 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4021 static BOOL warned = FALSE;
4024 ERR("No diffuse color in source, but destination has one\n");
4028 *( (DWORD *) dest_ptr) = 0xffffffff;
4029 dest_ptr += sizeof(DWORD);
4032 *( (DWORD *) dest_conv) = 0xffffffff;
4033 dest_conv += sizeof(DWORD);
4037 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4039 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4040 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4041 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4042 dest_conv += sizeof(DWORD);
4047 if (DestFVF & WINED3DFVF_SPECULAR)
4049 /* What's the color value in the feedback buffer? */
4050 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4051 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4052 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4054 static BOOL warned = FALSE;
4057 ERR("No specular color in source, but destination has one\n");
4061 *( (DWORD *) dest_ptr) = 0xFF000000;
4062 dest_ptr += sizeof(DWORD);
4065 *( (DWORD *) dest_conv) = 0xFF000000;
4066 dest_conv += sizeof(DWORD);
4070 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4072 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4073 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4074 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4075 dest_conv += sizeof(DWORD);
4080 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4081 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4082 const float *tex_coord = (const float *)(element->data + i * element->stride);
4083 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4085 ERR("No source texture, but destination requests one\n");
4086 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4087 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4090 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4092 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4102 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4103 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4104 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4105 dwCount * get_flexible_vertex_size(DestFVF),
4107 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4111 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4116 #undef copy_and_next
4118 /* Do not call while under the GL lock. */
4119 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4120 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 struct wined3d_stream_info stream_info;
4125 const struct wined3d_gl_info *gl_info;
4126 struct wined3d_context *context;
4127 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4130 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4133 ERR("Output vertex declaration not implemented yet\n");
4136 /* Need any context to write to the vbo. */
4137 context = context_acquire(This, NULL);
4138 gl_info = context->gl_info;
4140 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4141 * control the streamIsUP flag, thus restore it afterwards.
4143 This->stateBlock->streamIsUP = FALSE;
4144 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4145 This->stateBlock->streamIsUP = streamWasUP;
4147 if(vbo || SrcStartIndex) {
4149 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4150 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4152 * Also get the start index in, but only loop over all elements if there's something to add at all.
4154 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4156 struct wined3d_stream_info_element *e;
4158 if (!(stream_info.use_map & (1 << i))) continue;
4160 e = &stream_info.elements[i];
4161 if (e->buffer_object)
4163 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4164 e->buffer_object = 0;
4165 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4167 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4168 vb->buffer_object = 0;
4171 if (e->data) e->data += e->stride * SrcStartIndex;
4175 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4176 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4178 context_release(context);
4184 * Get / Set Texture Stage States
4185 * TODO: Verify against dx9 definitions
4187 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4189 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4190 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4192 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4194 if (Stage >= gl_info->limits.texture_stages)
4196 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4197 Stage, gl_info->limits.texture_stages - 1);
4201 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4202 This->updateStateBlock->textureState[Stage][Type] = Value;
4204 if (This->isRecordingState) {
4205 TRACE("Recording... not performing anything\n");
4209 /* Checked after the assignments to allow proper stateblock recording */
4210 if(oldValue == Value) {
4211 TRACE("App is setting the old value over, nothing to do\n");
4215 if(Stage > This->stateBlock->lowest_disabled_stage &&
4216 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4217 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4218 * Changes in other states are important on disabled stages too
4223 if(Type == WINED3DTSS_COLOROP) {
4226 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4227 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4228 * they have to be disabled
4230 * The current stage is dirtified below.
4232 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4233 TRACE("Additionally dirtifying stage %u\n", i);
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4236 This->stateBlock->lowest_disabled_stage = Stage;
4237 TRACE("New lowest disabled: %u\n", Stage);
4238 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4239 /* Previously disabled stage enabled. Stages above it may need enabling
4240 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4241 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4243 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4246 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4248 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4251 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4254 This->stateBlock->lowest_disabled_stage = i;
4255 TRACE("New lowest disabled: %u\n", i);
4259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4264 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4266 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4267 *pValue = This->updateStateBlock->textureState[Stage][Type];
4274 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4275 DWORD stage, IWineD3DBaseTexture *texture)
4277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4278 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4279 IWineD3DBaseTexture *prev;
4281 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4283 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4284 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4286 /* Windows accepts overflowing this array... we do not. */
4287 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4289 WARN("Ignoring invalid stage %u.\n", stage);
4293 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4294 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4296 WARN("Rejecting attempt to set scratch texture.\n");
4297 return WINED3DERR_INVALIDCALL;
4300 This->updateStateBlock->changed.textures |= 1 << stage;
4302 prev = This->updateStateBlock->textures[stage];
4303 TRACE("Previous texture %p.\n", prev);
4305 if (texture == prev)
4307 TRACE("App is setting the same texture again, nothing to do.\n");
4311 TRACE("Setting new texture to %p.\n", texture);
4312 This->updateStateBlock->textures[stage] = texture;
4314 if (This->isRecordingState)
4316 TRACE("Recording... not performing anything\n");
4318 if (texture) IWineD3DBaseTexture_AddRef(texture);
4319 if (prev) IWineD3DBaseTexture_Release(prev);
4326 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4327 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4328 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4330 IWineD3DBaseTexture_AddRef(texture);
4332 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4337 if (!prev && stage < gl_info->limits.texture_stages)
4339 /* The source arguments for color and alpha ops have different
4340 * meanings when a NULL texture is bound, so the COLOROP and
4341 * ALPHAOP have to be dirtified. */
4342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4346 if (bind_count == 1) t->baseTexture.sampler = stage;
4351 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4352 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4354 IWineD3DBaseTexture_Release(prev);
4356 if (!texture && stage < gl_info->limits.texture_stages)
4358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4362 if (bind_count && t->baseTexture.sampler == stage)
4366 /* Search for other stages the texture is bound to. Shouldn't
4367 * happen if applications bind textures to a single stage only. */
4368 TRACE("Searching for other stages the texture is bound to.\n");
4369 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4371 if (This->updateStateBlock->textures[i] == prev)
4373 TRACE("Texture is also bound to stage %u.\n", i);
4374 t->baseTexture.sampler = i;
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4386 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4389 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4391 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4392 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4395 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4396 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4397 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4400 *ppTexture=This->stateBlock->textures[Stage];
4402 IWineD3DBaseTexture_AddRef(*ppTexture);
4404 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4412 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4413 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4415 IWineD3DSwapChain *swapchain;
4418 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4419 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4421 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4424 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4428 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4429 IWineD3DSwapChain_Release(swapchain);
4432 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4439 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 WARN("(%p) : stub, calling idirect3d for now\n", This);
4442 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4445 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 IWineD3DSwapChain *swapChain;
4450 if(iSwapChain > 0) {
4451 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4452 if (hr == WINED3D_OK) {
4453 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4454 IWineD3DSwapChain_Release(swapChain);
4456 FIXME("(%p) Error getting display mode\n", This);
4459 /* Don't read the real display mode,
4460 but return the stored mode instead. X11 can't change the color
4461 depth, and some apps are pretty angry if they SetDisplayMode from
4462 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4464 Also don't relay to the swapchain because with ddraw it's possible
4465 that there isn't a swapchain at all */
4466 pMode->Width = This->ddraw_width;
4467 pMode->Height = This->ddraw_height;
4468 pMode->Format = This->ddraw_format;
4469 pMode->RefreshRate = 0;
4477 * Stateblock related functions
4480 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4482 IWineD3DStateBlock *stateblock;
4485 TRACE("(%p)\n", This);
4487 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4489 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4490 if (FAILED(hr)) return hr;
4492 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4493 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4494 This->isRecordingState = TRUE;
4496 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4501 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4505 if (!This->isRecordingState) {
4506 WARN("(%p) not recording! returning error\n", This);
4507 *ppStateBlock = NULL;
4508 return WINED3DERR_INVALIDCALL;
4511 stateblock_init_contained_states(object);
4513 *ppStateBlock = (IWineD3DStateBlock*) object;
4514 This->isRecordingState = FALSE;
4515 This->updateStateBlock = This->stateBlock;
4516 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4517 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4518 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4523 * Scene related functions
4525 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4526 /* At the moment we have no need for any functionality at the beginning
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("(%p)\n", This);
4532 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4533 return WINED3DERR_INVALIDCALL;
4535 This->inScene = TRUE;
4539 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 struct wined3d_context *context;
4544 TRACE("(%p)\n", This);
4546 if(!This->inScene) {
4547 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4548 return WINED3DERR_INVALIDCALL;
4551 context = context_acquire(This, NULL);
4552 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4554 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4556 context_release(context);
4558 This->inScene = FALSE;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4563 const RECT *pSourceRect, const RECT *pDestRect,
4564 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4566 IWineD3DSwapChain *swapChain = NULL;
4568 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4570 TRACE("iface %p.\n", iface);
4572 for(i = 0 ; i < swapchains ; i ++) {
4574 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4575 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4576 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4577 IWineD3DSwapChain_Release(swapChain);
4583 /* Do not call while under the GL lock. */
4584 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4585 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4587 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4588 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4591 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4592 iface, rect_count, rects, flags, color, depth, stencil);
4594 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4596 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4597 /* TODO: What about depth stencil buffers without stencil bits? */
4598 return WINED3DERR_INVALIDCALL;
4601 device_get_draw_rect(device, &draw_rect);
4603 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4604 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4611 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4612 WINED3DPRIMITIVETYPE primitive_type)
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4618 This->updateStateBlock->changed.primitive_type = TRUE;
4619 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4622 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4623 WINED3DPRIMITIVETYPE *primitive_type)
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4629 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4631 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4634 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4640 if(!This->stateBlock->vertexDecl) {
4641 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4642 return WINED3DERR_INVALIDCALL;
4645 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4646 if(This->stateBlock->streamIsUP) {
4647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4648 This->stateBlock->streamIsUP = FALSE;
4651 if(This->stateBlock->loadBaseVertexIndex != 0) {
4652 This->stateBlock->loadBaseVertexIndex = 0;
4653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4655 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4656 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4660 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 IWineD3DBuffer *pIB;
4667 pIB = This->stateBlock->pIndexData;
4669 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4670 * without an index buffer set. (The first time at least...)
4671 * D3D8 simply dies, but I doubt it can do much harm to return
4672 * D3DERR_INVALIDCALL there as well. */
4673 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4674 return WINED3DERR_INVALIDCALL;
4677 if(!This->stateBlock->vertexDecl) {
4678 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4679 return WINED3DERR_INVALIDCALL;
4682 if(This->stateBlock->streamIsUP) {
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4684 This->stateBlock->streamIsUP = FALSE;
4686 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4688 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4690 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4696 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4697 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4701 drawPrimitive(iface, index_count, startIndex, idxStride,
4702 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4707 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4708 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4714 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4716 if(!This->stateBlock->vertexDecl) {
4717 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4718 return WINED3DERR_INVALIDCALL;
4721 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4722 vb = This->stateBlock->streamSource[0];
4723 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4724 if (vb) IWineD3DBuffer_Release(vb);
4725 This->stateBlock->streamOffset[0] = 0;
4726 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4727 This->stateBlock->streamIsUP = TRUE;
4728 This->stateBlock->loadBaseVertexIndex = 0;
4730 /* TODO: Only mark dirty if drawing from a different UP address */
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4733 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4735 /* MSDN specifies stream zero settings must be set to NULL */
4736 This->stateBlock->streamStride[0] = 0;
4737 This->stateBlock->streamSource[0] = NULL;
4739 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4740 * the new stream sources or use UP drawing again
4745 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4746 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4747 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4755 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4757 if(!This->stateBlock->vertexDecl) {
4758 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4759 return WINED3DERR_INVALIDCALL;
4762 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4768 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4769 vb = This->stateBlock->streamSource[0];
4770 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4771 if (vb) IWineD3DBuffer_Release(vb);
4772 This->stateBlock->streamIsUP = TRUE;
4773 This->stateBlock->streamOffset[0] = 0;
4774 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4776 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4777 This->stateBlock->baseVertexIndex = 0;
4778 This->stateBlock->loadBaseVertexIndex = 0;
4779 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4783 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4785 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4786 This->stateBlock->streamSource[0] = NULL;
4787 This->stateBlock->streamStride[0] = 0;
4788 ib = This->stateBlock->pIndexData;
4790 IWineD3DBuffer_Release(ib);
4791 This->stateBlock->pIndexData = NULL;
4793 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4794 * SetStreamSource to specify a vertex buffer
4800 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4801 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4805 /* Mark the state dirty until we have nicer tracking
4806 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4811 This->stateBlock->baseVertexIndex = 0;
4812 This->up_strided = DrawPrimStrideData;
4813 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4814 This->up_strided = NULL;
4818 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4819 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4820 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4823 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4825 /* Mark the state dirty until we have nicer tracking
4826 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4831 This->stateBlock->streamIsUP = TRUE;
4832 This->stateBlock->baseVertexIndex = 0;
4833 This->up_strided = DrawPrimStrideData;
4834 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4835 This->up_strided = NULL;
4839 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4840 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4841 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4843 WINED3DLOCKED_BOX src;
4844 WINED3DLOCKED_BOX dst;
4847 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4848 iface, pSourceVolume, pDestinationVolume);
4850 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4851 * dirtification to improve loading performance.
4853 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4854 if(FAILED(hr)) return hr;
4855 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4857 IWineD3DVolume_UnlockBox(pSourceVolume);
4861 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4863 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4865 IWineD3DVolume_UnlockBox(pSourceVolume);
4867 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4872 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4873 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4875 unsigned int level_count, i;
4876 WINED3DRESOURCETYPE type;
4879 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4881 /* Verify that the source and destination textures are non-NULL. */
4882 if (!src_texture || !dst_texture)
4884 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4885 return WINED3DERR_INVALIDCALL;
4888 if (src_texture == dst_texture)
4890 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4891 return WINED3DERR_INVALIDCALL;
4894 /* Verify that the source and destination textures are the same type. */
4895 type = IWineD3DBaseTexture_GetType(src_texture);
4896 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4898 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4899 return WINED3DERR_INVALIDCALL;
4902 /* Check that both textures have the identical numbers of levels. */
4903 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4904 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4906 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4907 return WINED3DERR_INVALIDCALL;
4910 /* Make sure that the destination texture is loaded. */
4911 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4913 /* Update every surface level of the texture. */
4916 case WINED3DRTYPE_TEXTURE:
4918 IWineD3DSurface *src_surface;
4919 IWineD3DSurface *dst_surface;
4921 for (i = 0; i < level_count; ++i)
4923 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4924 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4925 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4926 IWineD3DSurface_Release(dst_surface);
4927 IWineD3DSurface_Release(src_surface);
4930 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4937 case WINED3DRTYPE_CUBETEXTURE:
4939 IWineD3DSurface *src_surface;
4940 IWineD3DSurface *dst_surface;
4941 WINED3DCUBEMAP_FACES face;
4943 for (i = 0; i < level_count; ++i)
4945 /* Update each cube face. */
4946 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4948 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4949 face, i, &src_surface);
4950 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4951 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4952 face, i, &dst_surface);
4953 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4954 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4955 IWineD3DSurface_Release(dst_surface);
4956 IWineD3DSurface_Release(src_surface);
4959 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4967 case WINED3DRTYPE_VOLUMETEXTURE:
4969 IWineD3DVolume *src_volume;
4970 IWineD3DVolume *dst_volume;
4972 for (i = 0; i < level_count; ++i)
4974 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4975 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4976 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4977 IWineD3DVolume_Release(dst_volume);
4978 IWineD3DVolume_Release(src_volume);
4981 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4989 FIXME("Unsupported texture type %#x.\n", type);
4990 return WINED3DERR_INVALIDCALL;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4997 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4999 IWineD3DSwapChain *swapchain;
5002 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5004 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5005 if (FAILED(hr)) return hr;
5007 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5008 IWineD3DSwapChain_Release(swapchain);
5013 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5015 IWineD3DBaseTextureImpl *texture;
5018 TRACE("(%p) : %p\n", This, pNumPasses);
5020 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5021 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5022 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5023 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5025 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5026 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5027 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5030 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5031 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5033 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5034 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5037 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5038 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5041 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5042 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5043 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5048 /* return a sensible default */
5051 TRACE("returning D3D_OK\n");
5055 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5059 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5061 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5062 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5063 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5065 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5070 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5074 PALETTEENTRY **palettes;
5076 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5078 if (PaletteNumber >= MAX_PALETTES) {
5079 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5080 return WINED3DERR_INVALIDCALL;
5083 if (PaletteNumber >= This->NumberOfPalettes) {
5084 NewSize = This->NumberOfPalettes;
5087 } while(PaletteNumber >= NewSize);
5088 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5090 ERR("Out of memory!\n");
5091 return E_OUTOFMEMORY;
5093 This->palettes = palettes;
5094 This->NumberOfPalettes = NewSize;
5097 if (!This->palettes[PaletteNumber]) {
5098 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5099 if (!This->palettes[PaletteNumber]) {
5100 ERR("Out of memory!\n");
5101 return E_OUTOFMEMORY;
5105 for (j = 0; j < 256; ++j) {
5106 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5107 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5108 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5109 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5111 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5112 TRACE("(%p) : returning\n", This);
5116 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5120 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5121 /* What happens in such situation isn't documented; Native seems to silently abort
5122 on such conditions. Return Invalid Call. */
5123 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5124 return WINED3DERR_INVALIDCALL;
5126 for (j = 0; j < 256; ++j) {
5127 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5128 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5129 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5130 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5132 TRACE("(%p) : returning\n", This);
5136 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5139 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5140 (tested with reference rasterizer). Return Invalid Call. */
5141 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5142 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5143 return WINED3DERR_INVALIDCALL;
5145 /*TODO: stateblocks */
5146 if (This->currentPalette != PaletteNumber) {
5147 This->currentPalette = PaletteNumber;
5148 dirtify_p8_texture_samplers(This);
5150 TRACE("(%p) : returning\n", This);
5154 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5156 if (PaletteNumber == NULL) {
5157 WARN("(%p) : returning Invalid Call\n", This);
5158 return WINED3DERR_INVALIDCALL;
5160 /*TODO: stateblocks */
5161 *PaletteNumber = This->currentPalette;
5162 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5166 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 FIXME("(%p) : stub\n", This);
5175 This->softwareVertexProcessing = bSoftware;
5180 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5185 FIXME("(%p) : stub\n", This);
5188 return This->softwareVertexProcessing;
5191 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5192 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5194 IWineD3DSwapChain *swapchain;
5197 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5198 iface, swapchain_idx, raster_status);
5200 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5203 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5207 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5208 IWineD3DSwapChain_Release(swapchain);
5211 WARN("Failed to get raster status, hr %#x.\n", hr);
5218 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5221 if(nSegments != 0.0f) {
5224 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5231 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5236 FIXME("iface %p stub!\n", iface);
5242 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5243 IWineD3DSurface *src_surface, const RECT *src_rect,
5244 IWineD3DSurface *dst_surface, const POINT *dst_point)
5246 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5247 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5249 const struct wined3d_format *src_format;
5250 const struct wined3d_format *dst_format;
5251 const struct wined3d_gl_info *gl_info;
5252 struct wined3d_context *context;
5253 const unsigned char *data;
5254 UINT update_w, update_h;
5255 CONVERT_TYPES convert;
5259 struct wined3d_format format;
5261 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5262 iface, src_surface, wine_dbgstr_rect(src_rect),
5263 dst_surface, wine_dbgstr_point(dst_point));
5265 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5267 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5268 src_surface, dst_surface);
5269 return WINED3DERR_INVALIDCALL;
5272 src_format = src_impl->resource.format;
5273 dst_format = dst_impl->resource.format;
5275 if (src_format->id != dst_format->id)
5277 WARN("Source and destination surfaces should have the same format.\n");
5278 return WINED3DERR_INVALIDCALL;
5281 dst_x = dst_point ? dst_point->x : 0;
5282 dst_y = dst_point ? dst_point->y : 0;
5284 /* This call loads the OpenGL surface directly, instead of copying the
5285 * surface to the destination's sysmem copy. If surface conversion is
5286 * needed, use BltFast instead to copy in sysmem and use regular surface
5288 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5289 if (convert != NO_CONVERSION || format.convert)
5290 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5292 context = context_acquire(This, NULL);
5293 gl_info = context->gl_info;
5296 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5297 checkGLcall("glActiveTextureARB");
5300 /* Make sure the surface is loaded and up to date */
5301 surface_internal_preload(dst_impl, SRGB_RGB);
5302 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5304 src_w = src_impl->currentDesc.Width;
5305 src_h = src_impl->currentDesc.Height;
5306 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5307 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5309 data = IWineD3DSurface_GetData(src_surface);
5310 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5314 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5316 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5317 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5318 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5322 data += (src_rect->top / src_format->block_height) * src_pitch;
5323 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5326 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5327 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5328 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5330 if (row_length == src_pitch)
5332 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5333 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5339 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5340 * can't use the unpack row length like below. */
5341 for (row = 0, y = dst_y; row < row_count; ++row)
5343 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5344 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5345 y += src_format->block_height;
5349 checkGLcall("glCompressedTexSubImage2DARB");
5355 data += src_rect->top * src_w * src_format->byte_count;
5356 data += src_rect->left * src_format->byte_count;
5359 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5360 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5361 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5363 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5364 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5365 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5366 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5367 checkGLcall("glTexSubImage2D");
5371 context_release(context);
5373 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5374 sampler = This->rev_tex_unit_map[0];
5375 if (sampler != WINED3D_UNMAPPED_STAGE)
5377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5383 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5385 struct WineD3DRectPatch *patch;
5386 GLenum old_primitive_type;
5390 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5392 if(!(Handle || pRectPatchInfo)) {
5393 /* TODO: Write a test for the return value, thus the FIXME */
5394 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5395 return WINED3DERR_INVALIDCALL;
5399 i = PATCHMAP_HASHFUNC(Handle);
5401 LIST_FOR_EACH(e, &This->patches[i]) {
5402 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5403 if(patch->Handle == Handle) {
5410 TRACE("Patch does not exist. Creating a new one\n");
5411 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5412 patch->Handle = Handle;
5413 list_add_head(&This->patches[i], &patch->entry);
5415 TRACE("Found existing patch %p\n", patch);
5418 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5419 * attributes we have to tesselate, read back, and draw. This needs a patch
5420 * management structure instance. Create one.
5422 * A possible improvement is to check if a vertex shader is used, and if not directly
5425 FIXME("Drawing an uncached patch. This is slow\n");
5426 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5429 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5430 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5431 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5433 TRACE("Tesselation density or patch info changed, retesselating\n");
5435 if(pRectPatchInfo) {
5436 patch->RectPatchInfo = *pRectPatchInfo;
5438 patch->numSegs[0] = pNumSegs[0];
5439 patch->numSegs[1] = pNumSegs[1];
5440 patch->numSegs[2] = pNumSegs[2];
5441 patch->numSegs[3] = pNumSegs[3];
5443 hr = tesselate_rectpatch(This, patch);
5445 WARN("Patch tesselation failed\n");
5447 /* Do not release the handle to store the params of the patch */
5449 HeapFree(GetProcessHeap(), 0, patch);
5455 This->currentPatch = patch;
5456 old_primitive_type = This->stateBlock->gl_primitive_type;
5457 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5458 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5459 This->stateBlock->gl_primitive_type = old_primitive_type;
5460 This->currentPatch = NULL;
5462 /* Destroy uncached patches */
5464 HeapFree(GetProcessHeap(), 0, patch->mem);
5465 HeapFree(GetProcessHeap(), 0, patch);
5470 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5471 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5473 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5474 iface, handle, segment_count, patch_info);
5479 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5482 struct WineD3DRectPatch *patch;
5484 TRACE("(%p) Handle(%d)\n", This, Handle);
5486 i = PATCHMAP_HASHFUNC(Handle);
5487 LIST_FOR_EACH(e, &This->patches[i]) {
5488 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5489 if(patch->Handle == Handle) {
5490 TRACE("Deleting patch %p\n", patch);
5491 list_remove(&patch->entry);
5492 HeapFree(GetProcessHeap(), 0, patch->mem);
5493 HeapFree(GetProcessHeap(), 0, patch);
5498 /* TODO: Write a test for the return value */
5499 FIXME("Attempt to destroy nonexistent patch\n");
5500 return WINED3DERR_INVALIDCALL;
5503 /* Do not call while under the GL lock. */
5504 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5505 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5507 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5509 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5510 iface, surface, wine_dbgstr_rect(rect),
5511 color->r, color->g, color->b, color->a);
5513 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5515 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5516 return WINED3DERR_INVALIDCALL;
5519 return surface_color_fill(s, rect, color);
5522 /* Do not call while under the GL lock. */
5523 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5524 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5526 IWineD3DResource *resource;
5529 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5532 ERR("Failed to get resource, hr %#x\n", hr);
5536 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5538 FIXME("Only supported on surface resources\n");
5539 IWineD3DResource_Release(resource);
5543 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5544 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5546 IWineD3DResource_Release(resource);
5549 /* rendertarget and depth stencil functions */
5550 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5551 DWORD render_target_idx, IWineD3DSurface **render_target)
5553 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5555 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5556 iface, render_target_idx, render_target);
5558 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5560 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5561 return WINED3DERR_INVALIDCALL;
5564 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5565 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5567 TRACE("Returning render target %p.\n", *render_target);
5572 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5573 IWineD3DSurface *front, IWineD3DSurface *back)
5575 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5576 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5577 IWineD3DSwapChainImpl *swapchain;
5580 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5582 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5584 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5588 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5590 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5591 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5592 return WINED3DERR_INVALIDCALL;
5597 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5599 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5600 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5601 return WINED3DERR_INVALIDCALL;
5604 if (!swapchain->back_buffers)
5606 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5607 if (!swapchain->back_buffers)
5609 ERR("Failed to allocate back buffer array memory.\n");
5610 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5611 return E_OUTOFMEMORY;
5616 if (swapchain->front_buffer != front_impl)
5618 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5620 if (swapchain->front_buffer)
5621 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5622 swapchain->front_buffer = front_impl;
5625 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5628 if (swapchain->back_buffers[0] != back_impl)
5630 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5632 if (swapchain->back_buffers[0])
5633 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5634 swapchain->back_buffers[0] = back_impl;
5638 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5639 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5640 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5641 swapchain->presentParms.BackBufferCount = 1;
5643 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5647 swapchain->presentParms.BackBufferCount = 0;
5648 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5649 swapchain->back_buffers = NULL;
5653 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5657 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5659 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5661 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5663 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5664 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5665 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5666 IWineD3DSurface_AddRef(*depth_stencil);
5671 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5672 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5674 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5675 IWineD3DSurfaceImpl *prev;
5677 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5678 iface, render_target_idx, render_target, set_viewport);
5680 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5682 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5683 return WINED3DERR_INVALIDCALL;
5686 prev = device->render_targets[render_target_idx];
5687 if (render_target == (IWineD3DSurface *)prev)
5689 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5693 /* Render target 0 can't be set to NULL. */
5694 if (!render_target && !render_target_idx)
5696 WARN("Trying to set render target 0 to NULL.\n");
5697 return WINED3DERR_INVALIDCALL;
5700 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5702 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5703 return WINED3DERR_INVALIDCALL;
5706 if (render_target) IWineD3DSurface_AddRef(render_target);
5707 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5708 /* Release after the assignment, to prevent device_resource_released()
5709 * from seeing the surface as still in use. */
5710 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5712 /* Render target 0 is special. */
5713 if (!render_target_idx && set_viewport)
5715 /* Set the viewport and scissor rectangles, if requested. Tests show
5716 * that stateblock recording is ignored, the change goes directly
5717 * into the primary stateblock. */
5718 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5719 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5720 device->stateBlock->viewport.X = 0;
5721 device->stateBlock->viewport.Y = 0;
5722 device->stateBlock->viewport.MaxZ = 1.0f;
5723 device->stateBlock->viewport.MinZ = 0.0f;
5724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5726 device->stateBlock->scissorRect.top = 0;
5727 device->stateBlock->scissorRect.left = 0;
5728 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5729 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5730 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5736 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 IWineD3DSurfaceImpl *tmp;
5741 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5743 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5745 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5749 if (This->depth_stencil)
5751 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5752 || This->depth_stencil->Flags & SFLAG_DISCARD)
5754 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5755 This->depth_stencil->currentDesc.Width,
5756 This->depth_stencil->currentDesc.Height);
5757 if (This->depth_stencil == This->onscreen_depth_stencil)
5759 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5760 This->onscreen_depth_stencil = NULL;
5765 tmp = This->depth_stencil;
5766 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5767 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5768 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5770 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5772 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5781 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5782 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5785 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5786 WINED3DLOCKED_RECT lockedRect;
5788 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5789 iface, XHotSpot, YHotSpot, cursor_image);
5791 /* some basic validation checks */
5792 if (This->cursorTexture)
5794 struct wined3d_context *context = context_acquire(This, NULL);
5796 glDeleteTextures(1, &This->cursorTexture);
5798 context_release(context);
5799 This->cursorTexture = 0;
5802 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5803 This->haveHardwareCursor = TRUE;
5805 This->haveHardwareCursor = FALSE;
5809 WINED3DLOCKED_RECT rect;
5811 /* MSDN: Cursor must be A8R8G8B8 */
5812 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5814 WARN("surface %p has an invalid format.\n", cursor_image);
5815 return WINED3DERR_INVALIDCALL;
5818 /* MSDN: Cursor must be smaller than the display mode */
5819 if (s->currentDesc.Width > This->ddraw_width
5820 || s->currentDesc.Height > This->ddraw_height)
5822 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5823 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5824 return WINED3DERR_INVALIDCALL;
5827 if (!This->haveHardwareCursor) {
5828 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5830 /* Do not store the surface's pointer because the application may
5831 * release it after setting the cursor image. Windows doesn't
5832 * addref the set surface, so we can't do this either without
5833 * creating circular refcount dependencies. Copy out the gl texture
5836 This->cursorWidth = s->currentDesc.Width;
5837 This->cursorHeight = s->currentDesc.Height;
5838 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5840 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5841 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5842 struct wined3d_context *context;
5843 char *mem, *bits = rect.pBits;
5844 GLint intfmt = format->glInternal;
5845 GLint gl_format = format->glFormat;
5846 GLint type = format->glType;
5847 INT height = This->cursorHeight;
5848 INT width = This->cursorWidth;
5849 INT bpp = format->byte_count;
5853 /* Reformat the texture memory (pitch and width can be
5855 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5856 for(i = 0; i < height; i++)
5857 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5858 IWineD3DSurface_UnlockRect(cursor_image);
5860 context = context_acquire(This, NULL);
5864 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5866 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5867 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5870 /* Make sure that a proper texture unit is selected */
5871 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5872 checkGLcall("glActiveTextureARB");
5873 sampler = This->rev_tex_unit_map[0];
5874 if (sampler != WINED3D_UNMAPPED_STAGE)
5876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5878 /* Create a new cursor texture */
5879 glGenTextures(1, &This->cursorTexture);
5880 checkGLcall("glGenTextures");
5881 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5882 checkGLcall("glBindTexture");
5883 /* Copy the bitmap memory into the cursor texture */
5884 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5885 HeapFree(GetProcessHeap(), 0, mem);
5886 checkGLcall("glTexImage2D");
5888 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5890 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5891 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5896 context_release(context);
5900 FIXME("A cursor texture was not returned.\n");
5901 This->cursorTexture = 0;
5906 /* Draw a hardware cursor */
5907 ICONINFO cursorInfo;
5909 /* Create and clear maskBits because it is not needed for
5910 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5912 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5913 (s->currentDesc.Width * s->currentDesc.Height / 8));
5914 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5915 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5916 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5918 cursorInfo.fIcon = FALSE;
5919 cursorInfo.xHotspot = XHotSpot;
5920 cursorInfo.yHotspot = YHotSpot;
5921 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5922 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5923 IWineD3DSurface_UnlockRect(cursor_image);
5924 /* Create our cursor and clean up. */
5925 cursor = CreateIconIndirect(&cursorInfo);
5927 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5928 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5929 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5930 This->hardwareCursor = cursor;
5931 HeapFree(GetProcessHeap(), 0, maskBits);
5935 This->xHotSpot = XHotSpot;
5936 This->yHotSpot = YHotSpot;
5940 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5942 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5944 This->xScreenSpace = XScreenSpace;
5945 This->yScreenSpace = YScreenSpace;
5951 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5953 BOOL oldVisible = This->bCursorVisible;
5956 TRACE("(%p) : visible(%d)\n", This, bShow);
5959 * When ShowCursor is first called it should make the cursor appear at the OS's last
5960 * known cursor position. Because of this, some applications just repetitively call
5961 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5964 This->xScreenSpace = pt.x;
5965 This->yScreenSpace = pt.y;
5967 if (This->haveHardwareCursor) {
5968 This->bCursorVisible = bShow;
5970 SetCursor(This->hardwareCursor);
5976 if (This->cursorTexture)
5977 This->bCursorVisible = bShow;
5983 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5984 TRACE("checking resource %p for eviction\n", resource);
5985 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5986 TRACE("Evicting %p\n", resource);
5987 IWineD3DResource_UnLoad(resource);
5989 IWineD3DResource_Release(resource);
5993 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5995 TRACE("iface %p.\n", iface);
5997 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5998 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5999 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6004 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6006 IWineD3DDeviceImpl *device = surface->resource.device;
6007 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6009 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6010 if(surface->Flags & SFLAG_DIBSECTION) {
6011 /* Release the DC */
6012 SelectObject(surface->hDC, surface->dib.holdbitmap);
6013 DeleteDC(surface->hDC);
6014 /* Release the DIB section */
6015 DeleteObject(surface->dib.DIBsection);
6016 surface->dib.bitmap_data = NULL;
6017 surface->resource.allocatedMemory = NULL;
6018 surface->Flags &= ~SFLAG_DIBSECTION;
6020 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6021 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6022 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6023 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6025 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6026 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6028 surface->pow2Width = surface->pow2Height = 1;
6029 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6030 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6033 if (surface->texture_name)
6035 struct wined3d_context *context = context_acquire(device, NULL);
6037 glDeleteTextures(1, &surface->texture_name);
6039 context_release(context);
6040 surface->texture_name = 0;
6041 surface->Flags &= ~SFLAG_CLIENT;
6043 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6044 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6045 surface->Flags |= SFLAG_NONPOW2;
6047 surface->Flags &= ~SFLAG_NONPOW2;
6049 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6050 surface->resource.allocatedMemory = NULL;
6051 surface->resource.heapMemory = NULL;
6052 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6054 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6056 if (!surface_init_sysmem(surface))
6058 return E_OUTOFMEMORY;
6063 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6064 TRACE("Unloading resource %p\n", resource);
6065 IWineD3DResource_UnLoad(resource);
6066 IWineD3DResource_Release(resource);
6070 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6073 WINED3DDISPLAYMODE m;
6076 /* All Windowed modes are supported, as is leaving the current mode */
6077 if(pp->Windowed) return TRUE;
6078 if(!pp->BackBufferWidth) return TRUE;
6079 if(!pp->BackBufferHeight) return TRUE;
6081 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6082 for(i = 0; i < count; i++) {
6083 memset(&m, 0, sizeof(m));
6084 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6086 ERR("EnumAdapterModes failed\n");
6088 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6089 /* Mode found, it is supported */
6093 /* Mode not found -> not supported */
6097 /* Do not call while under the GL lock. */
6098 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6101 const struct wined3d_gl_info *gl_info;
6102 struct wined3d_context *context;
6103 IWineD3DBaseShaderImpl *shader;
6105 context = context_acquire(This, NULL);
6106 gl_info = context->gl_info;
6108 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6109 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6110 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6114 if(This->depth_blt_texture) {
6115 glDeleteTextures(1, &This->depth_blt_texture);
6116 This->depth_blt_texture = 0;
6118 if (This->depth_blt_rb) {
6119 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6120 This->depth_blt_rb = 0;
6121 This->depth_blt_rb_w = 0;
6122 This->depth_blt_rb_h = 0;
6126 This->blitter->free_private(iface);
6127 This->frag_pipe->free_private(iface);
6128 This->shader_backend->shader_free_private(iface);
6129 destroy_dummy_textures(This, gl_info);
6131 context_release(context);
6133 while (This->numContexts)
6135 context_destroy(This, This->contexts[0]);
6137 HeapFree(GetProcessHeap(), 0, swapchain->context);
6138 swapchain->context = NULL;
6139 swapchain->num_contexts = 0;
6142 /* Do not call while under the GL lock. */
6143 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6146 struct wined3d_context *context;
6148 IWineD3DSurfaceImpl *target;
6150 /* Recreate the primary swapchain's context */
6151 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6152 if (!swapchain->context)
6154 ERR("Failed to allocate memory for swapchain context array.\n");
6155 return E_OUTOFMEMORY;
6158 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6159 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6161 WARN("Failed to create context.\n");
6162 HeapFree(GetProcessHeap(), 0, swapchain->context);
6166 swapchain->context[0] = context;
6167 swapchain->num_contexts = 1;
6168 create_dummy_textures(This);
6169 context_release(context);
6171 hr = This->shader_backend->shader_alloc_private(iface);
6174 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6178 hr = This->frag_pipe->alloc_private(iface);
6181 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6182 This->shader_backend->shader_free_private(iface);
6186 hr = This->blitter->alloc_private(iface);
6189 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6190 This->frag_pipe->free_private(iface);
6191 This->shader_backend->shader_free_private(iface);
6198 context_acquire(This, NULL);
6199 destroy_dummy_textures(This, context->gl_info);
6200 context_release(context);
6201 context_destroy(This, context);
6202 HeapFree(GetProcessHeap(), 0, swapchain->context);
6203 swapchain->num_contexts = 0;
6207 /* Do not call while under the GL lock. */
6208 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6209 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6212 IWineD3DSwapChainImpl *swapchain;
6214 BOOL DisplayModeChanged = FALSE;
6215 WINED3DDISPLAYMODE mode;
6216 TRACE("(%p)\n", This);
6218 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6220 ERR("Failed to get the first implicit swapchain\n");
6224 if(!is_display_mode_supported(This, pPresentationParameters)) {
6225 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6226 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6227 pPresentationParameters->BackBufferHeight);
6228 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6229 return WINED3DERR_INVALIDCALL;
6232 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6233 * on an existing gl context, so there's no real need for recreation.
6235 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6237 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6239 TRACE("New params:\n");
6240 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6241 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6242 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6243 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6244 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6245 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6246 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6247 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6248 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6249 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6250 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6251 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6252 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6254 /* No special treatment of these parameters. Just store them */
6255 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6256 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6257 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6258 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6260 /* What to do about these? */
6261 if(pPresentationParameters->BackBufferCount != 0 &&
6262 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6263 ERR("Cannot change the back buffer count yet\n");
6265 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6266 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6267 ERR("Cannot change the back buffer format yet\n");
6269 if(pPresentationParameters->hDeviceWindow != NULL &&
6270 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6271 ERR("Cannot change the device window yet\n");
6273 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6277 TRACE("Creating the depth stencil buffer\n");
6279 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6280 pPresentationParameters->BackBufferWidth,
6281 pPresentationParameters->BackBufferHeight,
6282 pPresentationParameters->AutoDepthStencilFormat,
6283 pPresentationParameters->MultiSampleType,
6284 pPresentationParameters->MultiSampleQuality,
6286 (IWineD3DSurface **)&This->auto_depth_stencil);
6289 ERR("Failed to create the depth stencil buffer\n");
6290 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6291 return WINED3DERR_INVALIDCALL;
6295 if (This->onscreen_depth_stencil)
6297 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6298 This->onscreen_depth_stencil = NULL;
6301 /* Reset the depth stencil */
6302 if (pPresentationParameters->EnableAutoDepthStencil)
6303 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6305 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6307 TRACE("Resetting stateblock\n");
6308 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6309 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6311 delete_opengl_contexts(iface, swapchain);
6313 if(pPresentationParameters->Windowed) {
6314 mode.Width = swapchain->orig_width;
6315 mode.Height = swapchain->orig_height;
6316 mode.RefreshRate = 0;
6317 mode.Format = swapchain->presentParms.BackBufferFormat;
6319 mode.Width = pPresentationParameters->BackBufferWidth;
6320 mode.Height = pPresentationParameters->BackBufferHeight;
6321 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6322 mode.Format = swapchain->presentParms.BackBufferFormat;
6325 /* Should Width == 800 && Height == 0 set 800x600? */
6326 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6327 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6328 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6332 if(!pPresentationParameters->Windowed) {
6333 DisplayModeChanged = TRUE;
6335 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6336 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6338 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6341 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6345 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6347 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6350 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6354 if (This->auto_depth_stencil)
6356 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6359 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6365 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6366 || DisplayModeChanged)
6368 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6370 if (!pPresentationParameters->Windowed)
6372 if(swapchain->presentParms.Windowed) {
6373 /* switch from windowed to fs */
6374 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6375 pPresentationParameters->BackBufferHeight);
6377 /* Fullscreen -> fullscreen mode change */
6378 MoveWindow(swapchain->device_window, 0, 0,
6379 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6383 else if (!swapchain->presentParms.Windowed)
6385 /* Fullscreen -> windowed switch */
6386 swapchain_restore_fullscreen_window(swapchain);
6388 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6389 } else if(!pPresentationParameters->Windowed) {
6390 DWORD style = This->style, exStyle = This->exStyle;
6391 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6392 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6393 * Reset to clear up their mess. Guild Wars also loses the device during that.
6397 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6398 pPresentationParameters->BackBufferHeight);
6399 This->style = style;
6400 This->exStyle = exStyle;
6403 /* Note: No parent needed for initial internal stateblock */
6404 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6405 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6406 else TRACE("Created stateblock %p\n", This->stateBlock);
6407 This->updateStateBlock = This->stateBlock;
6408 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6410 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6412 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6415 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6418 GetClientRect(swapchain->win_handle, &client_rect);
6420 if(!swapchain->presentParms.BackBufferCount)
6422 TRACE("Single buffered rendering\n");
6423 swapchain->render_to_fbo = FALSE;
6425 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6426 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6428 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6429 swapchain->presentParms.BackBufferWidth,
6430 swapchain->presentParms.BackBufferHeight,
6431 client_rect.right, client_rect.bottom);
6432 swapchain->render_to_fbo = TRUE;
6436 TRACE("Rendering directly to GL_BACK\n");
6437 swapchain->render_to_fbo = FALSE;
6441 hr = create_primary_opengl_context(iface, swapchain);
6442 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6444 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6450 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6452 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6454 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6460 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6462 TRACE("(%p) : pParameters %p\n", This, pParameters);
6464 *pParameters = This->createParms;
6468 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6469 IWineD3DSwapChain *swapchain;
6471 TRACE("Relaying to swapchain\n");
6473 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6474 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6475 IWineD3DSwapChain_Release(swapchain);
6479 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6480 IWineD3DSwapChain *swapchain;
6482 TRACE("Relaying to swapchain\n");
6484 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6485 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6486 IWineD3DSwapChain_Release(swapchain);
6491 /** ********************************************************
6492 * Notification functions
6493 ** ********************************************************/
6494 /** This function must be called in the release of a resource when ref == 0,
6495 * the contents of resource must still be correct,
6496 * any handles to other resource held by the caller must be closed
6497 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6498 *****************************************************/
6499 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6501 TRACE("(%p) : Adding resource %p\n", This, resource);
6503 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6506 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6508 TRACE("(%p) : Removing resource %p\n", This, resource);
6510 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6513 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6515 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6518 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6520 context_resource_released(device, resource, type);
6524 case WINED3DRTYPE_SURFACE:
6525 if (!device->d3d_initialized) break;
6527 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6529 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6531 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6532 device->render_targets[i] = NULL;
6536 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6538 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6539 device->depth_stencil = NULL;
6543 case WINED3DRTYPE_TEXTURE:
6544 case WINED3DRTYPE_CUBETEXTURE:
6545 case WINED3DRTYPE_VOLUMETEXTURE:
6546 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6548 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6550 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6551 resource, device->stateBlock, i);
6552 device->stateBlock->textures[i] = NULL;
6555 if (device->updateStateBlock != device->stateBlock
6556 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6558 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6559 resource, device->updateStateBlock, i);
6560 device->updateStateBlock->textures[i] = NULL;
6565 case WINED3DRTYPE_BUFFER:
6566 for (i = 0; i < MAX_STREAMS; ++i)
6568 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6570 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6571 resource, device->stateBlock, i);
6572 device->stateBlock->streamSource[i] = NULL;
6575 if (device->updateStateBlock != device->stateBlock
6576 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6578 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6579 resource, device->updateStateBlock, i);
6580 device->updateStateBlock->streamSource[i] = NULL;
6585 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6587 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6588 resource, device->stateBlock);
6589 device->stateBlock->pIndexData = NULL;
6592 if (device->updateStateBlock != device->stateBlock
6593 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6595 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6596 resource, device->updateStateBlock);
6597 device->updateStateBlock->pIndexData = NULL;
6605 /* Remove the resource from the resourceStore */
6606 device_resource_remove(device, resource);
6608 TRACE("Resource released.\n");
6611 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6613 IWineD3DResourceImpl *resource, *cursor;
6615 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6617 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6618 TRACE("enumerating resource %p\n", resource);
6619 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6620 ret = pCallback((IWineD3DResource *) resource, pData);
6621 if(ret == S_FALSE) {
6622 TRACE("Canceling enumeration\n");
6629 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6632 IWineD3DResourceImpl *resource;
6634 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6636 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6637 if (type == WINED3DRTYPE_SURFACE)
6639 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6641 TRACE("Found surface %p for dc %p.\n", resource, dc);
6642 *surface = (IWineD3DSurface *)resource;
6648 return WINED3DERR_INVALIDCALL;
6651 /**********************************************************
6652 * IWineD3DDevice VTbl follows
6653 **********************************************************/
6655 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6657 /*** IUnknown methods ***/
6658 IWineD3DDeviceImpl_QueryInterface,
6659 IWineD3DDeviceImpl_AddRef,
6660 IWineD3DDeviceImpl_Release,
6661 /*** IWineD3DDevice methods ***/
6662 /*** Creation methods**/
6663 IWineD3DDeviceImpl_CreateBuffer,
6664 IWineD3DDeviceImpl_CreateVertexBuffer,
6665 IWineD3DDeviceImpl_CreateIndexBuffer,
6666 IWineD3DDeviceImpl_CreateStateBlock,
6667 IWineD3DDeviceImpl_CreateSurface,
6668 IWineD3DDeviceImpl_CreateRendertargetView,
6669 IWineD3DDeviceImpl_CreateTexture,
6670 IWineD3DDeviceImpl_CreateVolumeTexture,
6671 IWineD3DDeviceImpl_CreateVolume,
6672 IWineD3DDeviceImpl_CreateCubeTexture,
6673 IWineD3DDeviceImpl_CreateQuery,
6674 IWineD3DDeviceImpl_CreateSwapChain,
6675 IWineD3DDeviceImpl_CreateVertexDeclaration,
6676 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6677 IWineD3DDeviceImpl_CreateVertexShader,
6678 IWineD3DDeviceImpl_CreateGeometryShader,
6679 IWineD3DDeviceImpl_CreatePixelShader,
6680 IWineD3DDeviceImpl_CreatePalette,
6681 /*** Odd functions **/
6682 IWineD3DDeviceImpl_Init3D,
6683 IWineD3DDeviceImpl_InitGDI,
6684 IWineD3DDeviceImpl_Uninit3D,
6685 IWineD3DDeviceImpl_UninitGDI,
6686 IWineD3DDeviceImpl_SetMultithreaded,
6687 IWineD3DDeviceImpl_EvictManagedResources,
6688 IWineD3DDeviceImpl_GetAvailableTextureMem,
6689 IWineD3DDeviceImpl_GetBackBuffer,
6690 IWineD3DDeviceImpl_GetCreationParameters,
6691 IWineD3DDeviceImpl_GetDeviceCaps,
6692 IWineD3DDeviceImpl_GetDirect3D,
6693 IWineD3DDeviceImpl_GetDisplayMode,
6694 IWineD3DDeviceImpl_SetDisplayMode,
6695 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6696 IWineD3DDeviceImpl_GetRasterStatus,
6697 IWineD3DDeviceImpl_GetSwapChain,
6698 IWineD3DDeviceImpl_Reset,
6699 IWineD3DDeviceImpl_SetDialogBoxMode,
6700 IWineD3DDeviceImpl_SetCursorProperties,
6701 IWineD3DDeviceImpl_SetCursorPosition,
6702 IWineD3DDeviceImpl_ShowCursor,
6703 /*** Getters and setters **/
6704 IWineD3DDeviceImpl_SetClipPlane,
6705 IWineD3DDeviceImpl_GetClipPlane,
6706 IWineD3DDeviceImpl_SetClipStatus,
6707 IWineD3DDeviceImpl_GetClipStatus,
6708 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6709 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6710 IWineD3DDeviceImpl_SetDepthStencilSurface,
6711 IWineD3DDeviceImpl_GetDepthStencilSurface,
6712 IWineD3DDeviceImpl_SetGammaRamp,
6713 IWineD3DDeviceImpl_GetGammaRamp,
6714 IWineD3DDeviceImpl_SetIndexBuffer,
6715 IWineD3DDeviceImpl_GetIndexBuffer,
6716 IWineD3DDeviceImpl_SetBaseVertexIndex,
6717 IWineD3DDeviceImpl_GetBaseVertexIndex,
6718 IWineD3DDeviceImpl_SetLight,
6719 IWineD3DDeviceImpl_GetLight,
6720 IWineD3DDeviceImpl_SetLightEnable,
6721 IWineD3DDeviceImpl_GetLightEnable,
6722 IWineD3DDeviceImpl_SetMaterial,
6723 IWineD3DDeviceImpl_GetMaterial,
6724 IWineD3DDeviceImpl_SetNPatchMode,
6725 IWineD3DDeviceImpl_GetNPatchMode,
6726 IWineD3DDeviceImpl_SetPaletteEntries,
6727 IWineD3DDeviceImpl_GetPaletteEntries,
6728 IWineD3DDeviceImpl_SetPixelShader,
6729 IWineD3DDeviceImpl_GetPixelShader,
6730 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6731 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6732 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6733 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6734 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6735 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6736 IWineD3DDeviceImpl_SetRenderState,
6737 IWineD3DDeviceImpl_GetRenderState,
6738 IWineD3DDeviceImpl_SetRenderTarget,
6739 IWineD3DDeviceImpl_GetRenderTarget,
6740 IWineD3DDeviceImpl_SetFrontBackBuffers,
6741 IWineD3DDeviceImpl_SetSamplerState,
6742 IWineD3DDeviceImpl_GetSamplerState,
6743 IWineD3DDeviceImpl_SetScissorRect,
6744 IWineD3DDeviceImpl_GetScissorRect,
6745 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6746 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6747 IWineD3DDeviceImpl_SetStreamSource,
6748 IWineD3DDeviceImpl_GetStreamSource,
6749 IWineD3DDeviceImpl_SetStreamSourceFreq,
6750 IWineD3DDeviceImpl_GetStreamSourceFreq,
6751 IWineD3DDeviceImpl_SetTexture,
6752 IWineD3DDeviceImpl_GetTexture,
6753 IWineD3DDeviceImpl_SetTextureStageState,
6754 IWineD3DDeviceImpl_GetTextureStageState,
6755 IWineD3DDeviceImpl_SetTransform,
6756 IWineD3DDeviceImpl_GetTransform,
6757 IWineD3DDeviceImpl_SetVertexDeclaration,
6758 IWineD3DDeviceImpl_GetVertexDeclaration,
6759 IWineD3DDeviceImpl_SetVertexShader,
6760 IWineD3DDeviceImpl_GetVertexShader,
6761 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6762 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6763 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6764 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6765 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6766 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6767 IWineD3DDeviceImpl_SetViewport,
6768 IWineD3DDeviceImpl_GetViewport,
6769 IWineD3DDeviceImpl_MultiplyTransform,
6770 IWineD3DDeviceImpl_ValidateDevice,
6771 IWineD3DDeviceImpl_ProcessVertices,
6772 /*** State block ***/
6773 IWineD3DDeviceImpl_BeginStateBlock,
6774 IWineD3DDeviceImpl_EndStateBlock,
6775 /*** Scene management ***/
6776 IWineD3DDeviceImpl_BeginScene,
6777 IWineD3DDeviceImpl_EndScene,
6778 IWineD3DDeviceImpl_Present,
6779 IWineD3DDeviceImpl_Clear,
6780 IWineD3DDeviceImpl_ClearRendertargetView,
6782 IWineD3DDeviceImpl_SetPrimitiveType,
6783 IWineD3DDeviceImpl_GetPrimitiveType,
6784 IWineD3DDeviceImpl_DrawPrimitive,
6785 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6786 IWineD3DDeviceImpl_DrawPrimitiveUP,
6787 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6788 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6789 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6790 IWineD3DDeviceImpl_DrawRectPatch,
6791 IWineD3DDeviceImpl_DrawTriPatch,
6792 IWineD3DDeviceImpl_DeletePatch,
6793 IWineD3DDeviceImpl_ColorFill,
6794 IWineD3DDeviceImpl_UpdateTexture,
6795 IWineD3DDeviceImpl_UpdateSurface,
6796 IWineD3DDeviceImpl_GetFrontBufferData,
6797 /*** object tracking ***/
6798 IWineD3DDeviceImpl_EnumResources,
6799 IWineD3DDeviceImpl_GetSurfaceFromDC,
6800 IWineD3DDeviceImpl_AcquireFocusWindow,
6801 IWineD3DDeviceImpl_ReleaseFocusWindow,
6804 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6805 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6806 IWineD3DDeviceParent *device_parent)
6808 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6809 const struct fragment_pipeline *fragment_pipeline;
6810 struct shader_caps shader_caps;
6811 struct fragment_caps ffp_caps;
6812 WINED3DDISPLAYMODE mode;
6816 device->lpVtbl = &IWineD3DDevice_Vtbl;
6818 device->wined3d = (IWineD3D *)wined3d;
6819 IWineD3D_AddRef(device->wined3d);
6820 device->adapter = wined3d->adapter_count ? adapter : NULL;
6821 device->device_parent = device_parent;
6822 list_init(&device->resources);
6823 list_init(&device->shaders);
6825 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6826 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6828 /* Get the initial screen setup for ddraw. */
6829 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6832 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6833 IWineD3D_Release(device->wined3d);
6836 device->ddraw_width = mode.Width;
6837 device->ddraw_height = mode.Height;
6838 device->ddraw_format = mode.Format;
6840 /* Save the creation parameters. */
6841 device->createParms.AdapterOrdinal = adapter_idx;
6842 device->createParms.DeviceType = device_type;
6843 device->createParms.hFocusWindow = focus_window;
6844 device->createParms.BehaviorFlags = flags;
6846 device->devType = device_type;
6847 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6849 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6850 device->shader_backend = adapter->shader_backend;
6852 if (device->shader_backend)
6854 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6855 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6856 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6857 device->vs_clipping = shader_caps.VSClipping;
6859 fragment_pipeline = adapter->fragment_pipe;
6860 device->frag_pipe = fragment_pipeline;
6861 if (fragment_pipeline)
6863 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6864 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6866 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6867 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6870 ERR("Failed to compile state table, hr %#x.\n", hr);
6871 IWineD3D_Release(device->wined3d);
6875 device->blitter = adapter->blitter;
6881 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6882 DWORD rep = This->StateTable[state].representative;
6883 struct wined3d_context *context;
6888 for(i = 0; i < This->numContexts; i++) {
6889 context = This->contexts[i];
6890 if(isStateDirty(context, rep)) continue;
6892 context->dirtyArray[context->numDirtyEntries++] = rep;
6893 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6894 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6895 context->isStateDirty[idx] |= (1 << shift);
6899 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6901 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6902 *width = context->current_rt->pow2Width;
6903 *height = context->current_rt->pow2Height;
6906 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6908 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6909 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6910 * current context's drawable, which is the size of the back buffer of the swapchain
6911 * the active context belongs to. */
6912 *width = swapchain->presentParms.BackBufferWidth;
6913 *height = swapchain->presentParms.BackBufferHeight;
6916 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6917 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6919 if (device->filter_messages)
6921 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6922 window, message, wparam, lparam);
6923 return DefWindowProcW(window, message, wparam, lparam);
6926 if (message == WM_DESTROY)
6928 TRACE("unregister window %p.\n", window);
6929 wined3d_unregister_window(window);
6931 if (device->focus_window == window) device->focus_window = NULL;
6932 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6935 return CallWindowProcW(proc, window, message, wparam, lparam);