1 /*
2  * Copyright 2011 Joakim Sindholt <opensource@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/format/u_format.h"
33 #include "translate/translate.h"
34 
35 #define DBG_CHANNEL DBG_VERTEXDECLARATION
36 
decltype_format(BYTE type)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 
decltype_size(BYTE type)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
nine_d3ddeclusage_check(unsigned usage,unsigned usage_idx)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
nine_d3d9_to_nine_declusage(unsigned usage,unsigned usage_idx)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 *
nine_declusage_name(unsigned ndcl)166 nine_declusage_name(unsigned ndcl)
167 {
168     return nine_declusage_names[ndcl % NINE_DECLUSAGE_COUNT];
169 }
170 
171 HRESULT
NineVertexDeclaration9_ctor(struct NineVertexDeclaration9 * This,struct NineUnknownParams * pParams,const D3DVERTEXELEMENT9 * pElements)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         This->elems[i].dual_slot = false;
214         /* XXX Remember Method (tesselation), Usage, UsageIndex */
215 
216         DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s%d\n", i,
217             This->decls[i].Stream,
218             This->decls[i].Offset,
219             util_format_name(This->elems[i].src_format),
220             nine_declusage_name(usage),
221             usage / NINE_DECLUSAGE_COUNT);
222     }
223 
224     return D3D_OK;
225 }
226 
227 void
NineVertexDeclaration9_dtor(struct NineVertexDeclaration9 * This)228 NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This )
229 {
230     DBG("This=%p\n", This);
231 
232     FREE(This->decls);
233     FREE(This->elems);
234     FREE(This->usage_map);
235 
236     NineUnknown_dtor(&This->base);
237 }
238 
239 HRESULT NINE_WINAPI
NineVertexDeclaration9_GetDeclaration(struct NineVertexDeclaration9 * This,D3DVERTEXELEMENT9 * pElement,UINT * pNumElements)240 NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
241                                        D3DVERTEXELEMENT9 *pElement,
242                                        UINT *pNumElements )
243 {
244     if (!pElement) {
245         user_assert(pNumElements, D3DERR_INVALIDCALL);
246         *pNumElements = This->nelems+1;
247         return D3D_OK;
248     }
249     if (pNumElements) { *pNumElements = This->nelems+1; }
250     memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
251     return D3D_OK;
252 }
253 
254 IDirect3DVertexDeclaration9Vtbl NineVertexDeclaration9_vtable = {
255     (void *)NineUnknown_QueryInterface,
256     (void *)NineUnknown_AddRef,
257     (void *)NineUnknown_Release,
258     (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */
259     (void *)NineVertexDeclaration9_GetDeclaration
260 };
261 
262 static const GUID *NineVertexDeclaration9_IIDs[] = {
263     &IID_IDirect3DVertexDeclaration9,
264     &IID_IUnknown,
265     NULL
266 };
267 
268 HRESULT
NineVertexDeclaration9_new(struct NineDevice9 * pDevice,const D3DVERTEXELEMENT9 * pElements,struct NineVertexDeclaration9 ** ppOut)269 NineVertexDeclaration9_new( struct NineDevice9 *pDevice,
270                             const D3DVERTEXELEMENT9 *pElements,
271                             struct NineVertexDeclaration9 **ppOut )
272 {
273     NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements);
274 }
275 
276 HRESULT
NineVertexDeclaration9_new_from_fvf(struct NineDevice9 * pDevice,DWORD FVF,struct NineVertexDeclaration9 ** ppOut)277 NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice,
278                                      DWORD FVF,
279                                      struct NineVertexDeclaration9 **ppOut )
280 {
281     D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END();
282     unsigned texcount, i, betas, nelems = 0;
283     BYTE beta_index = 0xFF;
284 
285     switch (FVF & D3DFVF_POSITION_MASK) {
286         case D3DFVF_XYZ: /* simple XYZ */
287         case D3DFVF_XYZB1:
288         case D3DFVF_XYZB2:
289         case D3DFVF_XYZB3:
290         case D3DFVF_XYZB4:
291         case D3DFVF_XYZB5: /* XYZ with beta values */
292             elems[nelems].Type = D3DDECLTYPE_FLOAT3;
293             elems[nelems].Usage = D3DDECLUSAGE_POSITION;
294             elems[nelems].UsageIndex = 0;
295             ++nelems;
296             /* simple XYZ has no beta values. break. */
297             if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; }
298 
299             betas = (((FVF & D3DFVF_XYZB5)-D3DFVF_XYZB1)>>1)+1;
300             if (FVF & D3DFVF_LASTBETA_D3DCOLOR) {
301                 beta_index = D3DDECLTYPE_D3DCOLOR;
302             } else if (FVF & D3DFVF_LASTBETA_UBYTE4) {
303                 beta_index = D3DDECLTYPE_UBYTE4;
304             } else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5) {
305                 beta_index = D3DDECLTYPE_FLOAT1;
306             }
307             if (beta_index != 0xFF) { --betas; }
308 
309             if (betas > 0) {
310                 switch (betas) {
311                     case 1: elems[nelems].Type = D3DDECLTYPE_FLOAT1; break;
312                     case 2: elems[nelems].Type = D3DDECLTYPE_FLOAT2; break;
313                     case 3: elems[nelems].Type = D3DDECLTYPE_FLOAT3; break;
314                     case 4: elems[nelems].Type = D3DDECLTYPE_FLOAT4; break;
315                     default:
316                         assert(!"Implementation error!");
317                 }
318                 elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT;
319                 elems[nelems].UsageIndex = 0;
320                 ++nelems;
321             }
322 
323             if (beta_index != 0xFF) {
324                 elems[nelems].Type = beta_index;
325                 elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES;
326                 elems[nelems].UsageIndex = 0;
327                 ++nelems;
328             }
329             break;
330 
331         case D3DFVF_XYZW: /* simple XYZW */
332         case D3DFVF_XYZRHW: /* pretransformed XYZW */
333             elems[nelems].Type = D3DDECLTYPE_FLOAT4;
334             elems[nelems].Usage =
335                 ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW) ?
336                 D3DDECLUSAGE_POSITION : D3DDECLUSAGE_POSITIONT;
337             elems[nelems].UsageIndex = 0;
338             ++nelems;
339             break;
340 
341         default:
342             (void)user_error(!"Position doesn't match any known combination");
343     }
344 
345     /* normals, psize and colors */
346     if (FVF & D3DFVF_NORMAL) {
347         elems[nelems].Type = D3DDECLTYPE_FLOAT3;
348         elems[nelems].Usage = D3DDECLUSAGE_NORMAL;
349         elems[nelems].UsageIndex = 0;
350         ++nelems;
351     }
352     if (FVF & D3DFVF_PSIZE) {
353         elems[nelems].Type = D3DDECLTYPE_FLOAT1;
354         elems[nelems].Usage = D3DDECLUSAGE_PSIZE;
355         elems[nelems].UsageIndex = 0;
356         ++nelems;
357     }
358     if (FVF & D3DFVF_DIFFUSE) {
359         elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
360         elems[nelems].Usage = D3DDECLUSAGE_COLOR;
361         elems[nelems].UsageIndex = 0;
362         ++nelems;
363     }
364     if (FVF & D3DFVF_SPECULAR) {
365         elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
366         elems[nelems].Usage = D3DDECLUSAGE_COLOR;
367         elems[nelems].UsageIndex = 1;
368         ++nelems;
369     }
370 
371     /* textures */
372     texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
373     if (user_error(texcount <= 8)) { texcount = 8; }
374 
375     for (i = 0; i < texcount; ++i) {
376         switch ((FVF >> (16+i*2)) & 0x3) {
377             case D3DFVF_TEXTUREFORMAT1:
378                 elems[nelems].Type = D3DDECLTYPE_FLOAT1;
379                 break;
380 
381             case D3DFVF_TEXTUREFORMAT2:
382                 elems[nelems].Type = D3DDECLTYPE_FLOAT2;
383                 break;
384 
385             case D3DFVF_TEXTUREFORMAT3:
386                 elems[nelems].Type = D3DDECLTYPE_FLOAT3;
387                 break;
388 
389             case D3DFVF_TEXTUREFORMAT4:
390                 elems[nelems].Type = D3DDECLTYPE_FLOAT4;
391                 break;
392 
393             default:
394                 assert(!"Implementation error!");
395         }
396         elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD;
397         elems[nelems].UsageIndex = i;
398         ++nelems;
399     }
400 
401     /* fill out remaining data */
402     for (i = 0; i < nelems; ++i) {
403         elems[i].Stream = 0;
404         elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset +
405                                           decltype_size(elems[i-1].Type));
406         elems[i].Method = D3DDECLMETHOD_DEFAULT;
407     }
408     elems[nelems++] = decl_end;
409 
410     NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems);
411 }
412 
413 void
NineVertexDeclaration9_FillStreamOutputInfo(struct NineVertexDeclaration9 * This,struct nine_vs_output_info * ShaderOutputsInfo,unsigned numOutputs,struct pipe_stream_output_info * so)414 NineVertexDeclaration9_FillStreamOutputInfo(
415     struct NineVertexDeclaration9 *This,
416     struct nine_vs_output_info *ShaderOutputsInfo,
417     unsigned numOutputs,
418     struct pipe_stream_output_info *so )
419 {
420     unsigned so_outputs = 0;
421     int i, j;
422 
423     memset(so, 0, sizeof(struct pipe_stream_output_info));
424 
425     for (i = 0; i < numOutputs; i++) {
426         BYTE output_semantic = ShaderOutputsInfo[i].output_semantic;
427         unsigned output_semantic_index = ShaderOutputsInfo[i].output_semantic_index;
428 
429         for (j = 0; j < This->nelems; j++) {
430             if ((This->decls[j].Usage == output_semantic ||
431                  (output_semantic == D3DDECLUSAGE_POSITION &&
432                   This->decls[j].Usage == D3DDECLUSAGE_POSITIONT)) &&
433                 This->decls[j].UsageIndex == output_semantic_index) {
434                 DBG("Matching %s %d: o%d -> %d\n",
435                     nine_declusage_name(nine_d3d9_to_nine_declusage(This->decls[j].Usage, 0)),
436                     This->decls[j].UsageIndex, i, j);
437                 so->output[so_outputs].register_index = ShaderOutputsInfo[i].output_index;
438                 so->output[so_outputs].start_component = 0;
439                 if (ShaderOutputsInfo[i].mask & 8)
440                     so->output[so_outputs].num_components = 4;
441                 else if (ShaderOutputsInfo[i].mask & 4)
442                     so->output[so_outputs].num_components = 3;
443                 else if (ShaderOutputsInfo[i].mask & 2)
444                     so->output[so_outputs].num_components = 2;
445                 else
446                     so->output[so_outputs].num_components = 1;
447                 so->output[so_outputs].output_buffer = 0;
448                 so->output[so_outputs].dst_offset = so_outputs * sizeof(float[4])/4;
449                 so->output[so_outputs].stream = 0;
450                 so_outputs++;
451                 break;
452             }
453         }
454     }
455 
456     so->num_outputs = so_outputs;
457     so->stride[0] = so_outputs * sizeof(float[4])/4;
458 }
459 
460 /* ProcessVertices runs stream output into a temporary buffer to capture
461  * all outputs.
462  * Now we have to convert them to the format and order set by the vertex
463  * declaration, for which we use u_translate.
464  * This is necessary if the vertex declaration contains elements using a
465  * non float32 format, because stream output only supports f32/u32/s32.
466  */
467 HRESULT
NineVertexDeclaration9_ConvertStreamOutput(struct NineVertexDeclaration9 * This,struct NineVertexBuffer9 * pDstBuf,UINT DestIndex,UINT VertexCount,void * pSrcBuf,const struct pipe_stream_output_info * so)468 NineVertexDeclaration9_ConvertStreamOutput(
469     struct NineVertexDeclaration9 *This,
470     struct NineVertexBuffer9 *pDstBuf,
471     UINT DestIndex,
472     UINT VertexCount,
473     void *pSrcBuf,
474     const struct pipe_stream_output_info *so )
475 {
476     struct translate *translate;
477     struct translate_key transkey;
478     HRESULT hr;
479     unsigned i;
480     void *dst_map;
481 
482     DBG("This=%p pDstBuf=%p DestIndex=%u VertexCount=%u pSrcBuf=%p so=%p\n",
483         This, pDstBuf, DestIndex, VertexCount, pSrcBuf, so);
484 
485     transkey.output_stride = 0;
486     for (i = 0; i < This->nelems; ++i) {
487         enum pipe_format format;
488 
489         switch (so->output[i].num_components) {
490         case 1: format = PIPE_FORMAT_R32_FLOAT; break;
491         case 2: format = PIPE_FORMAT_R32G32_FLOAT; break;
492         case 3: format = PIPE_FORMAT_R32G32B32_FLOAT; break;
493         default:
494             assert(so->output[i].num_components == 4);
495             format = PIPE_FORMAT_R32G32B32A32_FLOAT;
496             break;
497         }
498         transkey.element[i].type = TRANSLATE_ELEMENT_NORMAL;
499         transkey.element[i].input_format = format;
500         transkey.element[i].input_buffer = 0;
501         transkey.element[i].input_offset = so->output[i].dst_offset * 4;
502         transkey.element[i].instance_divisor = 0;
503 
504         transkey.element[i].output_format = This->elems[i].src_format;
505         transkey.element[i].output_offset = This->elems[i].src_offset;
506         transkey.output_stride +=
507             util_format_get_blocksize(This->elems[i].src_format);
508 
509         assert(!(transkey.output_stride & 3));
510     }
511     transkey.nr_elements = This->nelems;
512 
513     translate = translate_create(&transkey);
514     if (!translate)
515         return E_OUTOFMEMORY;
516 
517     hr = NineVertexBuffer9_Lock(pDstBuf,
518                                 transkey.output_stride * DestIndex,
519                                 transkey.output_stride * VertexCount,
520                                 &dst_map, D3DLOCK_DISCARD);
521     if (FAILED(hr))
522         goto out;
523 
524     translate->set_buffer(translate, 0, pSrcBuf, so->stride[0] * 4, ~0);
525 
526     translate->run(translate, 0, VertexCount, 0, 0, dst_map);
527 
528     NineVertexBuffer9_Unlock(pDstBuf);
529 out:
530     translate->release(translate); /* TODO: cache these */
531     return hr;
532 }
533