1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22b8e80941Smrg 23b8e80941Smrg#include "vertexdeclaration9.h" 24b8e80941Smrg#include "vertexbuffer9.h" 25b8e80941Smrg#include "device9.h" 26b8e80941Smrg#include "nine_helpers.h" 27b8e80941Smrg#include "nine_shader.h" 28b8e80941Smrg 29b8e80941Smrg#include "pipe/p_format.h" 30b8e80941Smrg#include "pipe/p_context.h" 31b8e80941Smrg#include "util/u_math.h" 32b8e80941Smrg#include "util/u_format.h" 33b8e80941Smrg#include "translate/translate.h" 34b8e80941Smrg 35b8e80941Smrg#define DBG_CHANNEL DBG_VERTEXDECLARATION 36b8e80941Smrg 37b8e80941Smrgstatic inline enum pipe_format decltype_format(BYTE type) 38b8e80941Smrg{ 39b8e80941Smrg switch (type) { 40b8e80941Smrg case D3DDECLTYPE_FLOAT1: return PIPE_FORMAT_R32_FLOAT; 41b8e80941Smrg case D3DDECLTYPE_FLOAT2: return PIPE_FORMAT_R32G32_FLOAT; 42b8e80941Smrg case D3DDECLTYPE_FLOAT3: return PIPE_FORMAT_R32G32B32_FLOAT; 43b8e80941Smrg case D3DDECLTYPE_FLOAT4: return PIPE_FORMAT_R32G32B32A32_FLOAT; 44b8e80941Smrg case D3DDECLTYPE_D3DCOLOR: return PIPE_FORMAT_B8G8R8A8_UNORM; 45b8e80941Smrg case D3DDECLTYPE_UBYTE4: return PIPE_FORMAT_R8G8B8A8_USCALED; 46b8e80941Smrg case D3DDECLTYPE_SHORT2: return PIPE_FORMAT_R16G16_SSCALED; 47b8e80941Smrg case D3DDECLTYPE_SHORT4: return PIPE_FORMAT_R16G16B16A16_SSCALED; 48b8e80941Smrg case D3DDECLTYPE_UBYTE4N: return PIPE_FORMAT_R8G8B8A8_UNORM; 49b8e80941Smrg case D3DDECLTYPE_SHORT2N: return PIPE_FORMAT_R16G16_SNORM; 50b8e80941Smrg case D3DDECLTYPE_SHORT4N: return PIPE_FORMAT_R16G16B16A16_SNORM; 51b8e80941Smrg case D3DDECLTYPE_USHORT2N: return PIPE_FORMAT_R16G16_UNORM; 52b8e80941Smrg case D3DDECLTYPE_USHORT4N: return PIPE_FORMAT_R16G16B16A16_UNORM; 53b8e80941Smrg case D3DDECLTYPE_UDEC3: return PIPE_FORMAT_R10G10B10X2_USCALED; 54b8e80941Smrg case D3DDECLTYPE_DEC3N: return PIPE_FORMAT_R10G10B10X2_SNORM; 55b8e80941Smrg case D3DDECLTYPE_FLOAT16_2: return PIPE_FORMAT_R16G16_FLOAT; 56b8e80941Smrg case D3DDECLTYPE_FLOAT16_4: return PIPE_FORMAT_R16G16B16A16_FLOAT; 57b8e80941Smrg default: 58b8e80941Smrg assert(!"Implementation error !"); 59b8e80941Smrg } 60b8e80941Smrg return PIPE_FORMAT_NONE; 61b8e80941Smrg} 62b8e80941Smrg 63b8e80941Smrgstatic inline unsigned decltype_size(BYTE type) 64b8e80941Smrg{ 65b8e80941Smrg switch (type) { 66b8e80941Smrg case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float); 67b8e80941Smrg case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float); 68b8e80941Smrg case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float); 69b8e80941Smrg case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float); 70b8e80941Smrg case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD); 71b8e80941Smrg case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE); 72b8e80941Smrg case D3DDECLTYPE_SHORT2: return 2 * sizeof(short); 73b8e80941Smrg case D3DDECLTYPE_SHORT4: return 4 * sizeof(short); 74b8e80941Smrg case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE); 75b8e80941Smrg case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short); 76b8e80941Smrg case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short); 77b8e80941Smrg case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short); 78b8e80941Smrg case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short); 79b8e80941Smrg case D3DDECLTYPE_UDEC3: return 4; 80b8e80941Smrg case D3DDECLTYPE_DEC3N: return 4; 81b8e80941Smrg case D3DDECLTYPE_FLOAT16_2: return 2 * 2; 82b8e80941Smrg case D3DDECLTYPE_FLOAT16_4: return 4 * 2; 83b8e80941Smrg default: 84b8e80941Smrg assert(!"Implementation error !"); 85b8e80941Smrg } 86b8e80941Smrg return 0; 87b8e80941Smrg} 88b8e80941Smrg 89b8e80941Smrg/* Actually, arbitrary usage index values are permitted, but a 90b8e80941Smrg * simple lookup table won't work in that case. Let's just wait 91b8e80941Smrg * with making this more generic until we need it. 92b8e80941Smrg */ 93b8e80941Smrgstatic inline boolean 94b8e80941Smrgnine_d3ddeclusage_check(unsigned usage, unsigned usage_idx) 95b8e80941Smrg{ 96b8e80941Smrg switch (usage) { 97b8e80941Smrg case D3DDECLUSAGE_POSITIONT: 98b8e80941Smrg case D3DDECLUSAGE_TESSFACTOR: 99b8e80941Smrg case D3DDECLUSAGE_DEPTH: 100b8e80941Smrg case D3DDECLUSAGE_NORMAL: 101b8e80941Smrg case D3DDECLUSAGE_TANGENT: 102b8e80941Smrg case D3DDECLUSAGE_BINORMAL: 103b8e80941Smrg case D3DDECLUSAGE_POSITION: 104b8e80941Smrg case D3DDECLUSAGE_BLENDWEIGHT: 105b8e80941Smrg case D3DDECLUSAGE_BLENDINDICES: 106b8e80941Smrg case D3DDECLUSAGE_COLOR: 107b8e80941Smrg return TRUE; 108b8e80941Smrg case D3DDECLUSAGE_PSIZE: 109b8e80941Smrg case D3DDECLUSAGE_FOG: 110b8e80941Smrg case D3DDECLUSAGE_SAMPLE: 111b8e80941Smrg return usage_idx <= 0; 112b8e80941Smrg case D3DDECLUSAGE_TEXCOORD: 113b8e80941Smrg return usage_idx <= 15; 114b8e80941Smrg default: 115b8e80941Smrg return FALSE; 116b8e80941Smrg } 117b8e80941Smrg} 118b8e80941Smrg 119b8e80941Smrg#define NINE_DECLUSAGE_CASE0(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n 120b8e80941Smrg#define NINE_DECLUSAGE_CASEi(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_i(n, usage_idx) 121b8e80941Smrguint16_t 122b8e80941Smrgnine_d3d9_to_nine_declusage(unsigned usage, unsigned usage_idx) 123b8e80941Smrg{ 124b8e80941Smrg if (!nine_d3ddeclusage_check(usage, usage_idx)) 125b8e80941Smrg ERR("D3DDECLUSAGE_%u[%u]\n",usage,usage_idx); 126b8e80941Smrg assert(nine_d3ddeclusage_check(usage, usage_idx)); 127b8e80941Smrg switch (usage) { 128b8e80941Smrg NINE_DECLUSAGE_CASEi(POSITION); 129b8e80941Smrg NINE_DECLUSAGE_CASEi(BLENDWEIGHT); 130b8e80941Smrg NINE_DECLUSAGE_CASEi(BLENDINDICES); 131b8e80941Smrg NINE_DECLUSAGE_CASEi(NORMAL); 132b8e80941Smrg NINE_DECLUSAGE_CASE0(PSIZE); 133b8e80941Smrg NINE_DECLUSAGE_CASEi(TEXCOORD); 134b8e80941Smrg NINE_DECLUSAGE_CASEi(TANGENT); 135b8e80941Smrg NINE_DECLUSAGE_CASEi(BINORMAL); 136b8e80941Smrg NINE_DECLUSAGE_CASE0(TESSFACTOR); 137b8e80941Smrg NINE_DECLUSAGE_CASEi(POSITIONT); 138b8e80941Smrg NINE_DECLUSAGE_CASEi(COLOR); 139b8e80941Smrg NINE_DECLUSAGE_CASE0(DEPTH); 140b8e80941Smrg NINE_DECLUSAGE_CASE0(FOG); 141b8e80941Smrg NINE_DECLUSAGE_CASE0(SAMPLE); 142b8e80941Smrg default: 143b8e80941Smrg assert(!"Invalid DECLUSAGE."); 144b8e80941Smrg return NINE_DECLUSAGE_NONE; 145b8e80941Smrg } 146b8e80941Smrg} 147b8e80941Smrg 148b8e80941Smrgstatic const char *nine_declusage_names[] = 149b8e80941Smrg{ 150b8e80941Smrg [NINE_DECLUSAGE_POSITION] = "POSITION", 151b8e80941Smrg [NINE_DECLUSAGE_BLENDWEIGHT] = "BLENDWEIGHT", 152b8e80941Smrg [NINE_DECLUSAGE_BLENDINDICES] = "BLENDINDICES", 153b8e80941Smrg [NINE_DECLUSAGE_NORMAL] = "NORMAL", 154b8e80941Smrg [NINE_DECLUSAGE_PSIZE] = "PSIZE", 155b8e80941Smrg [NINE_DECLUSAGE_TEXCOORD] = "TEXCOORD", 156b8e80941Smrg [NINE_DECLUSAGE_TANGENT] = "TANGENT", 157b8e80941Smrg [NINE_DECLUSAGE_BINORMAL] = "BINORMAL", 158b8e80941Smrg [NINE_DECLUSAGE_TESSFACTOR] = "TESSFACTOR", 159b8e80941Smrg [NINE_DECLUSAGE_POSITIONT] = "POSITIONT", 160b8e80941Smrg [NINE_DECLUSAGE_COLOR] = "DIFFUSE", 161b8e80941Smrg [NINE_DECLUSAGE_DEPTH] = "DEPTH", 162b8e80941Smrg [NINE_DECLUSAGE_FOG] = "FOG", 163b8e80941Smrg [NINE_DECLUSAGE_NONE] = "(NONE)", 164b8e80941Smrg}; 165b8e80941Smrgstatic inline const char * 166b8e80941Smrgnine_declusage_name(unsigned ndcl) 167b8e80941Smrg{ 168b8e80941Smrg return nine_declusage_names[ndcl % NINE_DECLUSAGE_COUNT]; 169b8e80941Smrg} 170b8e80941Smrg 171b8e80941SmrgHRESULT 172b8e80941SmrgNineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This, 173b8e80941Smrg struct NineUnknownParams *pParams, 174b8e80941Smrg const D3DVERTEXELEMENT9 *pElements ) 175b8e80941Smrg{ 176b8e80941Smrg const D3DCAPS9 *caps; 177b8e80941Smrg unsigned i, nelems; 178b8e80941Smrg DBG("This=%p pParams=%p pElements=%p\n", This, pParams, pElements); 179b8e80941Smrg 180b8e80941Smrg /* wine */ 181b8e80941Smrg for (nelems = 0; 182b8e80941Smrg pElements[nelems].Stream != 0xFF; 183b8e80941Smrg ++nelems) { 184b8e80941Smrg user_assert(pElements[nelems].Type != D3DDECLTYPE_UNUSED, E_FAIL); 185b8e80941Smrg user_assert(!(pElements[nelems].Offset & 3), E_FAIL); 186b8e80941Smrg } 187b8e80941Smrg 188b8e80941Smrg caps = NineDevice9_GetCaps(pParams->device); 189b8e80941Smrg user_assert(nelems <= caps->MaxStreams, D3DERR_INVALIDCALL); 190b8e80941Smrg 191b8e80941Smrg HRESULT hr = NineUnknown_ctor(&This->base, pParams); 192b8e80941Smrg if (FAILED(hr)) { return hr; } 193b8e80941Smrg 194b8e80941Smrg This->nelems = nelems; 195b8e80941Smrg This->decls = CALLOC(This->nelems+1, sizeof(D3DVERTEXELEMENT9)); 196b8e80941Smrg This->elems = CALLOC(This->nelems, sizeof(struct pipe_vertex_element)); 197b8e80941Smrg This->usage_map = CALLOC(This->nelems, sizeof(uint16_t)); 198b8e80941Smrg if (!This->decls || !This->elems || !This->usage_map) { return E_OUTOFMEMORY; } 199b8e80941Smrg memcpy(This->decls, pElements, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1)); 200b8e80941Smrg 201b8e80941Smrg for (i = 0; i < This->nelems; ++i) { 202b8e80941Smrg uint16_t usage = nine_d3d9_to_nine_declusage(This->decls[i].Usage, 203b8e80941Smrg This->decls[i].UsageIndex); 204b8e80941Smrg This->usage_map[i] = usage; 205b8e80941Smrg 206b8e80941Smrg if (This->decls[i].Usage == D3DDECLUSAGE_POSITIONT) 207b8e80941Smrg This->position_t = TRUE; 208b8e80941Smrg 209b8e80941Smrg This->elems[i].src_offset = This->decls[i].Offset; 210b8e80941Smrg This->elems[i].instance_divisor = 0; 211b8e80941Smrg This->elems[i].vertex_buffer_index = This->decls[i].Stream; 212b8e80941Smrg This->elems[i].src_format = decltype_format(This->decls[i].Type); 213b8e80941Smrg /* XXX Remember Method (tesselation), Usage, UsageIndex */ 214b8e80941Smrg 215b8e80941Smrg DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s%d\n", i, 216b8e80941Smrg This->decls[i].Stream, 217b8e80941Smrg This->decls[i].Offset, 218b8e80941Smrg util_format_name(This->elems[i].src_format), 219b8e80941Smrg nine_declusage_name(usage), 220b8e80941Smrg usage / NINE_DECLUSAGE_COUNT); 221b8e80941Smrg } 222b8e80941Smrg 223b8e80941Smrg return D3D_OK; 224b8e80941Smrg} 225b8e80941Smrg 226b8e80941Smrgvoid 227b8e80941SmrgNineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This ) 228b8e80941Smrg{ 229b8e80941Smrg DBG("This=%p\n", This); 230b8e80941Smrg 231b8e80941Smrg FREE(This->decls); 232b8e80941Smrg FREE(This->elems); 233b8e80941Smrg FREE(This->usage_map); 234b8e80941Smrg 235b8e80941Smrg NineUnknown_dtor(&This->base); 236b8e80941Smrg} 237b8e80941Smrg 238b8e80941SmrgHRESULT NINE_WINAPI 239b8e80941SmrgNineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This, 240b8e80941Smrg D3DVERTEXELEMENT9 *pElement, 241b8e80941Smrg UINT *pNumElements ) 242b8e80941Smrg{ 243b8e80941Smrg if (!pElement) { 244b8e80941Smrg user_assert(pNumElements, D3DERR_INVALIDCALL); 245b8e80941Smrg *pNumElements = This->nelems+1; 246b8e80941Smrg return D3D_OK; 247b8e80941Smrg } 248b8e80941Smrg if (pNumElements) { *pNumElements = This->nelems+1; } 249b8e80941Smrg memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1)); 250b8e80941Smrg return D3D_OK; 251b8e80941Smrg} 252b8e80941Smrg 253b8e80941SmrgIDirect3DVertexDeclaration9Vtbl NineVertexDeclaration9_vtable = { 254b8e80941Smrg (void *)NineUnknown_QueryInterface, 255b8e80941Smrg (void *)NineUnknown_AddRef, 256b8e80941Smrg (void *)NineUnknown_Release, 257b8e80941Smrg (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */ 258b8e80941Smrg (void *)NineVertexDeclaration9_GetDeclaration 259b8e80941Smrg}; 260b8e80941Smrg 261b8e80941Smrgstatic const GUID *NineVertexDeclaration9_IIDs[] = { 262b8e80941Smrg &IID_IDirect3DVertexDeclaration9, 263b8e80941Smrg &IID_IUnknown, 264b8e80941Smrg NULL 265b8e80941Smrg}; 266b8e80941Smrg 267b8e80941SmrgHRESULT 268b8e80941SmrgNineVertexDeclaration9_new( struct NineDevice9 *pDevice, 269b8e80941Smrg const D3DVERTEXELEMENT9 *pElements, 270b8e80941Smrg struct NineVertexDeclaration9 **ppOut ) 271b8e80941Smrg{ 272b8e80941Smrg NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements); 273b8e80941Smrg} 274b8e80941Smrg 275b8e80941SmrgHRESULT 276b8e80941SmrgNineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice, 277b8e80941Smrg DWORD FVF, 278b8e80941Smrg struct NineVertexDeclaration9 **ppOut ) 279b8e80941Smrg{ 280b8e80941Smrg D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END(); 281b8e80941Smrg unsigned texcount, i, betas, nelems = 0; 282b8e80941Smrg BYTE beta_index = 0xFF; 283b8e80941Smrg 284b8e80941Smrg switch (FVF & D3DFVF_POSITION_MASK) { 285b8e80941Smrg case D3DFVF_XYZ: /* simple XYZ */ 286b8e80941Smrg case D3DFVF_XYZB1: 287b8e80941Smrg case D3DFVF_XYZB2: 288b8e80941Smrg case D3DFVF_XYZB3: 289b8e80941Smrg case D3DFVF_XYZB4: 290b8e80941Smrg case D3DFVF_XYZB5: /* XYZ with beta values */ 291b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT3; 292b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_POSITION; 293b8e80941Smrg elems[nelems].UsageIndex = 0; 294b8e80941Smrg ++nelems; 295b8e80941Smrg /* simple XYZ has no beta values. break. */ 296b8e80941Smrg if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; } 297b8e80941Smrg 298b8e80941Smrg betas = (((FVF & D3DFVF_XYZB5)-D3DFVF_XYZB1)>>1)+1; 299b8e80941Smrg if (FVF & D3DFVF_LASTBETA_D3DCOLOR) { 300b8e80941Smrg beta_index = D3DDECLTYPE_D3DCOLOR; 301b8e80941Smrg } else if (FVF & D3DFVF_LASTBETA_UBYTE4) { 302b8e80941Smrg beta_index = D3DDECLTYPE_UBYTE4; 303b8e80941Smrg } else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5) { 304b8e80941Smrg beta_index = D3DDECLTYPE_FLOAT1; 305b8e80941Smrg } 306b8e80941Smrg if (beta_index != 0xFF) { --betas; } 307b8e80941Smrg 308b8e80941Smrg if (betas > 0) { 309b8e80941Smrg switch (betas) { 310b8e80941Smrg case 1: elems[nelems].Type = D3DDECLTYPE_FLOAT1; break; 311b8e80941Smrg case 2: elems[nelems].Type = D3DDECLTYPE_FLOAT2; break; 312b8e80941Smrg case 3: elems[nelems].Type = D3DDECLTYPE_FLOAT3; break; 313b8e80941Smrg case 4: elems[nelems].Type = D3DDECLTYPE_FLOAT4; break; 314b8e80941Smrg default: 315b8e80941Smrg assert(!"Implementation error!"); 316b8e80941Smrg } 317b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT; 318b8e80941Smrg elems[nelems].UsageIndex = 0; 319b8e80941Smrg ++nelems; 320b8e80941Smrg } 321b8e80941Smrg 322b8e80941Smrg if (beta_index != 0xFF) { 323b8e80941Smrg elems[nelems].Type = beta_index; 324b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES; 325b8e80941Smrg elems[nelems].UsageIndex = 0; 326b8e80941Smrg ++nelems; 327b8e80941Smrg } 328b8e80941Smrg break; 329b8e80941Smrg 330b8e80941Smrg case D3DFVF_XYZW: /* simple XYZW */ 331b8e80941Smrg case D3DFVF_XYZRHW: /* pretransformed XYZW */ 332b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT4; 333b8e80941Smrg elems[nelems].Usage = 334b8e80941Smrg ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW) ? 335b8e80941Smrg D3DDECLUSAGE_POSITION : D3DDECLUSAGE_POSITIONT; 336b8e80941Smrg elems[nelems].UsageIndex = 0; 337b8e80941Smrg ++nelems; 338b8e80941Smrg break; 339b8e80941Smrg 340b8e80941Smrg default: 341b8e80941Smrg (void)user_error(!"Position doesn't match any known combination"); 342b8e80941Smrg } 343b8e80941Smrg 344b8e80941Smrg /* normals, psize and colors */ 345b8e80941Smrg if (FVF & D3DFVF_NORMAL) { 346b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT3; 347b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_NORMAL; 348b8e80941Smrg elems[nelems].UsageIndex = 0; 349b8e80941Smrg ++nelems; 350b8e80941Smrg } 351b8e80941Smrg if (FVF & D3DFVF_PSIZE) { 352b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT1; 353b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_PSIZE; 354b8e80941Smrg elems[nelems].UsageIndex = 0; 355b8e80941Smrg ++nelems; 356b8e80941Smrg } 357b8e80941Smrg if (FVF & D3DFVF_DIFFUSE) { 358b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_D3DCOLOR; 359b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_COLOR; 360b8e80941Smrg elems[nelems].UsageIndex = 0; 361b8e80941Smrg ++nelems; 362b8e80941Smrg } 363b8e80941Smrg if (FVF & D3DFVF_SPECULAR) { 364b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_D3DCOLOR; 365b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_COLOR; 366b8e80941Smrg elems[nelems].UsageIndex = 1; 367b8e80941Smrg ++nelems; 368b8e80941Smrg } 369b8e80941Smrg 370b8e80941Smrg /* textures */ 371b8e80941Smrg texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; 372b8e80941Smrg if (user_error(texcount <= 8)) { texcount = 8; } 373b8e80941Smrg 374b8e80941Smrg for (i = 0; i < texcount; ++i) { 375b8e80941Smrg switch ((FVF >> (16+i*2)) & 0x3) { 376b8e80941Smrg case D3DFVF_TEXTUREFORMAT1: 377b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT1; 378b8e80941Smrg break; 379b8e80941Smrg 380b8e80941Smrg case D3DFVF_TEXTUREFORMAT2: 381b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT2; 382b8e80941Smrg break; 383b8e80941Smrg 384b8e80941Smrg case D3DFVF_TEXTUREFORMAT3: 385b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT3; 386b8e80941Smrg break; 387b8e80941Smrg 388b8e80941Smrg case D3DFVF_TEXTUREFORMAT4: 389b8e80941Smrg elems[nelems].Type = D3DDECLTYPE_FLOAT4; 390b8e80941Smrg break; 391b8e80941Smrg 392b8e80941Smrg default: 393b8e80941Smrg assert(!"Implementation error!"); 394b8e80941Smrg } 395b8e80941Smrg elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD; 396b8e80941Smrg elems[nelems].UsageIndex = i; 397b8e80941Smrg ++nelems; 398b8e80941Smrg } 399b8e80941Smrg 400b8e80941Smrg /* fill out remaining data */ 401b8e80941Smrg for (i = 0; i < nelems; ++i) { 402b8e80941Smrg elems[i].Stream = 0; 403b8e80941Smrg elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset + 404b8e80941Smrg decltype_size(elems[i-1].Type)); 405b8e80941Smrg elems[i].Method = D3DDECLMETHOD_DEFAULT; 406b8e80941Smrg } 407b8e80941Smrg elems[nelems++] = decl_end; 408b8e80941Smrg 409b8e80941Smrg NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems); 410b8e80941Smrg} 411b8e80941Smrg 412b8e80941Smrgvoid 413b8e80941SmrgNineVertexDeclaration9_FillStreamOutputInfo( 414b8e80941Smrg struct NineVertexDeclaration9 *This, 415b8e80941Smrg struct nine_vs_output_info *ShaderOutputsInfo, 416b8e80941Smrg unsigned numOutputs, 417b8e80941Smrg struct pipe_stream_output_info *so ) 418b8e80941Smrg{ 419b8e80941Smrg unsigned so_outputs = 0; 420b8e80941Smrg int i, j; 421b8e80941Smrg 422b8e80941Smrg memset(so, 0, sizeof(struct pipe_stream_output_info)); 423b8e80941Smrg 424b8e80941Smrg for (i = 0; i < numOutputs; i++) { 425b8e80941Smrg BYTE output_semantic = ShaderOutputsInfo[i].output_semantic; 426b8e80941Smrg unsigned output_semantic_index = ShaderOutputsInfo[i].output_semantic_index; 427b8e80941Smrg 428b8e80941Smrg for (j = 0; j < This->nelems; j++) { 429b8e80941Smrg if ((This->decls[j].Usage == output_semantic || 430b8e80941Smrg (output_semantic == D3DDECLUSAGE_POSITION && 431b8e80941Smrg This->decls[j].Usage == D3DDECLUSAGE_POSITIONT)) && 432b8e80941Smrg This->decls[j].UsageIndex == output_semantic_index) { 433b8e80941Smrg DBG("Matching %s %d: o%d -> %d\n", 434b8e80941Smrg nine_declusage_name(nine_d3d9_to_nine_declusage(This->decls[j].Usage, 0)), 435b8e80941Smrg This->decls[j].UsageIndex, i, j); 436b8e80941Smrg so->output[so_outputs].register_index = ShaderOutputsInfo[i].output_index; 437b8e80941Smrg so->output[so_outputs].start_component = 0; 438b8e80941Smrg if (ShaderOutputsInfo[i].mask & 8) 439b8e80941Smrg so->output[so_outputs].num_components = 4; 440b8e80941Smrg else if (ShaderOutputsInfo[i].mask & 4) 441b8e80941Smrg so->output[so_outputs].num_components = 3; 442b8e80941Smrg else if (ShaderOutputsInfo[i].mask & 2) 443b8e80941Smrg so->output[so_outputs].num_components = 2; 444b8e80941Smrg else 445b8e80941Smrg so->output[so_outputs].num_components = 1; 446b8e80941Smrg so->output[so_outputs].output_buffer = 0; 447b8e80941Smrg so->output[so_outputs].dst_offset = so_outputs * sizeof(float[4])/4; 448b8e80941Smrg so->output[so_outputs].stream = 0; 449b8e80941Smrg so_outputs++; 450b8e80941Smrg break; 451b8e80941Smrg } 452b8e80941Smrg } 453b8e80941Smrg } 454b8e80941Smrg 455b8e80941Smrg so->num_outputs = so_outputs; 456b8e80941Smrg so->stride[0] = so_outputs * sizeof(float[4])/4; 457b8e80941Smrg} 458b8e80941Smrg 459b8e80941Smrg/* ProcessVertices runs stream output into a temporary buffer to capture 460b8e80941Smrg * all outputs. 461b8e80941Smrg * Now we have to convert them to the format and order set by the vertex 462b8e80941Smrg * declaration, for which we use u_translate. 463b8e80941Smrg * This is necessary if the vertex declaration contains elements using a 464b8e80941Smrg * non float32 format, because stream output only supports f32/u32/s32. 465b8e80941Smrg */ 466b8e80941SmrgHRESULT 467b8e80941SmrgNineVertexDeclaration9_ConvertStreamOutput( 468b8e80941Smrg struct NineVertexDeclaration9 *This, 469b8e80941Smrg struct NineVertexBuffer9 *pDstBuf, 470b8e80941Smrg UINT DestIndex, 471b8e80941Smrg UINT VertexCount, 472b8e80941Smrg void *pSrcBuf, 473b8e80941Smrg const struct pipe_stream_output_info *so ) 474b8e80941Smrg{ 475b8e80941Smrg struct translate *translate; 476b8e80941Smrg struct translate_key transkey; 477b8e80941Smrg HRESULT hr; 478b8e80941Smrg unsigned i; 479b8e80941Smrg void *dst_map; 480b8e80941Smrg 481b8e80941Smrg DBG("This=%p pDstBuf=%p DestIndex=%u VertexCount=%u pSrcBuf=%p so=%p\n", 482b8e80941Smrg This, pDstBuf, DestIndex, VertexCount, pSrcBuf, so); 483b8e80941Smrg 484b8e80941Smrg transkey.output_stride = 0; 485b8e80941Smrg for (i = 0; i < This->nelems; ++i) { 486b8e80941Smrg enum pipe_format format; 487b8e80941Smrg 488b8e80941Smrg switch (so->output[i].num_components) { 489b8e80941Smrg case 1: format = PIPE_FORMAT_R32_FLOAT; break; 490b8e80941Smrg case 2: format = PIPE_FORMAT_R32G32_FLOAT; break; 491b8e80941Smrg case 3: format = PIPE_FORMAT_R32G32B32_FLOAT; break; 492b8e80941Smrg default: 493b8e80941Smrg assert(so->output[i].num_components == 4); 494b8e80941Smrg format = PIPE_FORMAT_R32G32B32A32_FLOAT; 495b8e80941Smrg break; 496b8e80941Smrg } 497b8e80941Smrg transkey.element[i].type = TRANSLATE_ELEMENT_NORMAL; 498b8e80941Smrg transkey.element[i].input_format = format; 499b8e80941Smrg transkey.element[i].input_buffer = 0; 500b8e80941Smrg transkey.element[i].input_offset = so->output[i].dst_offset * 4; 501b8e80941Smrg transkey.element[i].instance_divisor = 0; 502b8e80941Smrg 503b8e80941Smrg transkey.element[i].output_format = This->elems[i].src_format; 504b8e80941Smrg transkey.element[i].output_offset = This->elems[i].src_offset; 505b8e80941Smrg transkey.output_stride += 506b8e80941Smrg util_format_get_blocksize(This->elems[i].src_format); 507b8e80941Smrg 508b8e80941Smrg assert(!(transkey.output_stride & 3)); 509b8e80941Smrg } 510b8e80941Smrg transkey.nr_elements = This->nelems; 511b8e80941Smrg 512b8e80941Smrg translate = translate_create(&transkey); 513b8e80941Smrg if (!translate) 514b8e80941Smrg return E_OUTOFMEMORY; 515b8e80941Smrg 516b8e80941Smrg hr = NineVertexBuffer9_Lock(pDstBuf, 517b8e80941Smrg transkey.output_stride * DestIndex, 518b8e80941Smrg transkey.output_stride * VertexCount, 519b8e80941Smrg &dst_map, D3DLOCK_DISCARD); 520b8e80941Smrg if (FAILED(hr)) 521b8e80941Smrg goto out; 522b8e80941Smrg 523b8e80941Smrg translate->set_buffer(translate, 0, pSrcBuf, so->stride[0] * 4, ~0); 524b8e80941Smrg 525b8e80941Smrg translate->run(translate, 0, VertexCount, 0, 0, dst_map); 526b8e80941Smrg 527b8e80941Smrg NineVertexBuffer9_Unlock(pDstBuf); 528b8e80941Smrgout: 529b8e80941Smrg translate->release(translate); /* TODO: cache these */ 530b8e80941Smrg return hr; 531b8e80941Smrg} 532