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