Extended -gfx-state to produce culling node analysis

This commit is contained in:
Bart Trzynadlowski 2017-04-11 07:03:47 +00:00
parent 9dd2b24729
commit 76817790d4
5 changed files with 91 additions and 30 deletions

View file

@ -162,11 +162,6 @@
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#ifdef DEBUG
extern bool g_forceFlushModels;
#endif
namespace Legacy3D { namespace Legacy3D {
// Microsoft doesn't provide isnan() and isinf() // Microsoft doesn't provide isnan() and isinf()
@ -668,9 +663,13 @@ void CLegacy3D::DescendCullingNode(UINT32 addr)
m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
} }
//printf("%08x NODE %d\n", addr, stackDepth); #ifdef DEBUG
//for (int i = 0; i < 8; i++) bool oldDebugHighlightAll = m_debugHighlightAll;
// printf(" %08x\n", node[i]); m_debugHighlightAll = (m_debugHighlightCullingNodeIdx >= 0) && (node[m_debugHighlightCullingNodeIdx] & m_debugHighlightCullingNodeMask) != 0;
#endif
//printf("%08x NODE %d\n", addr, stackDepth);
//for (int i = 0; i < 8; i++)
// printf(" %08x\n", node[i]);
// Debug: texture offset? (NOTE: offsets 1 and 2 don't exist on step 1.0) // Debug: texture offset? (NOTE: offsets 1 and 2 don't exist on step 1.0)
//if (node[0x02]&0xFFFF) //if (node[0x02]&0xFFFF)
@ -716,6 +715,9 @@ void CLegacy3D::DescendCullingNode(UINT32 addr)
// Proceed to second link // Proceed to second link
glPopMatrix(); glPopMatrix();
#ifdef DEBUG
m_debugHighlightAll = oldDebugHighlightAll;
#endif
if ((node[0x00] & 0x07) != 0x06) // seems to indicate second link is invalid (fixes circular references) if ((node[0x00] & 0x07) != 0x06) // seems to indicate second link is invalid (fixes circular references)
DescendNodePtr(node2Ptr); DescendNodePtr(node2Ptr);
--stackDepth; --stackDepth;
@ -1001,7 +1003,11 @@ void CLegacy3D::RenderFrame(void)
// Draw // Draw
#ifdef DEBUG #ifdef DEBUG
if (g_forceFlushModels) m_debugHighlightPolyHeaderIdx = m_config["Debug/HighlightPolyHeaderIdx"].ValueAsDefault<int>(-1);
m_debugHighlightPolyHeaderMask = m_config["Debug/HighlightPolyHeaderMask"].ValueAsDefault<uint32_t>(0);
m_debugHighlightCullingNodeIdx = m_config["Debug/HighlightCullingNodeIdx"].ValueAsDefault<int>(-1);
m_debugHighlightCullingNodeMask = m_config["Debug/HighlightCullingNodeMask"].ValueAsDefault<uint32_t>(0);
if (m_config["Debug/ForceFlushModels"].ValueAsDefault<bool>(false))
ClearModelCache(&VROMCache); ClearModelCache(&VROMCache);
#endif #endif
ClearModelCache(&PolyCache); ClearModelCache(&PolyCache);

View file

@ -390,6 +390,15 @@ private:
const Util::Config::Node &m_config; const Util::Config::Node &m_config;
#ifdef DEBUG
// Debug
int m_debugHighlightPolyHeaderIdx = -1;
uint32_t m_debugHighlightPolyHeaderMask = 0;
int m_debugHighlightCullingNodeIdx = -1;
uint32_t m_debugHighlightCullingNodeMask = 0;
bool m_debugHighlightAll = false;
#endif
// Stepping // Stepping
int step; int step;
int offset; // offset to subtract for words 3 and higher of culling nodes int offset; // offset to subtract for words 3 and higher of culling nodes

View file

