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