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