1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Common/Assert.h"
6 #include "Common/CommonTypes.h"
7
8 #include "VideoCommon/DataReader.h"
9 #include "VideoCommon/VertexLoader.h"
10 #include "VideoCommon/VertexLoaderManager.h"
11 #include "VideoCommon/VertexLoaderUtils.h"
12 #include "VideoCommon/VertexLoader_Color.h"
13 #include "VideoCommon/VertexLoader_Normal.h"
14 #include "VideoCommon/VertexLoader_Position.h"
15 #include "VideoCommon/VertexLoader_TextCoord.h"
16 #include "VideoCommon/VideoCommon.h"
17
18 // This pointer is used as the source/dst for all fixed function loader calls
19 u8* g_video_buffer_read_ptr;
20 u8* g_vertex_manager_write_ptr;
21
PosMtx_ReadDirect_UByte(VertexLoader * loader)22 static void PosMtx_ReadDirect_UByte(VertexLoader* loader)
23 {
24 u32 posmtx = DataRead<u8>() & 0x3f;
25 if (loader->m_counter < 3)
26 VertexLoaderManager::position_matrix_index[loader->m_counter + 1] = posmtx;
27 DataWrite<u32>(posmtx);
28 PRIM_LOG("posmtx: %d, ", posmtx);
29 }
30
TexMtx_ReadDirect_UByte(VertexLoader * loader)31 static void TexMtx_ReadDirect_UByte(VertexLoader* loader)
32 {
33 loader->m_curtexmtx[loader->m_texmtxread] = DataRead<u8>() & 0x3f;
34
35 PRIM_LOG("texmtx%d: %d, ", loader->m_texmtxread, loader->m_curtexmtx[loader->m_texmtxread]);
36 loader->m_texmtxread++;
37 }
38
TexMtx_Write_Float(VertexLoader * loader)39 static void TexMtx_Write_Float(VertexLoader* loader)
40 {
41 DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++]));
42 }
43
TexMtx_Write_Float2(VertexLoader * loader)44 static void TexMtx_Write_Float2(VertexLoader* loader)
45 {
46 DataWrite(0.f);
47 DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++]));
48 }
49
TexMtx_Write_Float3(VertexLoader * loader)50 static void TexMtx_Write_Float3(VertexLoader* loader)
51 {
52 DataWrite(0.f);
53 DataWrite(0.f);
54 DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++]));
55 }
56
SkipVertex(VertexLoader * loader)57 static void SkipVertex(VertexLoader* loader)
58 {
59 if (loader->m_vertexSkip)
60 {
61 // reset the output buffer
62 g_vertex_manager_write_ptr -= loader->m_native_vtx_decl.stride;
63
64 loader->m_skippedVertices++;
65 }
66 }
67
VertexLoader(const TVtxDesc & vtx_desc,const VAT & vtx_attr)68 VertexLoader::VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr)
69 : VertexLoaderBase(vtx_desc, vtx_attr)
70 {
71 CompileVertexTranslator();
72
73 // generate frac factors
74 m_posScale = 1.0f / (1U << m_VtxAttr.PosFrac);
75 for (int i = 0; i < 8; i++)
76 m_tcScale[i] = 1.0f / (1U << m_VtxAttr.texCoord[i].Frac);
77 }
78
CompileVertexTranslator()79 void VertexLoader::CompileVertexTranslator()
80 {
81 m_VertexSize = 0;
82 const TVtxAttr& vtx_attr = m_VtxAttr;
83
84 // Reset pipeline
85 m_numPipelineStages = 0;
86
87 // Colors
88 const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
89 // TextureCoord
90 const u64 tc[8] = {m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord,
91 m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord,
92 m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord};
93
94 u32 components = 0;
95
96 // Position in pc vertex format.
97 int nat_offset = 0;
98
99 // Position Matrix Index
100 if (m_VtxDesc.PosMatIdx)
101 {
102 WriteCall(PosMtx_ReadDirect_UByte);
103 components |= VB_HAS_POSMTXIDX;
104 m_native_vtx_decl.posmtx.components = 4;
105 m_native_vtx_decl.posmtx.enable = true;
106 m_native_vtx_decl.posmtx.offset = nat_offset;
107 m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE;
108 m_native_vtx_decl.posmtx.integer = true;
109 nat_offset += 4;
110 m_VertexSize += 1;
111 }
112
113 if (m_VtxDesc.Tex0MatIdx)
114 {
115 m_VertexSize += 1;
116 components |= VB_HAS_TEXMTXIDX0;
117 WriteCall(TexMtx_ReadDirect_UByte);
118 }
119 if (m_VtxDesc.Tex1MatIdx)
120 {
121 m_VertexSize += 1;
122 components |= VB_HAS_TEXMTXIDX1;
123 WriteCall(TexMtx_ReadDirect_UByte);
124 }
125 if (m_VtxDesc.Tex2MatIdx)
126 {
127 m_VertexSize += 1;
128 components |= VB_HAS_TEXMTXIDX2;
129 WriteCall(TexMtx_ReadDirect_UByte);
130 }
131 if (m_VtxDesc.Tex3MatIdx)
132 {
133 m_VertexSize += 1;
134 components |= VB_HAS_TEXMTXIDX3;
135 WriteCall(TexMtx_ReadDirect_UByte);
136 }
137 if (m_VtxDesc.Tex4MatIdx)
138 {
139 m_VertexSize += 1;
140 components |= VB_HAS_TEXMTXIDX4;
141 WriteCall(TexMtx_ReadDirect_UByte);
142 }
143 if (m_VtxDesc.Tex5MatIdx)
144 {
145 m_VertexSize += 1;
146 components |= VB_HAS_TEXMTXIDX5;
147 WriteCall(TexMtx_ReadDirect_UByte);
148 }
149 if (m_VtxDesc.Tex6MatIdx)
150 {
151 m_VertexSize += 1;
152 components |= VB_HAS_TEXMTXIDX6;
153 WriteCall(TexMtx_ReadDirect_UByte);
154 }
155 if (m_VtxDesc.Tex7MatIdx)
156 {
157 m_VertexSize += 1;
158 components |= VB_HAS_TEXMTXIDX7;
159 WriteCall(TexMtx_ReadDirect_UByte);
160 }
161
162 // Write vertex position loader
163 WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat,
164 m_VtxAttr.PosElements));
165
166 m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat,
167 m_VtxAttr.PosElements);
168 int pos_elements = m_VtxAttr.PosElements + 2;
169 m_native_vtx_decl.position.components = pos_elements;
170 m_native_vtx_decl.position.enable = true;
171 m_native_vtx_decl.position.offset = nat_offset;
172 m_native_vtx_decl.position.type = VAR_FLOAT;
173 m_native_vtx_decl.position.integer = false;
174 nat_offset += pos_elements * sizeof(float);
175
176 // Normals
177 if (m_VtxDesc.Normal != NOT_PRESENT)
178 {
179 m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.Normal, m_VtxAttr.NormalFormat,
180 m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
181
182 TPipelineFunction pFunc = VertexLoader_Normal::GetFunction(
183 m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3);
184
185 if (pFunc == nullptr)
186 {
187 PanicAlert("VertexLoader_Normal::GetFunction(%i %i %i %i) returned zero!",
188 (u32)m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements,
189 m_VtxAttr.NormalIndex3);
190 }
191 WriteCall(pFunc);
192
193 for (int i = 0; i < (vtx_attr.NormalElements ? 3 : 1); i++)
194 {
195 m_native_vtx_decl.normals[i].components = 3;
196 m_native_vtx_decl.normals[i].enable = true;
197 m_native_vtx_decl.normals[i].offset = nat_offset;
198 m_native_vtx_decl.normals[i].type = VAR_FLOAT;
199 m_native_vtx_decl.normals[i].integer = false;
200 nat_offset += 12;
201 }
202
203 components |= VB_HAS_NRM0;
204 if (m_VtxAttr.NormalElements == 1)
205 components |= VB_HAS_NRM1 | VB_HAS_NRM2;
206 }
207
208 for (int i = 0; i < 2; i++)
209 {
210 m_native_vtx_decl.colors[i].components = 4;
211 m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE;
212 m_native_vtx_decl.colors[i].integer = false;
213 switch (col[i])
214 {
215 case NOT_PRESENT:
216 break;
217 case DIRECT:
218 switch (m_VtxAttr.color[i].Comp)
219 {
220 case FORMAT_16B_565:
221 m_VertexSize += 2;
222 WriteCall(Color_ReadDirect_16b_565);
223 break;
224 case FORMAT_24B_888:
225 m_VertexSize += 3;
226 WriteCall(Color_ReadDirect_24b_888);
227 break;
228 case FORMAT_32B_888x:
229 m_VertexSize += 4;
230 WriteCall(Color_ReadDirect_32b_888x);
231 break;
232 case FORMAT_16B_4444:
233 m_VertexSize += 2;
234 WriteCall(Color_ReadDirect_16b_4444);
235 break;
236 case FORMAT_24B_6666:
237 m_VertexSize += 3;
238 WriteCall(Color_ReadDirect_24b_6666);
239 break;
240 case FORMAT_32B_8888:
241 m_VertexSize += 4;
242 WriteCall(Color_ReadDirect_32b_8888);
243 break;
244 default:
245 ASSERT(0);
246 break;
247 }
248 break;
249 case INDEX8:
250 m_VertexSize += 1;
251 switch (m_VtxAttr.color[i].Comp)
252 {
253 case FORMAT_16B_565:
254 WriteCall(Color_ReadIndex8_16b_565);
255 break;
256 case FORMAT_24B_888:
257 WriteCall(Color_ReadIndex8_24b_888);
258 break;
259 case FORMAT_32B_888x:
260 WriteCall(Color_ReadIndex8_32b_888x);
261 break;
262 case FORMAT_16B_4444:
263 WriteCall(Color_ReadIndex8_16b_4444);
264 break;
265 case FORMAT_24B_6666:
266 WriteCall(Color_ReadIndex8_24b_6666);
267 break;
268 case FORMAT_32B_8888:
269 WriteCall(Color_ReadIndex8_32b_8888);
270 break;
271 default:
272 ASSERT(0);
273 break;
274 }
275 break;
276 case INDEX16:
277 m_VertexSize += 2;
278 switch (m_VtxAttr.color[i].Comp)
279 {
280 case FORMAT_16B_565:
281 WriteCall(Color_ReadIndex16_16b_565);
282 break;
283 case FORMAT_24B_888:
284 WriteCall(Color_ReadIndex16_24b_888);
285 break;
286 case FORMAT_32B_888x:
287 WriteCall(Color_ReadIndex16_32b_888x);
288 break;
289 case FORMAT_16B_4444:
290 WriteCall(Color_ReadIndex16_16b_4444);
291 break;
292 case FORMAT_24B_6666:
293 WriteCall(Color_ReadIndex16_24b_6666);
294 break;
295 case FORMAT_32B_8888:
296 WriteCall(Color_ReadIndex16_32b_8888);
297 break;
298 default:
299 ASSERT(0);
300 break;
301 }
302 break;
303 }
304 // Common for the three bottom cases
305 if (col[i] != NOT_PRESENT)
306 {
307 components |= VB_HAS_COL0 << i;
308 m_native_vtx_decl.colors[i].offset = nat_offset;
309 m_native_vtx_decl.colors[i].enable = true;
310 nat_offset += 4;
311 }
312 }
313
314 // Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
315 for (int i = 0; i < 8; i++)
316 {
317 m_native_vtx_decl.texcoords[i].offset = nat_offset;
318 m_native_vtx_decl.texcoords[i].type = VAR_FLOAT;
319 m_native_vtx_decl.texcoords[i].integer = false;
320
321 const int format = m_VtxAttr.texCoord[i].Format;
322 const int elements = m_VtxAttr.texCoord[i].Elements;
323
324 if (tc[i] != NOT_PRESENT)
325 {
326 ASSERT_MSG(VIDEO, DIRECT <= tc[i] && tc[i] <= INDEX16,
327 "Invalid texture coordinates!\n(tc[i] = %d)", (u32)tc[i]);
328 ASSERT_MSG(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT,
329 "Invalid texture coordinates format!\n(format = %d)", format);
330 ASSERT_MSG(VIDEO, 0 <= elements && elements <= 1,
331 "Invalid number of texture coordinates elements!\n(elements = %d)", elements);
332
333 components |= VB_HAS_UV0 << i;
334 WriteCall(VertexLoader_TextCoord::GetFunction(tc[i], format, elements));
335 m_VertexSize += VertexLoader_TextCoord::GetSize(tc[i], format, elements);
336 }
337
338 if (components & (VB_HAS_TEXMTXIDX0 << i))
339 {
340 m_native_vtx_decl.texcoords[i].enable = true;
341 if (tc[i] != NOT_PRESENT)
342 {
343 // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index
344 m_native_vtx_decl.texcoords[i].components = 3;
345 nat_offset += 12;
346 WriteCall(m_VtxAttr.texCoord[i].Elements ? TexMtx_Write_Float : TexMtx_Write_Float2);
347 }
348 else
349 {
350 m_native_vtx_decl.texcoords[i].components = 3;
351 nat_offset += 12;
352 WriteCall(TexMtx_Write_Float3);
353 }
354 }
355 else
356 {
357 if (tc[i] != NOT_PRESENT)
358 {
359 m_native_vtx_decl.texcoords[i].enable = true;
360 m_native_vtx_decl.texcoords[i].components = vtx_attr.texCoord[i].Elements ? 2 : 1;
361 nat_offset += 4 * (vtx_attr.texCoord[i].Elements ? 2 : 1);
362 }
363 }
364
365 if (tc[i] == NOT_PRESENT)
366 {
367 // if there's more tex coords later, have to write a dummy call
368 int j = i + 1;
369 for (; j < 8; ++j)
370 {
371 if (tc[j] != NOT_PRESENT)
372 {
373 WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right!
374 break;
375 }
376 }
377 // tricky!
378 if (j == 8 && !((components & VB_HAS_TEXMTXIDXALL) & (VB_HAS_TEXMTXIDXALL << (i + 1))))
379 {
380 // no more tex coords and tex matrices, so exit loop
381 break;
382 }
383 }
384 }
385
386 // indexed position formats may skip a the vertex
387 if (m_VtxDesc.Position & 2)
388 {
389 WriteCall(SkipVertex);
390 }
391
392 m_native_components = components;
393 m_native_vtx_decl.stride = nat_offset;
394 }
395
WriteCall(TPipelineFunction func)396 void VertexLoader::WriteCall(TPipelineFunction func)
397 {
398 m_PipelineStages[m_numPipelineStages++] = func;
399 }
400
RunVertices(DataReader src,DataReader dst,int count)401 int VertexLoader::RunVertices(DataReader src, DataReader dst, int count)
402 {
403 g_vertex_manager_write_ptr = dst.GetPointer();
404 g_video_buffer_read_ptr = src.GetPointer();
405
406 m_numLoadedVertices += count;
407 m_skippedVertices = 0;
408
409 for (m_counter = count - 1; m_counter >= 0; m_counter--)
410 {
411 m_tcIndex = 0;
412 m_colIndex = 0;
413 m_texmtxwrite = m_texmtxread = 0;
414 for (int i = 0; i < m_numPipelineStages; i++)
415 m_PipelineStages[i](this);
416 PRIM_LOG("\n");
417 }
418
419 return count - m_skippedVertices;
420 }
421