wineps: Handle EMR_INVERTRGN record in spool files.
[wine.git] / dlls / wined3d / vertexdeclaration.c
blobe1aaf6dc9bc276a09979dd6dde6d818738d7b163
1 /*
2 * vertex declaration implementation
4 * Copyright 2002-2005 Raphael Junqueira
5 * Copyright 2004 Jason Edmeades
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2009 Henri Verbeet for CodeWeavers
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl);
29 static void dump_wined3d_vertex_element(const struct wined3d_vertex_element *element)
31 TRACE(" format: %s (%#x)\n", debug_d3dformat(element->format), element->format);
32 TRACE(" input_slot: %u\n", element->input_slot);
33 TRACE(" offset: %u\n", element->offset);
34 TRACE(" output_slot: %u\n", element->output_slot);
35 TRACE(" input slot class: %s\n", debug_d3dinput_classification(element->input_slot_class));
36 TRACE("instance data step rate: %u\n", element->instance_data_step_rate);
37 TRACE(" method: %s (%#x)\n", debug_d3ddeclmethod(element->method), element->method);
38 TRACE(" usage: %s (%#x)\n", debug_d3ddeclusage(element->usage), element->usage);
39 TRACE(" usage_idx: %u\n", element->usage_idx);
42 ULONG CDECL wined3d_vertex_declaration_incref(struct wined3d_vertex_declaration *declaration)
44 unsigned int refcount = InterlockedIncrement(&declaration->ref);
46 TRACE("%p increasing refcount to %u.\n", declaration, refcount);
48 return refcount;
51 static void wined3d_vertex_declaration_destroy_object(void *object)
53 struct wined3d_vertex_declaration *declaration = object;
55 TRACE("declaration %p.\n", declaration);
57 heap_free(declaration->elements);
58 heap_free(declaration);
61 ULONG CDECL wined3d_vertex_declaration_decref(struct wined3d_vertex_declaration *declaration)
63 unsigned int refcount = InterlockedDecrement(&declaration->ref);
65 TRACE("%p decreasing refcount to %u.\n", declaration, refcount);
67 if (!refcount)
69 wined3d_mutex_lock();
70 declaration->parent_ops->wined3d_object_destroyed(declaration->parent);
71 wined3d_cs_destroy_object(declaration->device->cs,
72 wined3d_vertex_declaration_destroy_object, declaration);
73 wined3d_mutex_unlock();
76 return refcount;
79 void * CDECL wined3d_vertex_declaration_get_parent(const struct wined3d_vertex_declaration *declaration)
81 TRACE("declaration %p.\n", declaration);
83 return declaration->parent;
86 static BOOL declaration_element_valid_ffp(const struct wined3d_vertex_element *element)
88 switch(element->usage)
90 case WINED3D_DECL_USAGE_POSITION:
91 case WINED3D_DECL_USAGE_POSITIONT:
92 switch(element->format)
94 case WINED3DFMT_R32G32_FLOAT:
95 case WINED3DFMT_R32G32B32_FLOAT:
96 case WINED3DFMT_R32G32B32A32_FLOAT:
97 case WINED3DFMT_R16G16_SINT:
98 case WINED3DFMT_R16G16B16A16_SINT:
99 case WINED3DFMT_R16G16_FLOAT:
100 case WINED3DFMT_R16G16B16A16_FLOAT:
101 return TRUE;
102 default:
103 return FALSE;
106 case WINED3D_DECL_USAGE_BLEND_WEIGHT:
107 switch(element->format)
109 case WINED3DFMT_R32_FLOAT:
110 case WINED3DFMT_R32G32_FLOAT:
111 case WINED3DFMT_R32G32B32_FLOAT:
112 case WINED3DFMT_R32G32B32A32_FLOAT:
113 case WINED3DFMT_B8G8R8A8_UNORM:
114 case WINED3DFMT_R8G8B8A8_UINT:
115 case WINED3DFMT_R16G16_SINT:
116 case WINED3DFMT_R16G16B16A16_SINT:
117 case WINED3DFMT_R16G16_FLOAT:
118 case WINED3DFMT_R16G16B16A16_FLOAT:
119 return TRUE;
120 default:
121 return FALSE;
124 case WINED3D_DECL_USAGE_NORMAL:
125 switch(element->format)
127 case WINED3DFMT_R32G32B32_FLOAT:
128 case WINED3DFMT_R32G32B32A32_FLOAT:
129 case WINED3DFMT_R16G16B16A16_SINT:
130 case WINED3DFMT_R16G16B16A16_FLOAT:
131 return TRUE;
132 default:
133 return FALSE;
136 case WINED3D_DECL_USAGE_TEXCOORD:
137 switch(element->format)
139 case WINED3DFMT_R32_FLOAT:
140 case WINED3DFMT_R32G32_FLOAT:
141 case WINED3DFMT_R32G32B32_FLOAT:
142 case WINED3DFMT_R32G32B32A32_FLOAT:
143 case WINED3DFMT_R16G16_SINT:
144 case WINED3DFMT_R16G16B16A16_SINT:
145 case WINED3DFMT_R16G16_FLOAT:
146 case WINED3DFMT_R16G16B16A16_FLOAT:
147 return TRUE;
148 default:
149 return FALSE;
152 case WINED3D_DECL_USAGE_COLOR:
153 switch(element->format)
155 case WINED3DFMT_R32G32B32_FLOAT:
156 case WINED3DFMT_R32G32B32A32_FLOAT:
157 case WINED3DFMT_B8G8R8A8_UNORM:
158 case WINED3DFMT_R8G8B8A8_UINT:
159 case WINED3DFMT_R16G16B16A16_SINT:
160 case WINED3DFMT_R8G8B8A8_UNORM:
161 case WINED3DFMT_R16G16B16A16_SNORM:
162 case WINED3DFMT_R16G16B16A16_UNORM:
163 case WINED3DFMT_R16G16B16A16_FLOAT:
164 return TRUE;
165 default:
166 return FALSE;
169 default:
170 return FALSE;
174 static HRESULT vertexdeclaration_init(struct wined3d_vertex_declaration *declaration,
175 struct wined3d_device *device, const struct wined3d_vertex_element *elements, UINT element_count,
176 void *parent, const struct wined3d_parent_ops *parent_ops)
178 const struct wined3d_adapter *adapter = device->adapter;
179 unsigned int i;
181 if (TRACE_ON(d3d_decl))
183 for (i = 0; i < element_count; ++i)
185 dump_wined3d_vertex_element(elements + i);
189 declaration->ref = 1;
190 declaration->parent = parent;
191 declaration->parent_ops = parent_ops;
192 declaration->device = device;
193 if (!(declaration->elements = heap_calloc(element_count, sizeof(*declaration->elements))))
195 ERR("Failed to allocate elements memory.\n");
196 return E_OUTOFMEMORY;
198 declaration->element_count = element_count;
200 /* Do some static analysis on the elements to make reading the
201 * declaration more comfortable for the drawing code. */
202 for (i = 0; i < element_count; ++i)
204 struct wined3d_vertex_declaration_element *e = &declaration->elements[i];
205 unsigned int alignment;
207 e->format = wined3d_get_format(adapter, elements[i].format, 0);
208 e->ffp_valid = declaration_element_valid_ffp(&elements[i]);
209 e->input_slot = elements[i].input_slot;
210 e->offset = elements[i].offset;
211 e->output_slot = elements[i].output_slot;
212 e->input_slot_class = elements[i].input_slot_class;
213 e->instance_data_step_rate = elements[i].instance_data_step_rate;
214 e->method = elements[i].method;
215 e->usage = elements[i].usage;
216 e->usage_idx = elements[i].usage_idx;
218 if ((alignment = e->format->byte_count) > 4)
219 alignment = 4;
221 if (e->usage == WINED3D_DECL_USAGE_POSITIONT)
222 declaration->position_transformed = TRUE;
224 /* Find the streams used in the declaration. The vertex buffers have
225 * to be loaded when drawing, but filter tessellation pseudo streams. */
226 if (e->input_slot >= WINED3D_MAX_STREAMS)
227 continue;
229 if (!(e->format->caps[WINED3D_GL_RES_TYPE_BUFFER] & WINED3D_FORMAT_CAP_VERTEX_ATTRIBUTE))
231 FIXME("The application tries to use an unsupported format (%s).\n",
232 debug_d3dformat(elements[i].format));
233 heap_free(declaration->elements);
234 return E_INVALIDARG;
237 if (e->offset == WINED3D_APPEND_ALIGNED_ELEMENT)
239 const struct wined3d_vertex_declaration_element *prev;
240 unsigned int j;
242 e->offset = 0;
243 for (j = 1; j <= i; ++j)
245 prev = &declaration->elements[i - j];
246 if (prev->input_slot == e->input_slot)
248 e->offset = (prev->offset + prev->format->byte_count + alignment - 1) & ~(alignment - 1);
249 break;
254 if (e->offset & (alignment - 1))
256 WARN("Declaration element %u with format %s and offset %u is not %u byte aligned.\n",
257 i, debug_d3dformat(elements[i].format), e->offset, alignment);
258 heap_free(declaration->elements);
259 return E_INVALIDARG;
263 return WINED3D_OK;
266 HRESULT CDECL wined3d_vertex_declaration_create(struct wined3d_device *device,
267 const struct wined3d_vertex_element *elements, UINT element_count, void *parent,
268 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
270 struct wined3d_vertex_declaration *object;
271 HRESULT hr;
273 TRACE("device %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
274 device, elements, element_count, parent, parent_ops, declaration);
276 if (!(object = heap_alloc_zero(sizeof(*object))))
277 return E_OUTOFMEMORY;
279 hr = vertexdeclaration_init(object, device, elements, element_count, parent, parent_ops);
280 if (FAILED(hr))
282 WARN("Failed to initialize vertex declaration, hr %#lx.\n", hr);
283 heap_free(object);
284 return hr;
287 TRACE("Created vertex declaration %p.\n", object);
288 *declaration = object;
290 return WINED3D_OK;
293 struct wined3d_fvf_convert_state
295 const struct wined3d_adapter *adapter;
296 struct wined3d_vertex_element *elements;
297 unsigned int offset;
298 unsigned int idx;
301 static void append_decl_element(struct wined3d_fvf_convert_state *state,
302 enum wined3d_format_id format_id, enum wined3d_decl_usage usage, UINT usage_idx)
304 struct wined3d_vertex_element *elements = state->elements;
305 const struct wined3d_format *format;
306 UINT offset = state->offset;
307 UINT idx = state->idx;
309 elements[idx].format = format_id;
310 elements[idx].input_slot = 0;
311 elements[idx].offset = offset;
312 elements[idx].output_slot = WINED3D_OUTPUT_SLOT_SEMANTIC;
313 elements[idx].input_slot_class = WINED3D_INPUT_PER_VERTEX_DATA;
314 elements[idx].instance_data_step_rate = 0;
315 elements[idx].method = WINED3D_DECL_METHOD_DEFAULT;
316 elements[idx].usage = usage;
317 elements[idx].usage_idx = usage_idx;
319 format = wined3d_get_format(state->adapter, format_id, 0);
320 state->offset += format->byte_count;
321 ++state->idx;
324 static unsigned int convert_fvf_to_declaration(const struct wined3d_adapter *adapter,
325 uint32_t fvf, struct wined3d_vertex_element **elements)
327 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
328 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
329 BOOL has_blend_idx = has_blend &&
330 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
331 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
332 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
333 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
334 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
335 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
336 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
338 unsigned int num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
339 unsigned int texcoords = (fvf & 0xffff0000) >> 16;
340 struct wined3d_fvf_convert_state state;
341 unsigned int size;
342 unsigned int idx;
343 unsigned int num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
344 if (has_blend_idx) num_blends--;
346 /* Compute declaration size */
347 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
348 has_psize + has_diffuse + has_specular + num_textures;
350 state.adapter = adapter;
351 if (!(state.elements = heap_calloc(size, sizeof(*state.elements))))
352 return ~0u;
353 state.offset = 0;
354 state.idx = 0;
356 if (has_pos)
358 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
359 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3D_DECL_USAGE_POSITIONT, 0);
360 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
361 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3D_DECL_USAGE_POSITION, 0);
362 else
363 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3D_DECL_USAGE_POSITION, 0);
366 if (has_blend && (num_blends > 0))
368 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
369 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3D_DECL_USAGE_BLEND_WEIGHT, 0);
370 else
372 switch (num_blends)
374 case 1:
375 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3D_DECL_USAGE_BLEND_WEIGHT, 0);
376 break;
377 case 2:
378 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3D_DECL_USAGE_BLEND_WEIGHT, 0);
379 break;
380 case 3:
381 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3D_DECL_USAGE_BLEND_WEIGHT, 0);
382 break;
383 case 4:
384 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3D_DECL_USAGE_BLEND_WEIGHT, 0);
385 break;
386 default:
387 ERR("Unexpected amount of blend values: %u\n", num_blends);
392 if (has_blend_idx)
394 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
395 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
396 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3D_DECL_USAGE_BLEND_INDICES, 0);
397 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
398 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3D_DECL_USAGE_BLEND_INDICES, 0);
399 else
400 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3D_DECL_USAGE_BLEND_INDICES, 0);
403 if (has_normal)
404 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3D_DECL_USAGE_NORMAL, 0);
405 if (has_psize)
406 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3D_DECL_USAGE_PSIZE, 0);
407 if (has_diffuse)
408 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3D_DECL_USAGE_COLOR, 0);
409 if (has_specular)
410 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3D_DECL_USAGE_COLOR, 1);
412 for (idx = 0; idx < num_textures; ++idx)
414 switch ((texcoords >> (idx * 2)) & 0x03)
416 case WINED3DFVF_TEXTUREFORMAT1:
417 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3D_DECL_USAGE_TEXCOORD, idx);
418 break;
419 case WINED3DFVF_TEXTUREFORMAT2:
420 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3D_DECL_USAGE_TEXCOORD, idx);
421 break;
422 case WINED3DFVF_TEXTUREFORMAT3:
423 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3D_DECL_USAGE_TEXCOORD, idx);
424 break;
425 case WINED3DFVF_TEXTUREFORMAT4:
426 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3D_DECL_USAGE_TEXCOORD, idx);
427 break;
431 *elements = state.elements;
432 return size;
435 HRESULT CDECL wined3d_vertex_declaration_create_from_fvf(struct wined3d_device *device,
436 uint32_t fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
437 struct wined3d_vertex_declaration **declaration)
439 struct wined3d_vertex_element *elements;
440 unsigned int size;
441 DWORD hr;
443 TRACE("device %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
444 device, fvf, parent, parent_ops, declaration);
446 size = convert_fvf_to_declaration(device->adapter, fvf, &elements);
447 if (size == ~0u)
448 return E_OUTOFMEMORY;
450 hr = wined3d_vertex_declaration_create(device, elements, size, parent, parent_ops, declaration);
451 heap_free(elements);
452 return hr;