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