aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/video_core/debug_utils
diff options
context:
space:
mode:
authorGravatar Tony Wasserka <NeoBrainX@gmail.com>2014-08-14 14:30:38 +0200
committerGravatar Tony Wasserka <NeoBrainX@gmail.com>2014-08-25 22:03:18 +0200
commitf37e39deb9abe88b4874ebc2889ed52e02ed9c13 (patch)
treebbced32a26ee671ffb69de1c42492fc13b8f6724 /src/video_core/debug_utils
parent6ea003c7b5ec97d0a754197654cdf6e7fccdba24 (diff)
Pica: Add debug utilities for dumping shaders.
Diffstat (limited to 'src/video_core/debug_utils')
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp205
-rw-r--r--src/video_core/debug_utils/debug_utils.h3
2 files changed, 208 insertions, 0 deletions
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index ac895ec3..f41249ea 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
+#include <algorithm>
#include <fstream>
#include <string>
@@ -55,6 +56,210 @@ void GeometryDumper::Dump() {
}
}
+#pragma pack(1)
+struct DVLBHeader {
+ enum : u32 {
+ MAGIC_WORD = 0x424C5644, // "DVLB"
+ };
+
+ u32 magic_word;
+ u32 num_programs;
+// u32 dvle_offset_table[];
+};
+static_assert(sizeof(DVLBHeader) == 0x8, "Incorrect structure size");
+
+struct DVLPHeader {
+ enum : u32 {
+ MAGIC_WORD = 0x504C5644, // "DVLP"
+ };
+
+ u32 magic_word;
+ u32 version;
+ u32 binary_offset; // relative to DVLP start
+ u32 binary_size_words;
+ u32 swizzle_patterns_offset;
+ u32 swizzle_patterns_num_entries;
+ u32 unk2;
+};
+static_assert(sizeof(DVLPHeader) == 0x1C, "Incorrect structure size");
+
+struct DVLEHeader {
+ enum : u32 {
+ MAGIC_WORD = 0x454c5644, // "DVLE"
+ };
+
+ enum class ShaderType : u8 {
+ VERTEX = 0,
+ GEOMETRY = 1,
+ };
+
+ u32 magic_word;
+ u16 pad1;
+ ShaderType type;
+ u8 pad2;
+ u32 main_offset_words; // offset within binary blob
+ u32 endmain_offset_words;
+ u32 pad3;
+ u32 pad4;
+ u32 constant_table_offset;
+ u32 constant_table_size; // number of entries
+ u32 label_table_offset;
+ u32 label_table_size;
+ u32 output_register_table_offset;
+ u32 output_register_table_size;
+ u32 uniform_table_offset;
+ u32 uniform_table_size;
+ u32 symbol_table_offset;
+ u32 symbol_table_size;
+
+};
+static_assert(sizeof(DVLEHeader) == 0x40, "Incorrect structure size");
+#pragma pack()
+
+void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
+ u32 main_offset, const Regs::VSOutputAttributes* output_attributes)
+{
+ // NOTE: Permanently enabling this just trashes hard disks for no reason.
+ // Hence, this is currently disabled.
+ return;
+
+ struct StuffToWrite {
+ u8* pointer;
+ u32 size;
+ };
+ std::vector<StuffToWrite> writing_queue;
+ u32 write_offset = 0;
+
+ auto QueueForWriting = [&writing_queue,&write_offset](u8* pointer, u32 size) {
+ writing_queue.push_back({pointer, size});
+ u32 old_write_offset = write_offset;
+ write_offset += size;
+ return old_write_offset;
+ };
+
+ // First off, try to translate Pica state (one enum for output attribute type and component)
+ // into shbin format (separate type and component mask).
+ union OutputRegisterInfo {
+ enum Type : u64 {
+ POSITION = 0,
+ COLOR = 2,
+ TEXCOORD0 = 3,
+ TEXCOORD1 = 5,
+ TEXCOORD2 = 6,
+ };
+
+ BitField< 0, 64, u64> hex;
+
+ BitField< 0, 16, Type> type;
+ BitField<16, 16, u64> id;
+ BitField<32, 4, u64> component_mask;
+ };
+
+ // This is put into a try-catch block to make sure we notice unknown configurations.
+ std::vector<OutputRegisterInfo> output_info_table;
+ for (int i = 0; i < 7; ++i) {
+ using OutputAttributes = Pica::Regs::VSOutputAttributes;
+
+ // TODO: It's still unclear how the attribute components map to the register!
+ // Once we know that, this code probably will not make much sense anymore.
+ std::map<OutputAttributes::Semantic, std::pair<OutputRegisterInfo::Type, u32> > map = {
+ { OutputAttributes::POSITION_X, { OutputRegisterInfo::POSITION, 1} },
+ { OutputAttributes::POSITION_Y, { OutputRegisterInfo::POSITION, 2} },
+ { OutputAttributes::POSITION_Z, { OutputRegisterInfo::POSITION, 4} },
+ { OutputAttributes::POSITION_W, { OutputRegisterInfo::POSITION, 8} },
+ { OutputAttributes::COLOR_R, { OutputRegisterInfo::COLOR, 1} },
+ { OutputAttributes::COLOR_G, { OutputRegisterInfo::COLOR, 2} },
+ { OutputAttributes::COLOR_B, { OutputRegisterInfo::COLOR, 4} },
+ { OutputAttributes::COLOR_A, { OutputRegisterInfo::COLOR, 8} },
+ { OutputAttributes::TEXCOORD0_U, { OutputRegisterInfo::TEXCOORD0, 1} },
+ { OutputAttributes::TEXCOORD0_V, { OutputRegisterInfo::TEXCOORD0, 2} },
+ { OutputAttributes::TEXCOORD1_U, { OutputRegisterInfo::TEXCOORD1, 1} },
+ { OutputAttributes::TEXCOORD1_V, { OutputRegisterInfo::TEXCOORD1, 2} },
+ { OutputAttributes::TEXCOORD2_U, { OutputRegisterInfo::TEXCOORD2, 1} },
+ { OutputAttributes::TEXCOORD2_V, { OutputRegisterInfo::TEXCOORD2, 2} }
+ };
+
+ for (const auto& semantic : std::vector<OutputAttributes::Semantic>{
+ output_attributes[i].map_x,
+ output_attributes[i].map_y,
+ output_attributes[i].map_z,
+ output_attributes[i].map_w }) {
+ if (semantic == OutputAttributes::INVALID)
+ continue;
+
+ try {
+ OutputRegisterInfo::Type type = map.at(semantic).first;
+ u32 component_mask = map.at(semantic).second;
+
+ auto it = std::find_if(output_info_table.begin(), output_info_table.end(),
+ [&i, &type](const OutputRegisterInfo& info) {
+ return info.id == i && info.type == type;
+ }
+ );
+
+ if (it == output_info_table.end()) {
+ output_info_table.push_back({});
+ output_info_table.back().type = type;
+ output_info_table.back().component_mask = component_mask;
+ output_info_table.back().id = i;
+ } else {
+ it->component_mask = it->component_mask | component_mask;
+ }
+ } catch (const std::out_of_range& oor) {
+ _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping");
+ ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
+ (int)output_attributes[i].map_x.Value(),
+ (int)output_attributes[i].map_y.Value(),
+ (int)output_attributes[i].map_z.Value(),
+ (int)output_attributes[i].map_w.Value());
+ }
+ }
+ }
+
+
+ struct {
+ DVLBHeader header;
+ u32 dvle_offset;
+ } dvlb{ {DVLBHeader::MAGIC_WORD, 1 } }; // 1 DVLE
+
+ DVLPHeader dvlp{ DVLPHeader::MAGIC_WORD };
+ DVLEHeader dvle{ DVLEHeader::MAGIC_WORD };
+
+ QueueForWriting((u8*)&dvlb, sizeof(dvlb));
+ u32 dvlp_offset = QueueForWriting((u8*)&dvlp, sizeof(dvlp));
+ dvlb.dvle_offset = QueueForWriting((u8*)&dvle, sizeof(dvle));
+
+ // TODO: Reduce the amount of binary code written to relevant portions
+ dvlp.binary_offset = write_offset - dvlp_offset;
+ dvlp.binary_size_words = binary_size;
+ QueueForWriting((u8*)binary_data, binary_size * sizeof(u32));
+
+ dvlp.swizzle_patterns_offset = write_offset - dvlp_offset;
+ dvlp.swizzle_patterns_num_entries = swizzle_size;
+ u32 dummy = 0;
+ for (int i = 0; i < swizzle_size; ++i) {
+ QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i]));
+ QueueForWriting((u8*)&dummy, sizeof(dummy));
+ }
+
+ dvle.main_offset_words = main_offset;
+ dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
+ dvle.output_register_table_size = output_info_table.size();
+ QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo));
+
+ // TODO: Create a label table for "main"
+
+
+ // Write data to file
+ static int dump_index = 0;
+ std::string filename = std::string("shader_dump") + std::to_string(++dump_index) + std::string(".shbin");
+ std::ofstream file(filename, std::ios_base::out | std::ios_base::binary);
+
+ for (auto& chunk : writing_queue) {
+ file.write((char*)chunk.pointer, chunk.size);
+ }
+}
+
} // namespace
} // namespace
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 9b4dce53..bd7a0a89 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -35,6 +35,9 @@ private:
std::vector<Face> faces;
};
+void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
+ u32 main_offset, const Regs::VSOutputAttributes* output_attributes);
+
} // namespace
} // namespace