xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/nine/vertexdeclaration9.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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