@ -754,9 +754,9 @@ void CLegacy3D::InsertVertex(ModelCache *Cache, const Vertex *V, const Poly *P,
contourProcessing = 1.0f; contourProcessing = 1.0f;
#ifdef DEBUG #ifdef DEBUG
if (g_testPolyHeaderIdx >= 0) if (m_debugHighlightPolyHeaderIdx >= 0 || m_debugHighlightAll)
{ {
if ((P->header[g_testPolyHeaderIdx] & g_testPolyHeaderMask)) if ((P->header[m_debugHighlightPolyHeaderIdx] & m_debugHighlightPolyHeaderMask) || m_debugHighlightAll)
{ {
r = 0.; r = 0.;
g = 1.; g = 1.;

View file

@ -410,9 +410,6 @@ static void SaveFrameBuffer(const std::string &file)
Util::WriteSurfaceToBMP<Util::RGBA8>(file, pixels.get(), totalXRes, totalYRes, true); Util::WriteSurfaceToBMP<Util::RGBA8>(file, pixels.get(), totalXRes, totalYRes, true);
} }
bool g_forceFlushModels = false;
int g_testPolyHeaderIdx = -1;
uint32_t g_testPolyHeaderMask = 0;
static std::string s_gfxStatePath; static std::string s_gfxStatePath;
static std::string GetFileBaseName(const std::string &file) static std::string GetFileBaseName(const std::string &file)
@ -439,24 +436,54 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
0xffffff60, 0xffffff60,
0xff0300ff // contour, luminous, etc. 0xff0300ff // contour, luminous, etc.
}; };
const std::vector<uint32_t> unknownCullingNodeBits
{
0xffffffff,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
GLint readBuffer; GLint readBuffer;
glGetIntegerv(GL_READ_BUFFER, &readBuffer); glGetIntegerv(GL_READ_BUFFER, &readBuffer);
glReadBuffer(GL_FRONT); glReadBuffer(GL_FRONT);
// Render separate image for each unknown bit // Render separate image for each unknown bit
g_forceFlushModels = true; s_runtime_config.Set("Debug/ForceFlushModels", true);
for (int idx = 0; idx < 7; idx++) for (int idx = 0; idx < 7; idx++)
{ {
for (int bit = 0; bit < 32; bit++) for (int bit = 0; bit < 32; bit++)
{ {
uint32_t mask = 1 << bit; uint32_t mask = 1 << bit;
g_testPolyHeaderIdx = idx; s_runtime_config.Set("Debug/HighlightPolyHeaderIdx", idx);
g_testPolyHeaderMask = mask; s_runtime_config.Set("Debug/HighlightPolyHeaderMask", mask);
if ((unknownPolyBits[idx] & mask)) if ((unknownPolyBits[idx] & mask))
{ {
Emu->RenderFrame(); Emu->RenderFrame();
std::string file = Util::Format() << "Analysis/" << GetFileBaseName(s_gfxStatePath) << "." << idx << "_" << Util::Hex(mask) << ".bmp"; std::string file = Util::Format() << "Analysis/" << GetFileBaseName(s_gfxStatePath) << "." << "poly" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
SaveFrameBuffer(file);
}
}
}
for (int idx = 0; idx < 10; idx++)
{
for (int bit = 0; bit < 32; bit++)
{
uint32_t mask = 1 << bit;
s_runtime_config.Set("Debug/HighlightCullingNodeIdx", idx);
s_runtime_config.Set("Debug/HighlightCullingNodeMask", mask);
if ((unknownCullingNodeBits[idx] & mask))
{
Emu->RenderFrame();
std::string file = Util::Format() << "Analysis/" << GetFileBaseName(s_gfxStatePath) << "." << "culling" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
SaveFrameBuffer(file); SaveFrameBuffer(file);
} }
} }
@ -473,7 +500,8 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
{ {
std::string contents = s_polyAnalysisHTMLPrologue; std::string contents = s_polyAnalysisHTMLPrologue;
contents += " var g_file_base_name = '" + GetFileBaseName(s_gfxStatePath) + "';\n"; contents += " var g_file_base_name = '" + GetFileBaseName(s_gfxStatePath) + "';\n";
contents += " var g_unknown_bits = [" + std::string(Util::Format(",").Join(unknownPolyBits)) + "];\n"; contents += " var g_unknown_poly_bits = [" + std::string(Util::Format(",").Join(unknownPolyBits)) + "];\n";
contents += " var g_unknown_culling_bits = [" + std::string(Util::Format(",").Join(unknownCullingNodeBits)) + "];\n";
contents += s_polyAnalysisHTMLEpilogue; contents += s_polyAnalysisHTMLEpilogue;
fs << contents; fs << contents;
printf("Produced: %s\n", file.c_str()); printf("Produced: %s\n", file.c_str());

View file

@ -33,6 +33,7 @@ static const char s_polyAnalysisHTMLPrologue[] =
"<html>\n" "<html>\n"
"<head>\n" "<head>\n"
" <style>\n" " <style>\n"
" left { float: left; }\n"
" table { table-layout: fixed; }\n" " table { table-layout: fixed; }\n"
" td { border: 1px solid black; width: 1em; }\n" " td { border: 1px solid black; width: 1em; }\n"
" td.nonselectable { background-color: gray; }\n" " td.nonselectable { background-color: gray; }\n"
@ -42,10 +43,13 @@ static const char s_polyAnalysisHTMLPrologue[] =
" <script src='https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js'></script>\n" " <script src='https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js'></script>\n"
"</head>\n" "</head>\n"
"<body>\n" "<body>\n"
" <div id='Header'></div>\n" " <div id='Header'>\n"
" <div id='PolyBits' class='left'></div>\n"
" <div id='CullingBits' class='left'></div>\n"
" </div>\n"
" <div><img id='Image' /></div>\n" " <div><img id='Image' /></div>\n"
" <script>\n" " <script>\n"
// Insert g_file_base_name and g_unknown bits here, then append epilogue // Insert g_file_base_name, g_unknown_poly_bits, and g_unknown_culling_bits here, then append epilogue
}; };
static const char s_polyAnalysisHTMLEpilogue[] = static const char s_polyAnalysisHTMLEpilogue[] =
@ -54,27 +58,28 @@ static const char s_polyAnalysisHTMLEpilogue[] =
" {\n" " {\n"
" return '0x' + ('0000000'+Number(val).toString(16)).slice(-8);\n" " return '0x' + ('0000000'+Number(val).toString(16)).slice(-8);\n"
" }\n" " }\n"
" function getOnClickHandler(table, td, word, mask)\n"
" function createOnClickHandler(type, table, td, word, mask)\n"
" {\n" " {\n"
" return function()\n" " return function()\n"
" {\n" " {\n"
" var file = g_file_base_name + '.' + word + '_' + hex32(mask) + '.bmp';\n" " var file = g_file_base_name + '.' + type + '.' + word + '_' + hex32(mask) + '.bmp';\n"
" table.find('td').removeClass('selected'); // remove from all cells\n" " $('td').removeClass('selected'); // remove from all cells\n"
" td.addClass('selected');\n" " td.addClass('selected');\n"
" $('#Image').empty();\n" " $('#Image').empty();\n"
" $('#Image').attr('src', file);\n" " $('#Image').attr('src', file);\n"
" };\n" " };\n"
" }\n" " }\n"
" $(document).ready(function()\n"
" function buildTable(num_words, type, unknown_bits)\n"
" {\n" " {\n"
" // Construct table\n"
" var table = $('<table></table>');\n" " var table = $('<table></table>');\n"
" var bits_tr = $('<tr></tr>'); // first row will be bit legend\n" " var bits_tr = $('<tr></tr>'); // first row will be bit legend\n"
" bits_tr.append($('<td></td>')); // column for word numbers\n" " bits_tr.append($('<td></td>')); // column for word numbers\n"
" for (var bit = 31; bit >= 0; bit--)\n" " for (var bit = 31; bit >= 0; bit--)\n"
" bits_tr.append($('<td>'+bit+'</td>'));\n" " bits_tr.append($('<td>'+bit+'</td>'));\n"
" table.append(bits_tr);\n" " table.append(bits_tr);\n"
" for (var word = 0; word < 7; word++)\n" " for (var word = 0; word < num_words; word++)\n"
" {\n" " {\n"
" var tr = $('<tr></tr>');\n" " var tr = $('<tr></tr>');\n"
" tr.append($('<td>'+word+'</td>'));\n" " tr.append($('<td>'+word+'</td>'));\n"
@ -82,15 +87,28 @@ static const char s_polyAnalysisHTMLEpilogue[] =
" {\n" " {\n"
" var mask = 1 << bit;\n" " var mask = 1 << bit;\n"
" var td = $('<td></td>');\n" " var td = $('<td></td>');\n"
" if (g_unknown_bits[word] & mask)\n" " if (unknown_bits[word] & mask)\n"
" td.addClass('selectable').click(getOnClickHandler(table, td, word, mask));\n" " td.addClass('selectable').click(createOnClickHandler(type, table, td, word, mask));\n"
" else\n" " else\n"
" td.addClass('nonselectable');\n" " td.addClass('nonselectable');\n"
" tr.append(td);\n" " tr.append(td);\n"
" }\n" " }\n"
" table.append(tr);\n" " table.append(tr);\n"
" }\n" " }\n"
" $('#Header').append(table);\n" " return table;"
" }\n"
" $(document).ready(function()\n"
" {\n"
" // Construct tables\n"
" var poly_table = buildTable(7, 'poly', g_unknown_poly_bits);\n"
" var poly_title = $('<p></p>').text('Polygon Header');\n"
" $('#PolyBits').append(poly_title);\n"
" $('#PolyBits').append(poly_table);\n"
" var culling_table = buildTable(10, 'culling', g_unknown_culling_bits);\n"
" var culling_title = $('<p></p>').text('Culling Node');\n"
" $('#CullingBits').append(culling_title);\n"
" $('#CullingBits').append(culling_table);\n"
" });\n" " });\n"
" </script>\n" " </script>\n"
"</body>\n" "</body>\n"