First pass ShaderTranslator base type, able to disasm in msft style.

This commit is contained in:
Ben Vanik 2015-11-28 16:19:04 -08:00
parent bea8870700
commit 65130edaa1
11 changed files with 2796 additions and 716 deletions

View File

@ -83,4 +83,10 @@ std::string StringBuffer::to_string() {
char* StringBuffer::ToString() { return strdup(buffer_); }
std::vector<uint8_t> StringBuffer::ToBytes() const {
std::vector<uint8_t> bytes(buffer_offset_);
std::memcpy(bytes.data(), buffer_, buffer_offset_);
return bytes;
}
} // namespace xe

View File

@ -12,6 +12,7 @@
#include <cstdint>
#include <string>
#include <vector>
namespace xe {
@ -34,6 +35,7 @@ class StringBuffer {
const char* GetString() const;
std::string to_string();
char* ToString();
std::vector<uint8_t> ToBytes() const;
private:
void Grow(size_t additional_length);

View File

@ -18,68 +18,83 @@
#include "xenia/base/string.h"
#include "xenia/gpu/shader_translator.h"
DEFINE_string(input_shader, "", "Input shader binary file path.");
DEFINE_string(
shader_type, "",
"'vert', 'frag', or unspecified to infer from the given filename.");
DEFINE_string(shader_input, "", "Input shader binary file path.");
DEFINE_string(shader_input_type, "",
"'vs', 'ps', or unspecified to infer from the given filename.");
DEFINE_string(shader_output, "", "Output shader file path.");
DEFINE_string(shader_output_type, "ucode",
"Translator to use: [ucode, spirvtext].");
namespace xe {
namespace gpu {
int shader_compiler_main(const std::vector<std::wstring>& args) {
ShaderType shader_type;
if (!FLAGS_shader_type.empty()) {
if (FLAGS_shader_type == "vert") {
if (!FLAGS_shader_input_type.empty()) {
if (FLAGS_shader_input_type == "vs") {
shader_type = ShaderType::kVertex;
} else if (FLAGS_shader_type == "frag") {
} else if (FLAGS_shader_input_type == "ps") {
shader_type = ShaderType::kPixel;
} else {
XELOGE("Invalid --shader_type; must be 'vert' or 'frag'.");
XELOGE("Invalid --shader_input_type; must be 'vs' or 'ps'.");
return 1;
}
} else {
auto last_dot = FLAGS_input_shader.find_last_of('.');
auto last_dot = FLAGS_shader_input.find_last_of('.');
bool valid_type = false;
if (last_dot != std::string::npos) {
if (FLAGS_input_shader.substr(last_dot) == ".vert") {
if (FLAGS_shader_input.substr(last_dot) == ".vs") {
shader_type = ShaderType::kVertex;
valid_type = true;
} else if (FLAGS_input_shader.substr(last_dot) == ".frag") {
} else if (FLAGS_shader_input.substr(last_dot) == ".ps") {
shader_type = ShaderType::kPixel;
valid_type = true;
}
}
if (!valid_type) {
XELOGE(
"File type not recognized (use .vert, .frag or "
"--shader_type=vert|frag).");
"File type not recognized (use .vs, .ps or "
"--shader_input_type=vs|ps).");
return 1;
}
}
auto input_file = fopen(FLAGS_input_shader.c_str(), "r");
auto input_file = fopen(FLAGS_shader_input.c_str(), "rb");
if (!input_file) {
XELOGE("Unable to open input file: %s", FLAGS_input_shader.c_str());
XELOGE("Unable to open input file: %s", FLAGS_shader_input.c_str());
return 1;
}
fseek(input_file, 0, SEEK_END);
size_t input_file_size = ftell(input_file);
fseek(input_file, 0, SEEK_SET);
std::vector<uint32_t> ucode_words(input_file_size / 4);
fread(ucode_words.data(), 4, ucode_words.size(), input_file);
std::vector<uint32_t> ucode_dwords(input_file_size / 4);
fread(ucode_dwords.data(), 4, ucode_dwords.size(), input_file);
fclose(input_file);
XELOGI("Opened %s as a %s shader, %" PRId64 " words (%" PRId64 " bytes).",
FLAGS_input_shader.c_str(),
shader_type == ShaderType::kVertex ? "vertex" : "fragment",
ucode_words.size(), ucode_words.size() * 4);
FLAGS_shader_input.c_str(),
shader_type == ShaderType::kVertex ? "vertex" : "pixel",
ucode_dwords.size(), ucode_dwords.size() * 4);
ShaderTranslator translator;
std::unique_ptr<ShaderTranslator> translator;
if (FLAGS_shader_output_type == "spirvtext") {
// TODO(benvanik): SPIRV translator.
translator = std::make_unique<UcodeShaderTranslator>();
} else {
translator = std::make_unique<UcodeShaderTranslator>();
}
// TODO(benvanik): hash? need to return the data to big-endian format first.
uint64_t ucode_data_hash = 0;
auto translated_shader = translator.Translate(
shader_type, ucode_data_hash, ucode_words.data(), ucode_words.size());
auto translated_shader = translator->Translate(
shader_type, ucode_data_hash, ucode_dwords.data(), ucode_dwords.size());
if (!FLAGS_shader_output.empty()) {
auto output_file = fopen(FLAGS_shader_output.c_str(), "w");
fwrite(translated_shader->binary().data(),
translated_shader->binary().size(), 1, output_file);
fclose(output_file);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -11,44 +11,316 @@
#define XENIA_GPU_SHADER_TRANSLATOR_H_
#include <memory>
#include <string>
#include <vector>
#include "xenia/base/string_buffer.h"
#include "xenia/gpu/ucode.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/spirv/spirv_util.h"
namespace xe {
namespace gpu {
class TranslatedShader {
public:
TranslatedShader(ShaderType shader_type, uint64_t ucode_data_hash,
const uint32_t* ucode_words, size_t ucode_word_count);
struct Error {
bool is_fatal = false;
std::string message;
};
struct VertexBinding {
// Index within the vertex binding listing.
size_t binding_index;
// Fetch constant index [0-95].
uint32_t fetch_constant;
// Fetch instruction with all parameters.
ucode::VertexFetchInstruction op;
};
struct TextureBinding {
// Index within the texture binding listing.
size_t binding_index;
// Fetch constant index [0-31].
uint32_t fetch_constant;
// Fetch instruction with all parameters.
ucode::TextureFetchInstruction op;
};
~TranslatedShader();
ShaderType type() const { return shader_type_; }
const uint32_t* ucode_words() const { return ucode_data_.data(); }
size_t ucode_word_count() const { return ucode_data_.size(); }
const std::vector<uint32_t>& ucode_data() const { return ucode_data_; }
const uint32_t* ucode_dwords() const { return ucode_data_.data(); }
size_t ucode_dword_count() const { return ucode_data_.size(); }
const std::vector<VertexBinding>& vertex_bindings() const {
return vertex_bindings_;
}
const std::vector<TextureBinding>& texture_bindings() const {
return texture_bindings_;
}
bool is_valid() const { return is_valid_; }
const std::vector<Error> errors() const { return errors_; }
const std::vector<uint8_t> binary() const { return binary_; }
private:
friend class ShaderTranslator;
TranslatedShader(ShaderType shader_type, uint64_t ucode_data_hash,
const uint32_t* ucode_dwords, size_t ucode_dword_count,
std::vector<Error> errors);
ShaderType shader_type_;
std::vector<uint32_t> ucode_data_;
uint64_t ucode_data_hash_;
std::vector<VertexBinding> vertex_bindings_;
std::vector<TextureBinding> texture_bindings_;
bool is_valid_ = false;
std::vector<Error> errors_;
std::vector<uint8_t> binary_;
};
class ShaderTranslator {
public:
ShaderTranslator();
virtual ~ShaderTranslator();
std::unique_ptr<TranslatedShader> Translate(ShaderType shader_type,
uint64_t ucode_data_hash,
const uint32_t* ucode_words,
size_t ucode_word_count);
const uint32_t* ucode_dwords,
size_t ucode_dword_count);
protected:
ShaderTranslator();
size_t ucode_disasm_line_number() const { return ucode_disasm_line_number_; }
StringBuffer& ucode_disasm_buffer() { return ucode_disasm_buffer_; }
void EmitTranslationError(const char* message);
virtual std::vector<uint8_t> CompleteTranslation() {
return std::vector<uint8_t>();
}
virtual void ProcessControlFlowNop(const ucode::ControlFlowInstruction& cf) {}
virtual void ProcessControlFlowExec(
const ucode::ControlFlowExecInstruction& cf) {}
virtual void ProcessControlFlowCondExec(
const ucode::ControlFlowCondExecInstruction& cf) {}
virtual void ProcessControlFlowCondExecPred(
const ucode::ControlFlowCondExecPredInstruction& cf) {}
virtual void ProcessControlFlowLoopStart(
const ucode::ControlFlowLoopStartInstruction& cf) {}
virtual void ProcessControlFlowLoopEnd(
const ucode::ControlFlowLoopEndInstruction& cf) {}
virtual void ProcessControlFlowCondCall(
const ucode::ControlFlowCondCallInstruction& cf) {}
virtual void ProcessControlFlowReturn(
const ucode::ControlFlowReturnInstruction& cf) {}
virtual void ProcessControlFlowCondJmp(
const ucode::ControlFlowCondJmpInstruction& cf) {}
virtual void ProcessControlFlowAlloc(
const ucode::ControlFlowAllocInstruction& cf) {}
virtual void ProcessVertexFetchInstruction(
const ucode::VertexFetchInstruction& op) {}
virtual void ProcessTextureFetchTextureFetch(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureBorderColorFrac(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureComputedLod(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureGradients(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchGetTextureWeights(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureLod(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureGradientsHorz(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessTextureFetchSetTextureGradientsVert(
const ucode::TextureFetchInstruction& op) {}
virtual void ProcessAluNop(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorAdd(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMul(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMax(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMin(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorFrac(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorTrunc(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMad(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCndGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp4(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp3(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDp2Add(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorCube(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMax4(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetEQPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetNEPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetGTPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorPredSetGEPush(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillLGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorKillNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorDst(const ucode::AluInstruction& op) {}
virtual void ProcessAluVectorMaxA(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAdd(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMul(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulPrev2(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMax(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMin(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarFrac(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarTrunc(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarExp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarLogClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarLog(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRecipClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRecipFixedFunc(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarRecip(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRSqrtClamp(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRSqrtFixedFunc(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarRSqrt(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMovA(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMovAFloor(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSub(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubPrev(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetInv(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetPop(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetClear(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarPredSetRestore(const ucode::AluInstruction& op) {
}
virtual void ProcessAluScalarKillEQ(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillGT(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillGE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillNE(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarKillOne(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSqrt(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarMulConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarAddConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubConst0(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSubConst1(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarSin(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarCos(const ucode::AluInstruction& op) {}
virtual void ProcessAluScalarRetainPrev(const ucode::AluInstruction& op) {}
private:
struct AluOpcodeInfo {
const char* name;
size_t argument_count;
int src_swizzle_component_count;
void (ShaderTranslator::*fn)(const ucode::AluInstruction& op);
};
void MarkUcodeInstruction(uint32_t dword_offset);
void AppendUcodeDisasm(char c);
void AppendUcodeDisasm(const char* value);
void AppendUcodeDisasmFormat(const char* format, ...);
bool TranslateBlocks();
void GatherBindingInformation(const ucode::ControlFlowInstruction& cf);
void GatherVertexBindingInformation(const ucode::VertexFetchInstruction& op);
void GatherTextureBindingInformation(
const ucode::TextureFetchInstruction& op);
void TranslateControlFlowInstruction(const ucode::ControlFlowInstruction& cf);
void TranslateControlFlowNop(const ucode::ControlFlowInstruction& cf);
void TranslateControlFlowExec(const ucode::ControlFlowExecInstruction& cf);
void TranslateControlFlowCondExec(
const ucode::ControlFlowCondExecInstruction& cf);
void TranslateControlFlowCondExecPred(
const ucode::ControlFlowCondExecPredInstruction& cf);
void TranslateControlFlowLoopStart(
const ucode::ControlFlowLoopStartInstruction& cf);
void TranslateControlFlowLoopEnd(
const ucode::ControlFlowLoopEndInstruction& cf);
void TranslateControlFlowCondCall(
const ucode::ControlFlowCondCallInstruction& cf);
void TranslateControlFlowReturn(
const ucode::ControlFlowReturnInstruction& cf);
void TranslateControlFlowCondJmp(
const ucode::ControlFlowCondJmpInstruction& cf);
void TranslateControlFlowAlloc(const ucode::ControlFlowAllocInstruction& cf);
void TranslateExecInstructions(uint32_t address, uint32_t count,
uint32_t sequence);
void DisasmFetchDestReg(uint32_t dest, uint32_t swizzle, bool is_relative);
void DisasmFetchSourceReg(uint32_t src, uint32_t swizzle, bool is_relative,
int component_count);
void TranslateVertexFetchInstruction(const ucode::VertexFetchInstruction& op);
void TranslateTextureFetchInstruction(
const ucode::TextureFetchInstruction& op);
void DisasmVertexFetchAttributes(const ucode::VertexFetchInstruction& op);
void DisasmTextureFetchAttributes(const ucode::TextureFetchInstruction& op);
void TranslateAluInstruction(const ucode::AluInstruction& op);
void DisasmAluVectorInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
void DisasmAluScalarInstruction(const ucode::AluInstruction& op,
const AluOpcodeInfo& opcode_info);
void DisasmAluSourceReg(const ucode::AluInstruction& op, int i,
int swizzle_component_count);
void DisasmAluSourceRegScalarSpecial(const ucode::AluInstruction& op,
uint32_t reg, bool is_temp, bool negate,
int const_slot, uint32_t swizzle);
// Input shader metadata and microcode.
ShaderType shader_type_;
const uint32_t* ucode_dwords_;
size_t ucode_dword_count_;
// Accumulated translation errors.
std::vector<TranslatedShader::Error> errors_;
// Microcode disassembly buffer, accumulated throughout the translation.
StringBuffer ucode_disasm_buffer_;
// Current line number in the disasm, which can be used for source annotation.
size_t ucode_disasm_line_number_ = 0;
// Last offset used when scanning for line numbers.
size_t previous_ucode_disasm_scan_offset_ = 0;
// Kept for supporting vfetch_mini.
ucode::VertexFetchInstruction previous_vfetch_full_;
// Detected binding information gathered before translation.
std::vector<TranslatedShader::VertexBinding> vertex_bindings_;
std::vector<TranslatedShader::TextureBinding> texture_bindings_;
static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];
static const AluOpcodeInfo alu_scalar_opcode_infos_[0x40];
};
class UcodeShaderTranslator : public ShaderTranslator {
public:
UcodeShaderTranslator() = default;
protected:
std::vector<uint8_t> CompleteTranslation() override;
};
} // namespace gpu

File diff suppressed because it is too large Load Diff

View File

@ -1151,6 +1151,17 @@ Id SpirvEmitter::CreateExtendedInstructionCall(spv::Decoration precision,
return instr->result_id();
}
Id SpirvEmitter::CreateGlslStd450InstructionCall(
spv::Decoration precision, Id result_type,
spv::GLSLstd450 instruction_ordinal, std::initializer_list<Id> args) {
if (!glsl_std_450_instruction_set_) {
glsl_std_450_instruction_set_ = ImportExtendedInstructions("GLSL.std.450");
}
return CreateExtendedInstructionCall(
precision, result_type, glsl_std_450_instruction_set_,
static_cast<int>(instruction_ordinal), args);
}
// Accept all parameters needed to create a texture instruction.
// Create the correct instruction based on the inputs, and make the call.
Id SpirvEmitter::CreateTextureCall(spv::Decoration precision, Id result_type,

View File

@ -373,6 +373,10 @@ class SpirvEmitter {
Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type,
Id instruction_set, int instruction_ordinal,
std::initializer_list<Id> args);
// Executes an instruction from the extended GLSL set.
Id CreateGlslStd450InstructionCall(spv::Decoration precision, Id result_type,
spv::GLSLstd450 instruction_ordinal,
std::initializer_list<Id> args);
// List of parameters used to create a texture operation
struct TextureParameters {
@ -655,6 +659,7 @@ class SpirvEmitter {
Id unique_id_ = 0;
Function* main_function_ = nullptr;
AccessChain access_chain_;
Id glsl_std_450_instruction_set_ = 0;
// special blocks of instructions for output
std::vector<Instruction*> imports_;

View File

@ -23,94 +23,175 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.wordsTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.sourceCodeTextBox = new System.Windows.Forms.TextBox();
this.outputTextBox = new System.Windows.Forms.TextBox();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.wordsTextBox = new System.Windows.Forms.TextBox();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.compilerUcodeTextBox = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.compilerTranslatedTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// sourceCodeTextBox
//
this.sourceCodeTextBox.AcceptsReturn = true;
this.sourceCodeTextBox.AcceptsTab = true;
this.sourceCodeTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.sourceCodeTextBox.Location = new System.Drawing.Point(0, 0);
this.sourceCodeTextBox.Multiline = true;
this.sourceCodeTextBox.Name = "sourceCodeTextBox";
this.sourceCodeTextBox.Size = new System.Drawing.Size(352, 360);
this.sourceCodeTextBox.TabIndex = 0;
//
// outputTextBox
//
this.outputTextBox.AcceptsReturn = true;
this.outputTextBox.AcceptsTab = true;
this.outputTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.outputTextBox.Location = new System.Drawing.Point(0, 0);
this.outputTextBox.Multiline = true;
this.outputTextBox.Name = "outputTextBox";
this.outputTextBox.ReadOnly = true;
this.outputTextBox.Size = new System.Drawing.Size(349, 360);
this.outputTextBox.TabIndex = 1;
//
// splitContainer1
//
this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.splitContainer1.Location = new System.Drawing.Point(12, 12);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.sourceCodeTextBox);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.outputTextBox);
this.splitContainer1.Size = new System.Drawing.Size(705, 360);
this.splitContainer1.SplitterDistance = 352;
this.splitContainer1.TabIndex = 2;
//
//
// wordsTextBox
//
this.wordsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
//
this.wordsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.wordsTextBox.Location = new System.Drawing.Point(12, 378);
this.wordsTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.wordsTextBox.Location = new System.Drawing.Point(12, 657);
this.wordsTextBox.Multiline = true;
this.wordsTextBox.Name = "wordsTextBox";
this.wordsTextBox.ReadOnly = true;
this.wordsTextBox.Size = new System.Drawing.Size(705, 251);
this.wordsTextBox.Size = new System.Drawing.Size(1631, 137);
this.wordsTextBox.TabIndex = 4;
//
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanel1.ColumnCount = 4;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
this.tableLayoutPanel1.Controls.Add(this.compilerTranslatedTextBox, 3, 1);
this.tableLayoutPanel1.Controls.Add(this.sourceCodeTextBox, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.outputTextBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.compilerUcodeTextBox, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.label2, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.label3, 2, 0);
this.tableLayoutPanel1.Controls.Add(this.label4, 3, 0);
this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(1631, 639);
this.tableLayoutPanel1.TabIndex = 5;
//
// sourceCodeTextBox
//
this.sourceCodeTextBox.AcceptsReturn = true;
this.sourceCodeTextBox.AcceptsTab = true;
this.sourceCodeTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.sourceCodeTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.sourceCodeTextBox.Location = new System.Drawing.Point(3, 23);
this.sourceCodeTextBox.Multiline = true;
this.sourceCodeTextBox.Name = "sourceCodeTextBox";
this.sourceCodeTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.sourceCodeTextBox.Size = new System.Drawing.Size(401, 613);
this.sourceCodeTextBox.TabIndex = 6;
//
// outputTextBox
//
this.outputTextBox.AcceptsReturn = true;
this.outputTextBox.AcceptsTab = true;
this.outputTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.outputTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.outputTextBox.Location = new System.Drawing.Point(410, 23);
this.outputTextBox.Multiline = true;
this.outputTextBox.Name = "outputTextBox";
this.outputTextBox.ReadOnly = true;
this.outputTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.outputTextBox.Size = new System.Drawing.Size(401, 613);
this.outputTextBox.TabIndex = 5;
//
// compilerUcodeTextBox
//
this.compilerUcodeTextBox.AcceptsReturn = true;
this.compilerUcodeTextBox.AcceptsTab = true;
this.compilerUcodeTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.compilerUcodeTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.compilerUcodeTextBox.Location = new System.Drawing.Point(817, 23);
this.compilerUcodeTextBox.Multiline = true;
this.compilerUcodeTextBox.Name = "compilerUcodeTextBox";
this.compilerUcodeTextBox.ReadOnly = true;
this.compilerUcodeTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.compilerUcodeTextBox.Size = new System.Drawing.Size(401, 613);
this.compilerUcodeTextBox.TabIndex = 4;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(78, 13);
this.label1.TabIndex = 7;
this.label1.Text = "Input Assembly";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(410, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(107, 13);
this.label2.TabIndex = 8;
this.label2.Text = "XNA Compiler Output";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(817, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(191, 13);
this.label3.TabIndex = 9;
this.label3.Text = "xenia-gpu-shader-compiler Disassembly";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(1224, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(183, 13);
this.label4.TabIndex = 10;
this.label4.Text = "xenia-gpu-shader-compiler Translated";
//
// compilerTranslatedTextBox
//
this.compilerTranslatedTextBox.AcceptsReturn = true;
this.compilerTranslatedTextBox.AcceptsTab = true;
this.compilerTranslatedTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.compilerTranslatedTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.compilerTranslatedTextBox.Location = new System.Drawing.Point(1224, 23);
this.compilerTranslatedTextBox.Multiline = true;
this.compilerTranslatedTextBox.Name = "compilerTranslatedTextBox";
this.compilerTranslatedTextBox.ReadOnly = true;
this.compilerTranslatedTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.compilerTranslatedTextBox.Size = new System.Drawing.Size(404, 613);
this.compilerTranslatedTextBox.TabIndex = 11;
//
// Editor
//
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(729, 641);
this.ClientSize = new System.Drawing.Size(1655, 806);
this.Controls.Add(this.tableLayoutPanel1);
this.Controls.Add(this.wordsTextBox);
this.Controls.Add(this.splitContainer1);
this.Name = "Editor";
this.Text = "Shader Playground";
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel1.PerformLayout();
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
this.splitContainer1.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox wordsTextBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TextBox sourceCodeTextBox;
private System.Windows.Forms.TextBox outputTextBox;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.TextBox wordsTextBox;
private System.Windows.Forms.TextBox compilerUcodeTextBox;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox compilerTranslatedTextBox;
private System.Windows.Forms.Label label4;
}
}

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
@ -9,34 +10,84 @@ using System.Windows.Forms;
namespace shader_playground {
public partial class Editor : Form {
string compilerPath_ = @"..\..\..\..\..\build\bin\Windows\Debug\xenia-gpu-shader-compiler.exe";
FileSystemWatcher compilerWatcher_;
public Editor() {
InitializeComponent();
wordsTextBox.Click += WordsTextBox_Click;
var compilerBinPath = Path.Combine(Directory.GetCurrentDirectory(),
Path.GetDirectoryName(compilerPath_));
compilerWatcher_ = new FileSystemWatcher(compilerBinPath, "*.exe");
compilerWatcher_.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
compilerWatcher_.Changed += (object sender, FileSystemEventArgs e) => {
if (e.Name == Path.GetFileName(compilerPath_)) {
Invoke((MethodInvoker)delegate { Process(sourceCodeTextBox.Text); });
}
};
compilerWatcher_.EnableRaisingEvents = true;
wordsTextBox.Click += (object sender, EventArgs e) => {
wordsTextBox.SelectAll();
wordsTextBox.Copy();
};
this.sourceCodeTextBox.Click += (object sender, EventArgs e) => {
Process(sourceCodeTextBox.Text);
};
sourceCodeTextBox.TextChanged += (object sender, EventArgs e) => {
Process(sourceCodeTextBox.Text);
};
sourceCodeTextBox.TextChanged += SourceCodeTextBox_TextChanged;
sourceCodeTextBox.Text = string.Join(
"\r\n", new string[] {
"xps_3_0",
"dcl_texcoord1 r0",
"dcl_color r1.xy",
"exec",
"alloc colors",
"exece",
"mad oC0, r0, r1.y, c0",
"mul r4.xyz, r1.xyz, c0.xyz",
"+ adds r5.w, r0.xy",
"cnop",
});
}
private void WordsTextBox_Click(object sender, EventArgs e) {
wordsTextBox.SelectAll();
wordsTextBox.Copy();
}
void SourceCodeTextBox_TextChanged(object sender, EventArgs e) {
Assemble(sourceCodeTextBox.Text);
"xps_3_0",
"dcl_texcoord1 r0",
"dcl_color r1.xy",
"exec",
"alloc colors",
"exec",
"tfetch1D r2, r0.y, tf0, FetchValidOnly=false",
"tfetch1D r2, r0.x, tf2",
"tfetch2D r3, r3.wx, tf13",
"tfetch2D r[aL+3], r[aL+5].wx, tf13, FetchValidOnly=false, UnnormalizedTextureCoords=true, MagFilter=linear, MinFilter=linear, MipFilter=point, AnisoFilter=max1to1, UseRegisterGradients=true, UseComputedLOD=false, UseRegisterLOD=true, OffsetX=-1.5, OffsetY=1.0",
"tfetch3D r31.w_01, r0.xyw, tf15",
"tfetchCube r5, r1.xyw, tf31",
" setTexLOD r1.z",
" setGradientH r1.zyx",
"(!p0) setGradientV r1.zyx",
" getGradients r5, r1.xy, tf3",
" mad oC0, r0, r1.yyyy, c0",
" mul r4.xyz, r1.xyzz, c5.xyzz",
" mul r4.xyz, r1.xyzz, c[0 + aL].xyzz",
" mul r4.xyz, r1.xyzz, c[6 + aL].xyzz",
" mul r4.xyz, r1.xyzz, c[0 + a0].xyzz",
" mul r4.xyz, r1.xyzz, c[8 + a0].xyzz",
" + adds r5.w, r0.xz",
" cos r6.w, r0.x",
" adds r5.w, r0.zx",
" jmp l5",
"ccall b1, l5",
"nop",
" label l5",
"(!p0) exec",
"cexec b5, Yield=true",
"cexec !b6",
" mulsc r3.w, c1.z, r1.w",
"loop i7, L4",
" label L3",
" exec",
" setp_eq r15, c[aL].w",
" (!p0) add r0, r0, c[aL]",
"(p0) endloop i7, L3",
"label L4",
"exece",
" mulsc r3.w, c3.z, r6.x",
" mulsc r3.w, c200.z, r31.x",
" mov oDepth.x, c3.w",
" cnop",
});
}
class NopIncludeHandler : CompilerIncludeHandler {
@ -46,7 +97,7 @@ namespace shader_playground {
}
}
void Assemble(string shaderSourceCode) {
void Process(string shaderSourceCode) {
shaderSourceCode += "\ncnop";
shaderSourceCode += "\ncnop";
var preprocessorDefines = new CompilerMacro[2];
@ -58,45 +109,171 @@ namespace shader_playground {
shaderSourceCode, preprocessorDefines, includeHandler, options,
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
DumpWords(compiledShader.GetShaderCode());
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
disassembledSourceCode = disassembledSourceCode.Replace("\n", "\r\n");
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
outputTextBox.Text = disassembledSourceCode;
return;
}
var prefix = disassembledSourceCode.Substring(
0, disassembledSourceCode.IndexOf(':'));
disassembledSourceCode =
disassembledSourceCode.Replace(prefix + ": warning X7102: ", "");
disassembledSourceCode = disassembledSourceCode.Replace(
"// PDB hint 00000000-00000000-00000000\r\n", "");
var firstLine = disassembledSourceCode.IndexOf("//");
disassembledSourceCode = disassembledSourceCode.Substring(firstLine);
disassembledSourceCode = disassembledSourceCode.Trim();
outputTextBox.Text = disassembledSourceCode;
}
void DumpWords(byte[] shaderCode) {
if (shaderCode == null || shaderCode.Length == 0) {
compilerUcodeTextBox.Text = "";
wordsTextBox.Text = "";
return;
}
var prefix = disassembledSourceCode.Substring(
0, disassembledSourceCode.IndexOf(
':', disassembledSourceCode.IndexOf(':') + 1));
disassembledSourceCode =
disassembledSourceCode.Replace(prefix + ": ", "");
disassembledSourceCode = disassembledSourceCode.Replace(
"// PDB hint 00000000-00000000-00000000\r\n", "");
var firstLine = disassembledSourceCode.IndexOf("//");
var warnings = "// " +
disassembledSourceCode.Substring(0, firstLine)
.Replace("\r\n", "\r\n// ");
disassembledSourceCode =
warnings + disassembledSourceCode.Substring(firstLine + 3);
disassembledSourceCode = disassembledSourceCode.Trim();
outputTextBox.Text = disassembledSourceCode;
uint[] swappedCode = new uint[shaderCode.Length / sizeof(uint)];
Buffer.BlockCopy(shaderCode, 0, swappedCode, 0, shaderCode.Length);
string shaderType =
shaderSourceCode.IndexOf("xvs_") == -1 ? "ps" : "vs";
var ucodeWords = ExtractAndDumpWords(shaderType, compiledShader.GetShaderCode());
if (ucodeWords != null) {
TryCompiler(shaderType, ucodeWords);
} else {
compilerUcodeTextBox.Text = "";
}
if (compilerUcodeTextBox.Text.Length > 0) {
var sourcePrefix = disassembledSourceCode.Substring(0, disassembledSourceCode.IndexOf("/*"));
TryRoundTrip(sourcePrefix, compilerUcodeTextBox.Text, compiledShader.GetShaderCode());
}
}
void TryCompiler(string shaderType, uint[] ucodeWords) {
string ucodePath = Path.Combine(Path.GetTempPath(), "shader_playground_ucode.bin." + shaderType);
string ucodeDisasmPath = Path.Combine(Path.GetTempPath(), "shader_playground_disasm.ucode.txt");
string spirvDisasmPath = Path.Combine(Path.GetTempPath(), "shader_playground_disasm.spirv.txt");
if (File.Exists(ucodePath)) {
File.Delete(ucodePath);
}
if (File.Exists(ucodeDisasmPath)) {
File.Delete(ucodeDisasmPath);
}
if (File.Exists(spirvDisasmPath)) {
File.Delete(spirvDisasmPath);
}
byte[] ucodeBytes = new byte[ucodeWords.Length * 4];
Buffer.BlockCopy(ucodeWords, 0, ucodeBytes, 0, ucodeWords.Length * 4);
File.WriteAllBytes(ucodePath, ucodeBytes);
if (!File.Exists(compilerPath_)) {
compilerUcodeTextBox.Text = "Compiler not found: " + compilerPath_;
return;
}
var startInfo = new ProcessStartInfo(compilerPath_);
startInfo.Arguments = string.Join(" ", new string[]{
"--shader_input=" + ucodePath,
"--shader_input_type=" + shaderType,
"--shader_output=" + ucodeDisasmPath,
"--shader_output_type=ucode",
});
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
try {
using (var process = System.Diagnostics.Process.Start(startInfo)) {
process.WaitForExit();
}
string disasmText = File.ReadAllText(ucodeDisasmPath);
compilerUcodeTextBox.Text = disasmText;
} catch {
compilerUcodeTextBox.Text = "COMPILER FAILURE";
}
startInfo = new ProcessStartInfo(compilerPath_);
startInfo.Arguments = string.Join(" ", new string[]{
"--shader_input=" + ucodePath,
"--shader_input_type=" + shaderType,
"--shader_output=" + spirvDisasmPath,
"--shader_output_type=spirvtext",
});
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
try {
using (var process = System.Diagnostics.Process.Start(startInfo)) {
process.WaitForExit();
}
string disasmText = File.ReadAllText(spirvDisasmPath);
compilerTranslatedTextBox.Text = disasmText;
} catch {
compilerTranslatedTextBox.Text = "COMPILER FAILURE";
}
}
void TryRoundTrip(string sourcePrefix, string compilerSource, byte[] expectedBytes) {
var shaderSourceCode = sourcePrefix + compilerSource;
var preprocessorDefines = new CompilerMacro[2];
preprocessorDefines[0].Name = "XBOX";
preprocessorDefines[0].Name = "XBOX360";
var includeHandler = new NopIncludeHandler();
var options = CompilerOptions.None;
var compiledShader = ShaderCompiler.AssembleFromSource(
shaderSourceCode, preprocessorDefines, includeHandler, options,
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
var compiledBytes = compiledShader.GetShaderCode();
if (compiledBytes == null ||
compiledBytes.Length != expectedBytes.Length ||
!MemCmp(compiledBytes, expectedBytes)) {
compilerUcodeTextBox.BackColor = System.Drawing.Color.Red;
} else {
compilerUcodeTextBox.BackColor = System.Drawing.SystemColors.Control;
}
}
bool MemCmp(byte[] a1, byte[] b1) {
if (a1 == null || b1 == null) {
return false;
}
int length = a1.Length;
if (b1.Length != length) {
return false;
}
while (length > 0) {
length--;
if (a1[length] != b1[length]) {
return false;
}
}
return true;
}
uint[] ExtractAndDumpWords(string shaderType, byte[] shaderCode) {
if (shaderCode == null || shaderCode.Length == 0) {
wordsTextBox.Text = "";
return null;
}
// Find shader code.
int byteOffset = (shaderCode[4] << 24) | (shaderCode[5] << 16) |
(shaderCode[6] << 8) | (shaderCode[7] << 0);
int wordOffset = byteOffset / 4;
uint[] swappedCode = new uint[(shaderCode.Length - wordOffset) / sizeof(uint)];
Buffer.BlockCopy(shaderCode, wordOffset * 4, swappedCode, 0, shaderCode.Length - wordOffset * 4);
for (int i = 0; i < swappedCode.Length; ++i) {
swappedCode[i] = SwapBytes(swappedCode[i]);
}
var sb = new StringBuilder();
sb.Append("const uint32_t shader_words[] = {");
sb.Append("const uint32_t shader_dwords[] = {");
for (int i = 0; i < swappedCode.Length; ++i) {
sb.AppendFormat("0x{0:X8}, ", swappedCode[i]);
}
sb.Append("};");
sb.Append("};\r\n");
sb.Append("shader_type = ShaderType::" + (shaderType == "vs" ? "kVertex" : "kPixel") + ";\r\n");
wordsTextBox.Text = sb.ToString();
wordsTextBox.SelectAll();
return swappedCode;
}
uint SwapBytes(uint x) {
@ -105,6 +282,5 @@ namespace shader_playground {
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24);
}
}
}

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@ -117,4 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
</root>