2
* Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
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:
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
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. */
23
#include "vertexdeclaration9.h"
24
#include "vertexbuffer9.h"
26
#include "nine_helpers.h"
27
#include "nine_shader.h"
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"
35
#define DBG_CHANNEL DBG_VERTEXDECLARATION
37
static inline enum pipe_format decltype_format(BYTE 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;
58
assert(!"Implementation error !");
60
return PIPE_FORMAT_NONE;
63
static inline unsigned decltype_size(BYTE 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;
84
assert(!"Implementation error !");
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.
94
nine_d3ddeclusage_check(unsigned usage, unsigned usage_idx)
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:
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;
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)
122
nine_d3d9_to_nine_declusage(unsigned usage, unsigned usage_idx)
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));
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);
143
assert(!"Invalid DECLUSAGE.");
144
return NINE_DECLUSAGE_NONE;
148
static const char *nine_declusage_names[] =
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)",
165
static inline const char *
166
nine_declusage_name(unsigned ndcl)
168
return nine_declusage_names[ndcl % NINE_DECLUSAGE_COUNT];
172
NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This,
173
struct NineUnknownParams *pParams,
174
const D3DVERTEXELEMENT9 *pElements )
176
const D3DCAPS9 *caps;
178
DBG("This=%p pParams=%p pElements=%p\n", This, pParams, pElements);
182
pElements[nelems].Stream != 0xFF;
184
user_assert(pElements[nelems].Type != D3DDECLTYPE_UNUSED, E_FAIL);
185
user_assert(!(pElements[nelems].Offset & 3), E_FAIL);
188
caps = NineDevice9_GetCaps(pParams->device);
189
user_assert(nelems <= caps->MaxStreams, D3DERR_INVALIDCALL);
191
HRESULT hr = NineUnknown_ctor(&This->base, pParams);
192
if (FAILED(hr)) { return hr; }
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));
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;
206
if (This->decls[i].Usage == D3DDECLUSAGE_POSITIONT)
207
This->position_t = TRUE;
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 */
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);
228
NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This )
230
DBG("This=%p\n", This);
234
FREE(This->usage_map);
236
NineUnknown_dtor(&This->base);
240
NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
241
D3DVERTEXELEMENT9 *pElement,
245
user_assert(pNumElements, D3DERR_INVALIDCALL);
246
*pNumElements = This->nelems+1;
249
if (pNumElements) { *pNumElements = This->nelems+1; }
250
memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
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
262
static const GUID *NineVertexDeclaration9_IIDs[] = {
263
&IID_IDirect3DVertexDeclaration9,
269
NineVertexDeclaration9_new( struct NineDevice9 *pDevice,
270
const D3DVERTEXELEMENT9 *pElements,
271
struct NineVertexDeclaration9 **ppOut )
273
NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements);
277
NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice,
279
struct NineVertexDeclaration9 **ppOut )
281
D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END();
282
unsigned texcount, i, betas, nelems = 0;
283
BYTE beta_index = 0xFF;
285
switch (FVF & D3DFVF_POSITION_MASK) {
286
case D3DFVF_XYZ: /* simple XYZ */
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;
296
/* simple XYZ has no beta values. break. */
297
if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; }
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;
307
if (beta_index != 0xFF) { --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;
316
assert(!"Implementation error!");
318
elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT;
319
elems[nelems].UsageIndex = 0;
323
if (beta_index != 0xFF) {
324
elems[nelems].Type = beta_index;
325
elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES;
326
elems[nelems].UsageIndex = 0;
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;
342
(void)user_error(!"Position doesn't match any known combination");
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;
352
if (FVF & D3DFVF_PSIZE) {
353
elems[nelems].Type = D3DDECLTYPE_FLOAT1;
354
elems[nelems].Usage = D3DDECLUSAGE_PSIZE;
355
elems[nelems].UsageIndex = 0;
358
if (FVF & D3DFVF_DIFFUSE) {
359
elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
360
elems[nelems].Usage = D3DDECLUSAGE_COLOR;
361
elems[nelems].UsageIndex = 0;
364
if (FVF & D3DFVF_SPECULAR) {
365
elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
366
elems[nelems].Usage = D3DDECLUSAGE_COLOR;
367
elems[nelems].UsageIndex = 1;
372
texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
373
if (user_error(texcount <= 8)) { texcount = 8; }
375
for (i = 0; i < texcount; ++i) {
376
switch ((FVF >> (16+i*2)) & 0x3) {
377
case D3DFVF_TEXTUREFORMAT1:
378
elems[nelems].Type = D3DDECLTYPE_FLOAT1;
381
case D3DFVF_TEXTUREFORMAT2:
382
elems[nelems].Type = D3DDECLTYPE_FLOAT2;
385
case D3DFVF_TEXTUREFORMAT3:
386
elems[nelems].Type = D3DDECLTYPE_FLOAT3;
389
case D3DFVF_TEXTUREFORMAT4:
390
elems[nelems].Type = D3DDECLTYPE_FLOAT4;
394
assert(!"Implementation error!");
396
elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD;
397
elems[nelems].UsageIndex = i;
401
/* fill out remaining data */
402
for (i = 0; i < nelems; ++i) {
404
elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset +
405
decltype_size(elems[i-1].Type));
406
elems[i].Method = D3DDECLMETHOD_DEFAULT;
408
elems[nelems++] = decl_end;
410
NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems);
414
NineVertexDeclaration9_FillStreamOutputInfo(
415
struct NineVertexDeclaration9 *This,
416
struct nine_vs_output_info *ShaderOutputsInfo,
418
struct pipe_stream_output_info *so )
420
unsigned so_outputs = 0;
423
memset(so, 0, sizeof(struct pipe_stream_output_info));
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;
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;
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;
456
so->num_outputs = so_outputs;
457
so->stride[0] = so_outputs * sizeof(float[4])/4;
460
/* ProcessVertices runs stream output into a temporary buffer to capture
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.
468
NineVertexDeclaration9_ConvertStreamOutput(
469
struct NineVertexDeclaration9 *This,
470
struct NineVertexBuffer9 *pDstBuf,
474
const struct pipe_stream_output_info *so )
476
struct translate *translate;
477
struct translate_key transkey;
482
DBG("This=%p pDstBuf=%p DestIndex=%u VertexCount=%u pSrcBuf=%p so=%p\n",
483
This, pDstBuf, DestIndex, VertexCount, pSrcBuf, so);
485
transkey.output_stride = 0;
486
for (i = 0; i < This->nelems; ++i) {
487
enum pipe_format format;
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;
494
assert(so->output[i].num_components == 4);
495
format = PIPE_FORMAT_R32G32B32A32_FLOAT;
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;
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);
509
assert(!(transkey.output_stride & 3));
511
transkey.nr_elements = This->nelems;
513
translate = translate_create(&transkey);
515
return E_OUTOFMEMORY;
517
hr = NineVertexBuffer9_Lock(pDstBuf,
518
transkey.output_stride * DestIndex,
519
transkey.output_stride * VertexCount,
520
&dst_map, D3DLOCK_DISCARD);
524
translate->set_buffer(translate, 0, pSrcBuf, so->stride[0] * 4, ~0);
526
translate->run(translate, 0, VertexCount, 0, 0, dst_map);
528
NineVertexBuffer9_Unlock(pDstBuf);
530
translate->release(translate); /* TODO: cache these */