1 /* 2 * IDirect3DVertexDeclaration9 implementation 3 * 4 * Copyright 2002-2003 Raphael Junqueira 5 * Jason Edmeades 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "config.h" 23 #include "d3d9_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(d3d9); 26 27 static const struct 28 { 29 enum wined3d_format_id format; 30 unsigned int component_count; 31 unsigned int component_size; 32 } 33 d3d_dtype_lookup[] = 34 { 35 /* D3DDECLTYPE_FLOAT1 */ {WINED3DFMT_R32_FLOAT, 1, sizeof(float)}, 36 /* D3DDECLTYPE_FLOAT2 */ {WINED3DFMT_R32G32_FLOAT, 2, sizeof(float)}, 37 /* D3DDECLTYPE_FLOAT3 */ {WINED3DFMT_R32G32B32_FLOAT, 3, sizeof(float)}, 38 /* D3DDECLTYPE_FLOAT4 */ {WINED3DFMT_R32G32B32A32_FLOAT, 4, sizeof(float)}, 39 /* D3DDECLTYPE_D3DCOLOR */ {WINED3DFMT_B8G8R8A8_UNORM, 4, sizeof(BYTE)}, 40 /* D3DDECLTYPE_UBYTE4 */ {WINED3DFMT_R8G8B8A8_UINT, 4, sizeof(BYTE)}, 41 /* D3DDECLTYPE_SHORT2 */ {WINED3DFMT_R16G16_SINT, 2, sizeof(short int)}, 42 /* D3DDECLTYPE_SHORT4 */ {WINED3DFMT_R16G16B16A16_SINT, 4, sizeof(short int)}, 43 /* D3DDECLTYPE_UBYTE4N */ {WINED3DFMT_R8G8B8A8_UNORM, 4, sizeof(BYTE)}, 44 /* D3DDECLTYPE_SHORT2N */ {WINED3DFMT_R16G16_SNORM, 2, sizeof(short int)}, 45 /* D3DDECLTYPE_SHORT4N */ {WINED3DFMT_R16G16B16A16_SNORM, 4, sizeof(short int)}, 46 /* D3DDECLTYPE_USHORT2N */ {WINED3DFMT_R16G16_UNORM, 2, sizeof(short int)}, 47 /* D3DDECLTYPE_USHORT4N */ {WINED3DFMT_R16G16B16A16_UNORM, 4, sizeof(short int)}, 48 /* D3DDECLTYPE_UDEC3 */ {WINED3DFMT_R10G10B10X2_UINT, 3, sizeof(short int)}, 49 /* D3DDECLTYPE_DEC3N */ {WINED3DFMT_R10G10B10X2_SNORM, 3, sizeof(short int)}, 50 /* D3DDECLTYPE_FLOAT16_2 */ {WINED3DFMT_R16G16_FLOAT, 2, sizeof(short int)}, 51 /* D3DDECLTYPE_FLOAT16_4 */ {WINED3DFMT_R16G16B16A16_FLOAT, 4, sizeof(short int)} 52 }; 53 54 static inline struct d3d9_vertex_declaration *impl_from_IDirect3DVertexDeclaration9(IDirect3DVertexDeclaration9 *iface) 55 { 56 return CONTAINING_RECORD(iface, struct d3d9_vertex_declaration, IDirect3DVertexDeclaration9_iface); 57 } 58 59 HRESULT vdecl_convert_fvf( 60 DWORD fvf, 61 D3DVERTEXELEMENT9** ppVertexElements) { 62 63 unsigned int idx, idx2; 64 unsigned int offset; 65 BOOL has_pos = (fvf & D3DFVF_POSITION_MASK) != 0; 66 BOOL has_blend = (fvf & D3DFVF_XYZB5) > D3DFVF_XYZRHW; 67 BOOL has_blend_idx = has_blend && 68 (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB5) || 69 (fvf & D3DFVF_LASTBETA_D3DCOLOR) || 70 (fvf & D3DFVF_LASTBETA_UBYTE4)); 71 BOOL has_normal = (fvf & D3DFVF_NORMAL) != 0; 72 BOOL has_psize = (fvf & D3DFVF_PSIZE) != 0; 73 74 BOOL has_diffuse = (fvf & D3DFVF_DIFFUSE) != 0; 75 BOOL has_specular = (fvf & D3DFVF_SPECULAR) !=0; 76 77 DWORD num_textures = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; 78 DWORD texcoords = (fvf & 0xFFFF0000) >> 16; 79 80 D3DVERTEXELEMENT9 end_element = D3DDECL_END(); 81 D3DVERTEXELEMENT9 *elements = NULL; 82 83 unsigned int size; 84 DWORD num_blends = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1); 85 if (has_blend_idx) num_blends--; 86 87 /* Compute declaration size */ 88 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal + 89 has_psize + has_diffuse + has_specular + num_textures + 1; 90 91 /* convert the declaration */ 92 if (!(elements = heap_alloc(size * sizeof(*elements)))) 93 return D3DERR_OUTOFVIDEOMEMORY; 94 95 elements[size-1] = end_element; 96 idx = 0; 97 if (has_pos) { 98 if (!has_blend && (fvf & D3DFVF_XYZRHW)) { 99 elements[idx].Type = D3DDECLTYPE_FLOAT4; 100 elements[idx].Usage = D3DDECLUSAGE_POSITIONT; 101 } 102 else if (!has_blend && (fvf & D3DFVF_XYZW) == D3DFVF_XYZW) { 103 elements[idx].Type = D3DDECLTYPE_FLOAT4; 104 elements[idx].Usage = D3DDECLUSAGE_POSITION; 105 } 106 else { 107 elements[idx].Type = D3DDECLTYPE_FLOAT3; 108 elements[idx].Usage = D3DDECLUSAGE_POSITION; 109 } 110 elements[idx].UsageIndex = 0; 111 idx++; 112 } 113 if (has_blend && (num_blends > 0)) { 114 if (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR)) 115 elements[idx].Type = D3DDECLTYPE_D3DCOLOR; 116 else { 117 switch(num_blends) { 118 case 1: elements[idx].Type = D3DDECLTYPE_FLOAT1; break; 119 case 2: elements[idx].Type = D3DDECLTYPE_FLOAT2; break; 120 case 3: elements[idx].Type = D3DDECLTYPE_FLOAT3; break; 121 case 4: elements[idx].Type = D3DDECLTYPE_FLOAT4; break; 122 default: 123 ERR("Unexpected amount of blend values: %u\n", num_blends); 124 } 125 } 126 elements[idx].Usage = D3DDECLUSAGE_BLENDWEIGHT; 127 elements[idx].UsageIndex = 0; 128 idx++; 129 } 130 if (has_blend_idx) { 131 if (fvf & D3DFVF_LASTBETA_UBYTE4 || 132 (((fvf & D3DFVF_XYZB5) == D3DFVF_XYZB2) && (fvf & D3DFVF_LASTBETA_D3DCOLOR))) 133 elements[idx].Type = D3DDECLTYPE_UBYTE4; 134 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR) 135 elements[idx].Type = D3DDECLTYPE_D3DCOLOR; 136 else 137 elements[idx].Type = D3DDECLTYPE_FLOAT1; 138 elements[idx].Usage = D3DDECLUSAGE_BLENDINDICES; 139 elements[idx].UsageIndex = 0; 140 idx++; 141 } 142 if (has_normal) { 143 elements[idx].Type = D3DDECLTYPE_FLOAT3; 144 elements[idx].Usage = D3DDECLUSAGE_NORMAL; 145 elements[idx].UsageIndex = 0; 146 idx++; 147 } 148 if (has_psize) { 149 elements[idx].Type = D3DDECLTYPE_FLOAT1; 150 elements[idx].Usage = D3DDECLUSAGE_PSIZE; 151 elements[idx].UsageIndex = 0; 152 idx++; 153 } 154 if (has_diffuse) { 155 elements[idx].Type = D3DDECLTYPE_D3DCOLOR; 156 elements[idx].Usage = D3DDECLUSAGE_COLOR; 157 elements[idx].UsageIndex = 0; 158 idx++; 159 } 160 if (has_specular) { 161 elements[idx].Type = D3DDECLTYPE_D3DCOLOR; 162 elements[idx].Usage = D3DDECLUSAGE_COLOR; 163 elements[idx].UsageIndex = 1; 164 idx++; 165 } 166 for (idx2 = 0; idx2 < num_textures; idx2++) { 167 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03; 168 switch (numcoords) { 169 case D3DFVF_TEXTUREFORMAT1: 170 elements[idx].Type = D3DDECLTYPE_FLOAT1; 171 break; 172 case D3DFVF_TEXTUREFORMAT2: 173 elements[idx].Type = D3DDECLTYPE_FLOAT2; 174 break; 175 case D3DFVF_TEXTUREFORMAT3: 176 elements[idx].Type = D3DDECLTYPE_FLOAT3; 177 break; 178 case D3DFVF_TEXTUREFORMAT4: 179 elements[idx].Type = D3DDECLTYPE_FLOAT4; 180 break; 181 } 182 elements[idx].Usage = D3DDECLUSAGE_TEXCOORD; 183 elements[idx].UsageIndex = idx2; 184 idx++; 185 } 186 187 /* Now compute offsets, and initialize the rest of the fields */ 188 for (idx = 0, offset = 0; idx < size-1; idx++) { 189 elements[idx].Stream = 0; 190 elements[idx].Method = D3DDECLMETHOD_DEFAULT; 191 elements[idx].Offset = offset; 192 offset += d3d_dtype_lookup[elements[idx].Type].component_count 193 * d3d_dtype_lookup[elements[idx].Type].component_size; 194 } 195 196 *ppVertexElements = elements; 197 return D3D_OK; 198 } 199 200 static HRESULT WINAPI d3d9_vertex_declaration_QueryInterface(IDirect3DVertexDeclaration9 *iface, 201 REFIID riid, void **out) 202 { 203 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); 204 205 if (IsEqualGUID(riid, &IID_IDirect3DVertexDeclaration9) 206 || IsEqualGUID(riid, &IID_IUnknown)) 207 { 208 IDirect3DVertexDeclaration9_AddRef(iface); 209 *out = iface; 210 return S_OK; 211 } 212 213 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 214 215 *out = NULL; 216 return E_NOINTERFACE; 217 } 218 219 static ULONG WINAPI d3d9_vertex_declaration_AddRef(IDirect3DVertexDeclaration9 *iface) 220 { 221 struct d3d9_vertex_declaration *declaration = impl_from_IDirect3DVertexDeclaration9(iface); 222 ULONG refcount = InterlockedIncrement(&declaration->refcount); 223 224 TRACE("%p increasing refcount to %u.\n", iface, refcount); 225 226 if (refcount == 1) 227 { 228 IDirect3DDevice9Ex_AddRef(declaration->parent_device); 229 wined3d_mutex_lock(); 230 wined3d_vertex_declaration_incref(declaration->wined3d_declaration); 231 wined3d_mutex_unlock(); 232 } 233 234 return refcount; 235 } 236 237 static ULONG WINAPI d3d9_vertex_declaration_Release(IDirect3DVertexDeclaration9 *iface) 238 { 239 struct d3d9_vertex_declaration *declaration = impl_from_IDirect3DVertexDeclaration9(iface); 240 ULONG refcount = InterlockedDecrement(&declaration->refcount); 241 242 TRACE("%p decreasing refcount to %u.\n", iface, refcount); 243 244 if (!refcount) 245 { 246 IDirect3DDevice9Ex *parent_device = declaration->parent_device; 247 wined3d_mutex_lock(); 248 wined3d_vertex_declaration_decref(declaration->wined3d_declaration); 249 wined3d_mutex_unlock(); 250 251 /* Release the device last, as it may cause the device to be destroyed. */ 252 IDirect3DDevice9Ex_Release(parent_device); 253 } 254 255 return refcount; 256 } 257 258 static HRESULT WINAPI d3d9_vertex_declaration_GetDevice(IDirect3DVertexDeclaration9 *iface, IDirect3DDevice9 **device) 259 { 260 struct d3d9_vertex_declaration *declaration = impl_from_IDirect3DVertexDeclaration9(iface); 261 262 TRACE("iface %p, device %p.\n", iface, device); 263 264 *device = (IDirect3DDevice9 *)declaration->parent_device; 265 IDirect3DDevice9_AddRef(*device); 266 267 TRACE("Returning device %p.\n", *device); 268 269 return D3D_OK; 270 } 271 272 static HRESULT WINAPI d3d9_vertex_declaration_GetDeclaration(IDirect3DVertexDeclaration9 *iface, 273 D3DVERTEXELEMENT9 *elements, UINT *element_count) 274 { 275 struct d3d9_vertex_declaration *declaration = impl_from_IDirect3DVertexDeclaration9(iface); 276 277 TRACE("iface %p, elements %p, element_count %p.\n", iface, elements, element_count); 278 279 *element_count = declaration->element_count; 280 281 /* Passing a NULL elements is used to just retrieve the number of elements */ 282 if (!elements) 283 return D3D_OK; 284 285 TRACE("Copying %p to %p.\n", declaration->elements, elements); 286 memcpy(elements, declaration->elements, sizeof(*declaration->elements) * declaration->element_count); 287 288 return D3D_OK; 289 } 290 291 static const struct IDirect3DVertexDeclaration9Vtbl d3d9_vertex_declaration_vtbl = 292 { 293 /* IUnknown */ 294 d3d9_vertex_declaration_QueryInterface, 295 d3d9_vertex_declaration_AddRef, 296 d3d9_vertex_declaration_Release, 297 /* IDirect3DVertexDeclaration9 */ 298 d3d9_vertex_declaration_GetDevice, 299 d3d9_vertex_declaration_GetDeclaration, 300 }; 301 302 struct d3d9_vertex_declaration *unsafe_impl_from_IDirect3DVertexDeclaration9(IDirect3DVertexDeclaration9 *iface) 303 { 304 if (!iface) 305 return NULL; 306 assert(iface->lpVtbl == &d3d9_vertex_declaration_vtbl); 307 return CONTAINING_RECORD(iface, struct d3d9_vertex_declaration, IDirect3DVertexDeclaration9_iface); 308 } 309 310 static void STDMETHODCALLTYPE d3d9_vertexdeclaration_wined3d_object_destroyed(void *parent) 311 { 312 struct d3d9_vertex_declaration *declaration = parent; 313 heap_free(declaration->elements); 314 heap_free(declaration); 315 } 316 317 static const struct wined3d_parent_ops d3d9_vertexdeclaration_wined3d_parent_ops = 318 { 319 d3d9_vertexdeclaration_wined3d_object_destroyed, 320 }; 321 322 static HRESULT convert_to_wined3d_declaration(const D3DVERTEXELEMENT9 *d3d9_elements, 323 struct wined3d_vertex_element **wined3d_elements, UINT *element_count) 324 { 325 const D3DVERTEXELEMENT9* element; 326 UINT count = 1; 327 UINT i; 328 329 TRACE("d3d9_elements %p, wined3d_elements %p, element_count %p\n", d3d9_elements, wined3d_elements, element_count); 330 331 element = d3d9_elements; 332 while (element++->Stream != 0xff && count++ < 128); 333 334 if (count == 128) return E_FAIL; 335 336 /* Skip the END element */ 337 --count; 338 339 if (!(*wined3d_elements = heap_alloc(count * sizeof(**wined3d_elements)))) 340 { 341 FIXME("Memory allocation failed\n"); 342 return D3DERR_OUTOFVIDEOMEMORY; 343 } 344 345 for (i = 0; i < count; ++i) 346 { 347 if (d3d9_elements[i].Type >= ARRAY_SIZE(d3d_dtype_lookup)) 348 { 349 WARN("Invalid element type %#x.\n", d3d9_elements[i].Type); 350 heap_free(*wined3d_elements); 351 return E_FAIL; 352 } 353 (*wined3d_elements)[i].format = d3d_dtype_lookup[d3d9_elements[i].Type].format; 354 (*wined3d_elements)[i].input_slot = d3d9_elements[i].Stream; 355 (*wined3d_elements)[i].offset = d3d9_elements[i].Offset; 356 (*wined3d_elements)[i].output_slot = WINED3D_OUTPUT_SLOT_SEMANTIC; 357 (*wined3d_elements)[i].input_slot_class = WINED3D_INPUT_PER_VERTEX_DATA; 358 (*wined3d_elements)[i].instance_data_step_rate = 0; 359 (*wined3d_elements)[i].method = d3d9_elements[i].Method; 360 (*wined3d_elements)[i].usage = d3d9_elements[i].Usage; 361 (*wined3d_elements)[i].usage_idx = d3d9_elements[i].UsageIndex; 362 } 363 364 *element_count = count; 365 366 return D3D_OK; 367 } 368 369 static HRESULT vertexdeclaration_init(struct d3d9_vertex_declaration *declaration, 370 struct d3d9_device *device, const D3DVERTEXELEMENT9 *elements) 371 { 372 struct wined3d_vertex_element *wined3d_elements; 373 UINT wined3d_element_count; 374 UINT element_count; 375 HRESULT hr; 376 377 hr = convert_to_wined3d_declaration(elements, &wined3d_elements, &wined3d_element_count); 378 if (FAILED(hr)) 379 { 380 WARN("Failed to create wined3d vertex declaration elements, hr %#x.\n", hr); 381 return hr; 382 } 383 384 declaration->IDirect3DVertexDeclaration9_iface.lpVtbl = &d3d9_vertex_declaration_vtbl; 385 declaration->refcount = 1; 386 387 element_count = wined3d_element_count + 1; 388 if (!(declaration->elements = heap_alloc(element_count * sizeof(*declaration->elements)))) 389 { 390 heap_free(wined3d_elements); 391 ERR("Failed to allocate vertex declaration elements memory.\n"); 392 return D3DERR_OUTOFVIDEOMEMORY; 393 } 394 memcpy(declaration->elements, elements, element_count * sizeof(*elements)); 395 declaration->element_count = element_count; 396 397 wined3d_mutex_lock(); 398 hr = wined3d_vertex_declaration_create(device->wined3d_device, wined3d_elements, wined3d_element_count, 399 declaration, &d3d9_vertexdeclaration_wined3d_parent_ops, &declaration->wined3d_declaration); 400 wined3d_mutex_unlock(); 401 heap_free(wined3d_elements); 402 if (FAILED(hr)) 403 { 404 heap_free(declaration->elements); 405 WARN("Failed to create wined3d vertex declaration, hr %#x.\n", hr); 406 return hr; 407 } 408 409 declaration->parent_device = &device->IDirect3DDevice9Ex_iface; 410 IDirect3DDevice9Ex_AddRef(declaration->parent_device); 411 412 return D3D_OK; 413 } 414 415 HRESULT d3d9_vertex_declaration_create(struct d3d9_device *device, 416 const D3DVERTEXELEMENT9 *elements, struct d3d9_vertex_declaration **declaration) 417 { 418 struct d3d9_vertex_declaration *object; 419 HRESULT hr; 420 421 if (!(object = heap_alloc_zero(sizeof(*object)))) 422 return E_OUTOFMEMORY; 423 424 hr = vertexdeclaration_init(object, device, elements); 425 if (FAILED(hr)) 426 { 427 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr); 428 heap_free(object); 429 return hr; 430 } 431 432 TRACE("Created vertex declaration %p.\n", object); 433 *declaration = object; 434 435 return D3D_OK; 436 } 437