17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
87ec681f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom
97ec681f3Smrg * the Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
197ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
207ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
217ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */
227ec681f3Smrg
237ec681f3Smrg#include "vertexdeclaration9.h"
247ec681f3Smrg#include "vertexbuffer9.h"
257ec681f3Smrg#include "device9.h"
267ec681f3Smrg#include "nine_helpers.h"
277ec681f3Smrg#include "nine_shader.h"
287ec681f3Smrg
297ec681f3Smrg#include "pipe/p_format.h"
307ec681f3Smrg#include "pipe/p_context.h"
317ec681f3Smrg#include "util/u_math.h"
327ec681f3Smrg#include "util/format/u_format.h"
337ec681f3Smrg#include "translate/translate.h"
347ec681f3Smrg
357ec681f3Smrg#define DBG_CHANNEL DBG_VERTEXDECLARATION
367ec681f3Smrg
377ec681f3Smrgstatic inline enum pipe_format decltype_format(BYTE type)
387ec681f3Smrg{
397ec681f3Smrg    switch (type) {
407ec681f3Smrg    case D3DDECLTYPE_FLOAT1:    return PIPE_FORMAT_R32_FLOAT;
417ec681f3Smrg    case D3DDECLTYPE_FLOAT2:    return PIPE_FORMAT_R32G32_FLOAT;
427ec681f3Smrg    case D3DDECLTYPE_FLOAT3:    return PIPE_FORMAT_R32G32B32_FLOAT;
437ec681f3Smrg    case D3DDECLTYPE_FLOAT4:    return PIPE_FORMAT_R32G32B32A32_FLOAT;
447ec681f3Smrg    case D3DDECLTYPE_D3DCOLOR:  return PIPE_FORMAT_B8G8R8A8_UNORM;
457ec681f3Smrg    case D3DDECLTYPE_UBYTE4:    return PIPE_FORMAT_R8G8B8A8_USCALED;
467ec681f3Smrg    case D3DDECLTYPE_SHORT2:    return PIPE_FORMAT_R16G16_SSCALED;
477ec681f3Smrg    case D3DDECLTYPE_SHORT4:    return PIPE_FORMAT_R16G16B16A16_SSCALED;
487ec681f3Smrg    case D3DDECLTYPE_UBYTE4N:   return PIPE_FORMAT_R8G8B8A8_UNORM;
497ec681f3Smrg    case D3DDECLTYPE_SHORT2N:   return PIPE_FORMAT_R16G16_SNORM;
507ec681f3Smrg    case D3DDECLTYPE_SHORT4N:   return PIPE_FORMAT_R16G16B16A16_SNORM;
517ec681f3Smrg    case D3DDECLTYPE_USHORT2N:  return PIPE_FORMAT_R16G16_UNORM;
527ec681f3Smrg    case D3DDECLTYPE_USHORT4N:  return PIPE_FORMAT_R16G16B16A16_UNORM;
537ec681f3Smrg    case D3DDECLTYPE_UDEC3:     return PIPE_FORMAT_R10G10B10X2_USCALED;
547ec681f3Smrg    case D3DDECLTYPE_DEC3N:     return PIPE_FORMAT_R10G10B10X2_SNORM;
557ec681f3Smrg    case D3DDECLTYPE_FLOAT16_2: return PIPE_FORMAT_R16G16_FLOAT;
567ec681f3Smrg    case D3DDECLTYPE_FLOAT16_4: return PIPE_FORMAT_R16G16B16A16_FLOAT;
577ec681f3Smrg    default:
587ec681f3Smrg        assert(!"Implementation error !");
597ec681f3Smrg    }
607ec681f3Smrg    return PIPE_FORMAT_NONE;
617ec681f3Smrg}
627ec681f3Smrg
637ec681f3Smrgstatic inline unsigned decltype_size(BYTE type)
647ec681f3Smrg{
657ec681f3Smrg    switch (type) {
667ec681f3Smrg    case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float);
677ec681f3Smrg    case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float);
687ec681f3Smrg    case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float);
697ec681f3Smrg    case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float);
707ec681f3Smrg    case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD);
717ec681f3Smrg    case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE);
727ec681f3Smrg    case D3DDECLTYPE_SHORT2: return 2 * sizeof(short);
737ec681f3Smrg    case D3DDECLTYPE_SHORT4: return 4 * sizeof(short);
747ec681f3Smrg    case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE);
757ec681f3Smrg    case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short);
767ec681f3Smrg    case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short);
777ec681f3Smrg    case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short);
787ec681f3Smrg    case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short);
797ec681f3Smrg    case D3DDECLTYPE_UDEC3: return 4;
807ec681f3Smrg    case D3DDECLTYPE_DEC3N: return 4;
817ec681f3Smrg    case D3DDECLTYPE_FLOAT16_2: return 2 * 2;
827ec681f3Smrg    case D3DDECLTYPE_FLOAT16_4: return 4 * 2;
837ec681f3Smrg    default:
847ec681f3Smrg        assert(!"Implementation error !");
857ec681f3Smrg    }
867ec681f3Smrg    return 0;
877ec681f3Smrg}
887ec681f3Smrg
897ec681f3Smrg/* Actually, arbitrary usage index values are permitted, but a
907ec681f3Smrg * simple lookup table won't work in that case. Let's just wait
917ec681f3Smrg * with making this more generic until we need it.
927ec681f3Smrg */
937ec681f3Smrgstatic inline boolean
947ec681f3Smrgnine_d3ddeclusage_check(unsigned usage, unsigned usage_idx)
957ec681f3Smrg{
967ec681f3Smrg    switch (usage) {
977ec681f3Smrg    case D3DDECLUSAGE_POSITIONT:
987ec681f3Smrg    case D3DDECLUSAGE_TESSFACTOR:
997ec681f3Smrg    case D3DDECLUSAGE_DEPTH:
1007ec681f3Smrg    case D3DDECLUSAGE_NORMAL:
1017ec681f3Smrg    case D3DDECLUSAGE_TANGENT:
1027ec681f3Smrg    case D3DDECLUSAGE_BINORMAL:
1037ec681f3Smrg    case D3DDECLUSAGE_POSITION:
1047ec681f3Smrg    case D3DDECLUSAGE_BLENDWEIGHT:
1057ec681f3Smrg    case D3DDECLUSAGE_BLENDINDICES:
1067ec681f3Smrg    case D3DDECLUSAGE_COLOR:
1077ec681f3Smrg        return TRUE;
1087ec681f3Smrg    case D3DDECLUSAGE_PSIZE:
1097ec681f3Smrg    case D3DDECLUSAGE_FOG:
1107ec681f3Smrg    case D3DDECLUSAGE_SAMPLE:
1117ec681f3Smrg        return usage_idx <= 0;
1127ec681f3Smrg    case D3DDECLUSAGE_TEXCOORD:
1137ec681f3Smrg        return usage_idx <= 15;
1147ec681f3Smrg    default:
1157ec681f3Smrg        return FALSE;
1167ec681f3Smrg    }
1177ec681f3Smrg}
1187ec681f3Smrg
1197ec681f3Smrg#define NINE_DECLUSAGE_CASE0(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n
1207ec681f3Smrg#define NINE_DECLUSAGE_CASEi(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_i(n, usage_idx)
1217ec681f3Smrguint16_t
1227ec681f3Smrgnine_d3d9_to_nine_declusage(unsigned usage, unsigned usage_idx)
1237ec681f3Smrg{
1247ec681f3Smrg    if (!nine_d3ddeclusage_check(usage, usage_idx))
1257ec681f3Smrg        ERR("D3DDECLUSAGE_%u[%u]\n",usage,usage_idx);
1267ec681f3Smrg    assert(nine_d3ddeclusage_check(usage, usage_idx));
1277ec681f3Smrg    switch (usage) {
1287ec681f3Smrg    NINE_DECLUSAGE_CASEi(POSITION);
1297ec681f3Smrg    NINE_DECLUSAGE_CASEi(BLENDWEIGHT);
1307ec681f3Smrg    NINE_DECLUSAGE_CASEi(BLENDINDICES);
1317ec681f3Smrg    NINE_DECLUSAGE_CASEi(NORMAL);
1327ec681f3Smrg    NINE_DECLUSAGE_CASE0(PSIZE);
1337ec681f3Smrg    NINE_DECLUSAGE_CASEi(TEXCOORD);
1347ec681f3Smrg    NINE_DECLUSAGE_CASEi(TANGENT);
1357ec681f3Smrg    NINE_DECLUSAGE_CASEi(BINORMAL);
1367ec681f3Smrg    NINE_DECLUSAGE_CASE0(TESSFACTOR);
1377ec681f3Smrg    NINE_DECLUSAGE_CASEi(POSITIONT);
1387ec681f3Smrg    NINE_DECLUSAGE_CASEi(COLOR);
1397ec681f3Smrg    NINE_DECLUSAGE_CASE0(DEPTH);
1407ec681f3Smrg    NINE_DECLUSAGE_CASE0(FOG);
1417ec681f3Smrg    NINE_DECLUSAGE_CASE0(SAMPLE);
1427ec681f3Smrg    default:
1437ec681f3Smrg        assert(!"Invalid DECLUSAGE.");
1447ec681f3Smrg        return NINE_DECLUSAGE_NONE;
1457ec681f3Smrg    }
1467ec681f3Smrg}
1477ec681f3Smrg
1487ec681f3Smrgstatic const char *nine_declusage_names[] =
1497ec681f3Smrg{
1507ec681f3Smrg    [NINE_DECLUSAGE_POSITION]        = "POSITION",
1517ec681f3Smrg    [NINE_DECLUSAGE_BLENDWEIGHT]     = "BLENDWEIGHT",
1527ec681f3Smrg    [NINE_DECLUSAGE_BLENDINDICES]    = "BLENDINDICES",
1537ec681f3Smrg    [NINE_DECLUSAGE_NORMAL]          = "NORMAL",
1547ec681f3Smrg    [NINE_DECLUSAGE_PSIZE]           = "PSIZE",
1557ec681f3Smrg    [NINE_DECLUSAGE_TEXCOORD]        = "TEXCOORD",
1567ec681f3Smrg    [NINE_DECLUSAGE_TANGENT]         = "TANGENT",
1577ec681f3Smrg    [NINE_DECLUSAGE_BINORMAL]        = "BINORMAL",
1587ec681f3Smrg    [NINE_DECLUSAGE_TESSFACTOR]      = "TESSFACTOR",
1597ec681f3Smrg    [NINE_DECLUSAGE_POSITIONT]       = "POSITIONT",
1607ec681f3Smrg    [NINE_DECLUSAGE_COLOR]           = "DIFFUSE",
1617ec681f3Smrg    [NINE_DECLUSAGE_DEPTH]           = "DEPTH",
1627ec681f3Smrg    [NINE_DECLUSAGE_FOG]             = "FOG",
1637ec681f3Smrg    [NINE_DECLUSAGE_NONE]            = "(NONE)",
1647ec681f3Smrg};
1657ec681f3Smrgstatic inline const char *
1667ec681f3Smrgnine_declusage_name(unsigned ndcl)
1677ec681f3Smrg{
1687ec681f3Smrg    return nine_declusage_names[ndcl % NINE_DECLUSAGE_COUNT];
1697ec681f3Smrg}
1707ec681f3Smrg
1717ec681f3SmrgHRESULT
1727ec681f3SmrgNineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This,
1737ec681f3Smrg                             struct NineUnknownParams *pParams,
1747ec681f3Smrg                             const D3DVERTEXELEMENT9 *pElements )
1757ec681f3Smrg{
1767ec681f3Smrg    const D3DCAPS9 *caps;
1777ec681f3Smrg    unsigned i, nelems;
1787ec681f3Smrg    DBG("This=%p pParams=%p pElements=%p\n", This, pParams, pElements);
1797ec681f3Smrg
1807ec681f3Smrg    /* wine */
1817ec681f3Smrg    for (nelems = 0;
1827ec681f3Smrg         pElements[nelems].Stream != 0xFF;
1837ec681f3Smrg         ++nelems) {
1847ec681f3Smrg        user_assert(pElements[nelems].Type != D3DDECLTYPE_UNUSED, E_FAIL);
1857ec681f3Smrg        user_assert(!(pElements[nelems].Offset & 3), E_FAIL);
1867ec681f3Smrg    }
1877ec681f3Smrg
1887ec681f3Smrg    caps = NineDevice9_GetCaps(pParams->device);
1897ec681f3Smrg    user_assert(nelems <= caps->MaxStreams, D3DERR_INVALIDCALL);
1907ec681f3Smrg
1917ec681f3Smrg    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
1927ec681f3Smrg    if (FAILED(hr)) { return hr; }
1937ec681f3Smrg
1947ec681f3Smrg    This->nelems = nelems;
1957ec681f3Smrg    This->decls = CALLOC(This->nelems+1, sizeof(D3DVERTEXELEMENT9));
1967ec681f3Smrg    This->elems = CALLOC(This->nelems, sizeof(struct pipe_vertex_element));
1977ec681f3Smrg    This->usage_map = CALLOC(This->nelems, sizeof(uint16_t));
1987ec681f3Smrg    if (!This->decls || !This->elems || !This->usage_map) { return E_OUTOFMEMORY; }
1997ec681f3Smrg    memcpy(This->decls, pElements, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
2007ec681f3Smrg
2017ec681f3Smrg    for (i = 0; i < This->nelems; ++i) {
2027ec681f3Smrg        uint16_t usage = nine_d3d9_to_nine_declusage(This->decls[i].Usage,
2037ec681f3Smrg                                                     This->decls[i].UsageIndex);
2047ec681f3Smrg        This->usage_map[i] = usage;
2057ec681f3Smrg
2067ec681f3Smrg        if (This->decls[i].Usage == D3DDECLUSAGE_POSITIONT)
2077ec681f3Smrg            This->position_t = TRUE;
2087ec681f3Smrg
2097ec681f3Smrg        This->elems[i].src_offset = This->decls[i].Offset;
2107ec681f3Smrg        This->elems[i].instance_divisor = 0;
2117ec681f3Smrg        This->elems[i].vertex_buffer_index = This->decls[i].Stream;
2127ec681f3Smrg        This->elems[i].src_format = decltype_format(This->decls[i].Type);
2137ec681f3Smrg        This->elems[i].dual_slot = false;
2147ec681f3Smrg        /* XXX Remember Method (tesselation), Usage, UsageIndex */
2157ec681f3Smrg
2167ec681f3Smrg        DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s%d\n", i,
2177ec681f3Smrg            This->decls[i].Stream,
2187ec681f3Smrg            This->decls[i].Offset,
2197ec681f3Smrg            util_format_name(This->elems[i].src_format),
2207ec681f3Smrg            nine_declusage_name(usage),
2217ec681f3Smrg            usage / NINE_DECLUSAGE_COUNT);
2227ec681f3Smrg    }
2237ec681f3Smrg
2247ec681f3Smrg    return D3D_OK;
2257ec681f3Smrg}
2267ec681f3Smrg
2277ec681f3Smrgvoid
2287ec681f3SmrgNineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This )
2297ec681f3Smrg{
2307ec681f3Smrg    DBG("This=%p\n", This);
2317ec681f3Smrg
2327ec681f3Smrg    FREE(This->decls);
2337ec681f3Smrg    FREE(This->elems);
2347ec681f3Smrg    FREE(This->usage_map);
2357ec681f3Smrg
2367ec681f3Smrg    NineUnknown_dtor(&This->base);
2377ec681f3Smrg}
2387ec681f3Smrg
2397ec681f3SmrgHRESULT NINE_WINAPI
2407ec681f3SmrgNineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
2417ec681f3Smrg                                       D3DVERTEXELEMENT9 *pElement,
2427ec681f3Smrg                                       UINT *pNumElements )
2437ec681f3Smrg{
2447ec681f3Smrg    if (!pElement) {
2457ec681f3Smrg        user_assert(pNumElements, D3DERR_INVALIDCALL);
2467ec681f3Smrg        *pNumElements = This->nelems+1;
2477ec681f3Smrg        return D3D_OK;
2487ec681f3Smrg    }
2497ec681f3Smrg    if (pNumElements) { *pNumElements = This->nelems+1; }
2507ec681f3Smrg    memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
2517ec681f3Smrg    return D3D_OK;
2527ec681f3Smrg}
2537ec681f3Smrg
2547ec681f3SmrgIDirect3DVertexDeclaration9Vtbl NineVertexDeclaration9_vtable = {
2557ec681f3Smrg    (void *)NineUnknown_QueryInterface,
2567ec681f3Smrg    (void *)NineUnknown_AddRef,
2577ec681f3Smrg    (void *)NineUnknown_Release,
2587ec681f3Smrg    (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */
2597ec681f3Smrg    (void *)NineVertexDeclaration9_GetDeclaration
2607ec681f3Smrg};
2617ec681f3Smrg
2627ec681f3Smrgstatic const GUID *NineVertexDeclaration9_IIDs[] = {
2637ec681f3Smrg    &IID_IDirect3DVertexDeclaration9,
2647ec681f3Smrg    &IID_IUnknown,
2657ec681f3Smrg    NULL
2667ec681f3Smrg};
2677ec681f3Smrg
2687ec681f3SmrgHRESULT
2697ec681f3SmrgNineVertexDeclaration9_new( struct NineDevice9 *pDevice,
2707ec681f3Smrg                            const D3DVERTEXELEMENT9 *pElements,
2717ec681f3Smrg                            struct NineVertexDeclaration9 **ppOut )
2727ec681f3Smrg{
2737ec681f3Smrg    NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements);
2747ec681f3Smrg}
2757ec681f3Smrg
2767ec681f3SmrgHRESULT
2777ec681f3SmrgNineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice,
2787ec681f3Smrg                                     DWORD FVF,
2797ec681f3Smrg                                     struct NineVertexDeclaration9 **ppOut )
2807ec681f3Smrg{
2817ec681f3Smrg    D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END();
2827ec681f3Smrg    unsigned texcount, i, betas, nelems = 0;
2837ec681f3Smrg    BYTE beta_index = 0xFF;
2847ec681f3Smrg
2857ec681f3Smrg    switch (FVF & D3DFVF_POSITION_MASK) {
2867ec681f3Smrg        case D3DFVF_XYZ: /* simple XYZ */
2877ec681f3Smrg        case D3DFVF_XYZB1:
2887ec681f3Smrg        case D3DFVF_XYZB2:
2897ec681f3Smrg        case D3DFVF_XYZB3:
2907ec681f3Smrg        case D3DFVF_XYZB4:
2917ec681f3Smrg        case D3DFVF_XYZB5: /* XYZ with beta values */
2927ec681f3Smrg            elems[nelems].Type = D3DDECLTYPE_FLOAT3;
2937ec681f3Smrg            elems[nelems].Usage = D3DDECLUSAGE_POSITION;
2947ec681f3Smrg            elems[nelems].UsageIndex = 0;
2957ec681f3Smrg            ++nelems;
2967ec681f3Smrg            /* simple XYZ has no beta values. break. */
2977ec681f3Smrg            if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; }
2987ec681f3Smrg
2997ec681f3Smrg            betas = (((FVF & D3DFVF_XYZB5)-D3DFVF_XYZB1)>>1)+1;
3007ec681f3Smrg            if (FVF & D3DFVF_LASTBETA_D3DCOLOR) {
3017ec681f3Smrg                beta_index = D3DDECLTYPE_D3DCOLOR;
3027ec681f3Smrg            } else if (FVF & D3DFVF_LASTBETA_UBYTE4) {
3037ec681f3Smrg                beta_index = D3DDECLTYPE_UBYTE4;
3047ec681f3Smrg            } else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5) {
3057ec681f3Smrg                beta_index = D3DDECLTYPE_FLOAT1;
3067ec681f3Smrg            }
3077ec681f3Smrg            if (beta_index != 0xFF) { --betas; }
3087ec681f3Smrg
3097ec681f3Smrg            if (betas > 0) {
3107ec681f3Smrg                switch (betas) {
3117ec681f3Smrg                    case 1: elems[nelems].Type = D3DDECLTYPE_FLOAT1; break;
3127ec681f3Smrg                    case 2: elems[nelems].Type = D3DDECLTYPE_FLOAT2; break;
3137ec681f3Smrg                    case 3: elems[nelems].Type = D3DDECLTYPE_FLOAT3; break;
3147ec681f3Smrg                    case 4: elems[nelems].Type = D3DDECLTYPE_FLOAT4; break;
3157ec681f3Smrg                    default:
3167ec681f3Smrg                        assert(!"Implementation error!");
3177ec681f3Smrg                }
3187ec681f3Smrg                elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT;
3197ec681f3Smrg                elems[nelems].UsageIndex = 0;
3207ec681f3Smrg                ++nelems;
3217ec681f3Smrg            }
3227ec681f3Smrg
3237ec681f3Smrg            if (beta_index != 0xFF) {
3247ec681f3Smrg                elems[nelems].Type = beta_index;
3257ec681f3Smrg                elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES;
3267ec681f3Smrg                elems[nelems].UsageIndex = 0;
3277ec681f3Smrg                ++nelems;
3287ec681f3Smrg            }
3297ec681f3Smrg            break;
3307ec681f3Smrg
3317ec681f3Smrg        case D3DFVF_XYZW: /* simple XYZW */
3327ec681f3Smrg        case D3DFVF_XYZRHW: /* pretransformed XYZW */
3337ec681f3Smrg            elems[nelems].Type = D3DDECLTYPE_FLOAT4;
3347ec681f3Smrg            elems[nelems].Usage =
3357ec681f3Smrg                ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW) ?
3367ec681f3Smrg                D3DDECLUSAGE_POSITION : D3DDECLUSAGE_POSITIONT;
3377ec681f3Smrg            elems[nelems].UsageIndex = 0;
3387ec681f3Smrg            ++nelems;
3397ec681f3Smrg            break;
3407ec681f3Smrg
3417ec681f3Smrg        default:
3427ec681f3Smrg            (void)user_error(!"Position doesn't match any known combination");
3437ec681f3Smrg    }
3447ec681f3Smrg
3457ec681f3Smrg    /* normals, psize and colors */
3467ec681f3Smrg    if (FVF & D3DFVF_NORMAL) {
3477ec681f3Smrg        elems[nelems].Type = D3DDECLTYPE_FLOAT3;
3487ec681f3Smrg        elems[nelems].Usage = D3DDECLUSAGE_NORMAL;
3497ec681f3Smrg        elems[nelems].UsageIndex = 0;
3507ec681f3Smrg        ++nelems;
3517ec681f3Smrg    }
3527ec681f3Smrg    if (FVF & D3DFVF_PSIZE) {
3537ec681f3Smrg        elems[nelems].Type = D3DDECLTYPE_FLOAT1;
3547ec681f3Smrg        elems[nelems].Usage = D3DDECLUSAGE_PSIZE;
3557ec681f3Smrg        elems[nelems].UsageIndex = 0;
3567ec681f3Smrg        ++nelems;
3577ec681f3Smrg    }
3587ec681f3Smrg    if (FVF & D3DFVF_DIFFUSE) {
3597ec681f3Smrg        elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
3607ec681f3Smrg        elems[nelems].Usage = D3DDECLUSAGE_COLOR;
3617ec681f3Smrg        elems[nelems].UsageIndex = 0;
3627ec681f3Smrg        ++nelems;
3637ec681f3Smrg    }
3647ec681f3Smrg    if (FVF & D3DFVF_SPECULAR) {
3657ec681f3Smrg        elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
3667ec681f3Smrg        elems[nelems].Usage = D3DDECLUSAGE_COLOR;
3677ec681f3Smrg        elems[nelems].UsageIndex = 1;
3687ec681f3Smrg        ++nelems;
3697ec681f3Smrg    }
3707ec681f3Smrg
3717ec681f3Smrg    /* textures */
3727ec681f3Smrg    texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
3737ec681f3Smrg    if (user_error(texcount <= 8)) { texcount = 8; }
3747ec681f3Smrg
3757ec681f3Smrg    for (i = 0; i < texcount; ++i) {
3767ec681f3Smrg        switch ((FVF >> (16+i*2)) & 0x3) {
3777ec681f3Smrg            case D3DFVF_TEXTUREFORMAT1:
3787ec681f3Smrg                elems[nelems].Type = D3DDECLTYPE_FLOAT1;
3797ec681f3Smrg                break;
3807ec681f3Smrg
3817ec681f3Smrg            case D3DFVF_TEXTUREFORMAT2:
3827ec681f3Smrg                elems[nelems].Type = D3DDECLTYPE_FLOAT2;
3837ec681f3Smrg                break;
3847ec681f3Smrg
3857ec681f3Smrg            case D3DFVF_TEXTUREFORMAT3:
3867ec681f3Smrg                elems[nelems].Type = D3DDECLTYPE_FLOAT3;
3877ec681f3Smrg                break;
3887ec681f3Smrg
3897ec681f3Smrg            case D3DFVF_TEXTUREFORMAT4:
3907ec681f3Smrg                elems[nelems].Type = D3DDECLTYPE_FLOAT4;
3917ec681f3Smrg                break;
3927ec681f3Smrg
3937ec681f3Smrg            default:
3947ec681f3Smrg                assert(!"Implementation error!");
3957ec681f3Smrg        }
3967ec681f3Smrg        elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD;
3977ec681f3Smrg        elems[nelems].UsageIndex = i;
3987ec681f3Smrg        ++nelems;
3997ec681f3Smrg    }
4007ec681f3Smrg
4017ec681f3Smrg    /* fill out remaining data */
4027ec681f3Smrg    for (i = 0; i < nelems; ++i) {
4037ec681f3Smrg        elems[i].Stream = 0;
4047ec681f3Smrg        elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset +
4057ec681f3Smrg                                          decltype_size(elems[i-1].Type));
4067ec681f3Smrg        elems[i].Method = D3DDECLMETHOD_DEFAULT;
4077ec681f3Smrg    }
4087ec681f3Smrg    elems[nelems++] = decl_end;
4097ec681f3Smrg
4107ec681f3Smrg    NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems);
4117ec681f3Smrg}
4127ec681f3Smrg
4137ec681f3Smrgvoid
4147ec681f3SmrgNineVertexDeclaration9_FillStreamOutputInfo(
4157ec681f3Smrg    struct NineVertexDeclaration9 *This,
4167ec681f3Smrg    struct nine_vs_output_info *ShaderOutputsInfo,
4177ec681f3Smrg    unsigned numOutputs,
4187ec681f3Smrg    struct pipe_stream_output_info *so )
4197ec681f3Smrg{
4207ec681f3Smrg    unsigned so_outputs = 0;
4217ec681f3Smrg    int i, j;
4227ec681f3Smrg
4237ec681f3Smrg    memset(so, 0, sizeof(struct pipe_stream_output_info));
4247ec681f3Smrg
4257ec681f3Smrg    for (i = 0; i < numOutputs; i++) {
4267ec681f3Smrg        BYTE output_semantic = ShaderOutputsInfo[i].output_semantic;
4277ec681f3Smrg        unsigned output_semantic_index = ShaderOutputsInfo[i].output_semantic_index;
4287ec681f3Smrg
4297ec681f3Smrg        for (j = 0; j < This->nelems; j++) {
4307ec681f3Smrg            if ((This->decls[j].Usage == output_semantic ||
4317ec681f3Smrg                 (output_semantic == D3DDECLUSAGE_POSITION &&
4327ec681f3Smrg                  This->decls[j].Usage == D3DDECLUSAGE_POSITIONT)) &&
4337ec681f3Smrg                This->decls[j].UsageIndex == output_semantic_index) {
4347ec681f3Smrg                DBG("Matching %s %d: o%d -> %d\n",
4357ec681f3Smrg                    nine_declusage_name(nine_d3d9_to_nine_declusage(This->decls[j].Usage, 0)),
4367ec681f3Smrg                    This->decls[j].UsageIndex, i, j);
4377ec681f3Smrg                so->output[so_outputs].register_index = ShaderOutputsInfo[i].output_index;
4387ec681f3Smrg                so->output[so_outputs].start_component = 0;
4397ec681f3Smrg                if (ShaderOutputsInfo[i].mask & 8)
4407ec681f3Smrg                    so->output[so_outputs].num_components = 4;
4417ec681f3Smrg                else if (ShaderOutputsInfo[i].mask & 4)
4427ec681f3Smrg                    so->output[so_outputs].num_components = 3;
4437ec681f3Smrg                else if (ShaderOutputsInfo[i].mask & 2)
4447ec681f3Smrg                    so->output[so_outputs].num_components = 2;
4457ec681f3Smrg                else
4467ec681f3Smrg                    so->output[so_outputs].num_components = 1;
4477ec681f3Smrg                so->output[so_outputs].output_buffer = 0;
4487ec681f3Smrg                so->output[so_outputs].dst_offset = so_outputs * sizeof(float[4])/4;
4497ec681f3Smrg                so->output[so_outputs].stream = 0;
4507ec681f3Smrg                so_outputs++;
4517ec681f3Smrg                break;
4527ec681f3Smrg            }
4537ec681f3Smrg        }
4547ec681f3Smrg    }
4557ec681f3Smrg
4567ec681f3Smrg    so->num_outputs = so_outputs;
4577ec681f3Smrg    so->stride[0] = so_outputs * sizeof(float[4])/4;
4587ec681f3Smrg}
4597ec681f3Smrg
4607ec681f3Smrg/* ProcessVertices runs stream output into a temporary buffer to capture
4617ec681f3Smrg * all outputs.
4627ec681f3Smrg * Now we have to convert them to the format and order set by the vertex
4637ec681f3Smrg * declaration, for which we use u_translate.
4647ec681f3Smrg * This is necessary if the vertex declaration contains elements using a
4657ec681f3Smrg * non float32 format, because stream output only supports f32/u32/s32.
4667ec681f3Smrg */
4677ec681f3SmrgHRESULT
4687ec681f3SmrgNineVertexDeclaration9_ConvertStreamOutput(
4697ec681f3Smrg    struct NineVertexDeclaration9 *This,
4707ec681f3Smrg    struct NineVertexBuffer9 *pDstBuf,
4717ec681f3Smrg    UINT DestIndex,
4727ec681f3Smrg    UINT VertexCount,
4737ec681f3Smrg    void *pSrcBuf,
4747ec681f3Smrg    const struct pipe_stream_output_info *so )
4757ec681f3Smrg{
4767ec681f3Smrg    struct translate *translate;
4777ec681f3Smrg    struct translate_key transkey;
4787ec681f3Smrg    HRESULT hr;
4797ec681f3Smrg    unsigned i;
4807ec681f3Smrg    void *dst_map;
4817ec681f3Smrg
4827ec681f3Smrg    DBG("This=%p pDstBuf=%p DestIndex=%u VertexCount=%u pSrcBuf=%p so=%p\n",
4837ec681f3Smrg        This, pDstBuf, DestIndex, VertexCount, pSrcBuf, so);
4847ec681f3Smrg
4857ec681f3Smrg    transkey.output_stride = 0;
4867ec681f3Smrg    for (i = 0; i < This->nelems; ++i) {
4877ec681f3Smrg        enum pipe_format format;
4887ec681f3Smrg
4897ec681f3Smrg        switch (so->output[i].num_components) {
4907ec681f3Smrg        case 1: format = PIPE_FORMAT_R32_FLOAT; break;
4917ec681f3Smrg        case 2: format = PIPE_FORMAT_R32G32_FLOAT; break;
4927ec681f3Smrg        case 3: format = PIPE_FORMAT_R32G32B32_FLOAT; break;
4937ec681f3Smrg        default:
4947ec681f3Smrg            assert(so->output[i].num_components == 4);
4957ec681f3Smrg            format = PIPE_FORMAT_R32G32B32A32_FLOAT;
4967ec681f3Smrg            break;
4977ec681f3Smrg        }
4987ec681f3Smrg        transkey.element[i].type = TRANSLATE_ELEMENT_NORMAL;
4997ec681f3Smrg        transkey.element[i].input_format = format;
5007ec681f3Smrg        transkey.element[i].input_buffer = 0;
5017ec681f3Smrg        transkey.element[i].input_offset = so->output[i].dst_offset * 4;
5027ec681f3Smrg        transkey.element[i].instance_divisor = 0;
5037ec681f3Smrg
5047ec681f3Smrg        transkey.element[i].output_format = This->elems[i].src_format;
5057ec681f3Smrg        transkey.element[i].output_offset = This->elems[i].src_offset;
5067ec681f3Smrg        transkey.output_stride +=
5077ec681f3Smrg            util_format_get_blocksize(This->elems[i].src_format);
5087ec681f3Smrg
5097ec681f3Smrg        assert(!(transkey.output_stride & 3));
5107ec681f3Smrg    }
5117ec681f3Smrg    transkey.nr_elements = This->nelems;
5127ec681f3Smrg
5137ec681f3Smrg    translate = translate_create(&transkey);
5147ec681f3Smrg    if (!translate)
5157ec681f3Smrg        return E_OUTOFMEMORY;
5167ec681f3Smrg
5177ec681f3Smrg    hr = NineVertexBuffer9_Lock(pDstBuf,
5187ec681f3Smrg                                transkey.output_stride * DestIndex,
5197ec681f3Smrg                                transkey.output_stride * VertexCount,
5207ec681f3Smrg                                &dst_map, D3DLOCK_DISCARD);
5217ec681f3Smrg    if (FAILED(hr))
5227ec681f3Smrg        goto out;
5237ec681f3Smrg
5247ec681f3Smrg    translate->set_buffer(translate, 0, pSrcBuf, so->stride[0] * 4, ~0);
5257ec681f3Smrg
5267ec681f3Smrg    translate->run(translate, 0, VertexCount, 0, 0, dst_map);
5277ec681f3Smrg
5287ec681f3Smrg    NineVertexBuffer9_Unlock(pDstBuf);
5297ec681f3Smrgout:
5307ec681f3Smrg    translate->release(translate); /* TODO: cache these */
5317ec681f3Smrg    return hr;
5327ec681f3Smrg}
533