First pass ShaderTranslator base type, able to disasm in msft style.
This commit is contained in:
parent
bea8870700
commit
65130edaa1
|
@ -83,4 +83,10 @@ std::string StringBuffer::to_string() {
|
||||||
|
|
||||||
char* StringBuffer::ToString() { return strdup(buffer_); }
|
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
|
} // namespace xe
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ class StringBuffer {
|
||||||
const char* GetString() const;
|
const char* GetString() const;
|
||||||
std::string to_string();
|
std::string to_string();
|
||||||
char* ToString();
|
char* ToString();
|
||||||
|
std::vector<uint8_t> ToBytes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Grow(size_t additional_length);
|
void Grow(size_t additional_length);
|
||||||
|
|
|
@ -18,68 +18,83 @@
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/gpu/shader_translator.h"
|
#include "xenia/gpu/shader_translator.h"
|
||||||
|
|
||||||
DEFINE_string(input_shader, "", "Input shader binary file path.");
|
DEFINE_string(shader_input, "", "Input shader binary file path.");
|
||||||
DEFINE_string(
|
DEFINE_string(shader_input_type, "",
|
||||||
shader_type, "",
|
"'vs', 'ps', or unspecified to infer from the given filename.");
|
||||||
"'vert', 'frag', 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 xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
int shader_compiler_main(const std::vector<std::wstring>& args) {
|
int shader_compiler_main(const std::vector<std::wstring>& args) {
|
||||||
ShaderType shader_type;
|
ShaderType shader_type;
|
||||||
if (!FLAGS_shader_type.empty()) {
|
if (!FLAGS_shader_input_type.empty()) {
|
||||||
if (FLAGS_shader_type == "vert") {
|
if (FLAGS_shader_input_type == "vs") {
|
||||||
shader_type = ShaderType::kVertex;
|
shader_type = ShaderType::kVertex;
|
||||||
} else if (FLAGS_shader_type == "frag") {
|
} else if (FLAGS_shader_input_type == "ps") {
|
||||||
shader_type = ShaderType::kPixel;
|
shader_type = ShaderType::kPixel;
|
||||||
} else {
|
} else {
|
||||||
XELOGE("Invalid --shader_type; must be 'vert' or 'frag'.");
|
XELOGE("Invalid --shader_input_type; must be 'vs' or 'ps'.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto last_dot = FLAGS_input_shader.find_last_of('.');
|
auto last_dot = FLAGS_shader_input.find_last_of('.');
|
||||||
bool valid_type = false;
|
bool valid_type = false;
|
||||||
if (last_dot != std::string::npos) {
|
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;
|
shader_type = ShaderType::kVertex;
|
||||||
valid_type = true;
|
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;
|
shader_type = ShaderType::kPixel;
|
||||||
valid_type = true;
|
valid_type = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!valid_type) {
|
if (!valid_type) {
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"File type not recognized (use .vert, .frag or "
|
"File type not recognized (use .vs, .ps or "
|
||||||
"--shader_type=vert|frag).");
|
"--shader_input_type=vs|ps).");
|
||||||
return 1;
|
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) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
fseek(input_file, 0, SEEK_END);
|
fseek(input_file, 0, SEEK_END);
|
||||||
size_t input_file_size = ftell(input_file);
|
size_t input_file_size = ftell(input_file);
|
||||||
fseek(input_file, 0, SEEK_SET);
|
fseek(input_file, 0, SEEK_SET);
|
||||||
std::vector<uint32_t> ucode_words(input_file_size / 4);
|
std::vector<uint32_t> ucode_dwords(input_file_size / 4);
|
||||||
fread(ucode_words.data(), 4, ucode_words.size(), input_file);
|
fread(ucode_dwords.data(), 4, ucode_dwords.size(), input_file);
|
||||||
fclose(input_file);
|
fclose(input_file);
|
||||||
|
|
||||||
XELOGI("Opened %s as a %s shader, %" PRId64 " words (%" PRId64 " bytes).",
|
XELOGI("Opened %s as a %s shader, %" PRId64 " words (%" PRId64 " bytes).",
|
||||||
FLAGS_input_shader.c_str(),
|
FLAGS_shader_input.c_str(),
|
||||||
shader_type == ShaderType::kVertex ? "vertex" : "fragment",
|
shader_type == ShaderType::kVertex ? "vertex" : "pixel",
|
||||||
ucode_words.size(), ucode_words.size() * 4);
|
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.
|
// TODO(benvanik): hash? need to return the data to big-endian format first.
|
||||||
uint64_t ucode_data_hash = 0;
|
uint64_t ucode_data_hash = 0;
|
||||||
auto translated_shader = translator.Translate(
|
auto translated_shader = translator->Translate(
|
||||||
shader_type, ucode_data_hash, ucode_words.data(), ucode_words.size());
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,44 +11,316 @@
|
||||||
#define XENIA_GPU_SHADER_TRANSLATOR_H_
|
#define XENIA_GPU_SHADER_TRANSLATOR_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/string_buffer.h"
|
||||||
|
#include "xenia/gpu/ucode.h"
|
||||||
#include "xenia/gpu/xenos.h"
|
#include "xenia/gpu/xenos.h"
|
||||||
#include "xenia/ui/spirv/spirv_util.h"
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
class TranslatedShader {
|
class TranslatedShader {
|
||||||
public:
|
public:
|
||||||
TranslatedShader(ShaderType shader_type, uint64_t ucode_data_hash,
|
struct Error {
|
||||||
const uint32_t* ucode_words, size_t ucode_word_count);
|
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();
|
~TranslatedShader();
|
||||||
|
|
||||||
ShaderType type() const { return shader_type_; }
|
ShaderType type() const { return shader_type_; }
|
||||||
const uint32_t* ucode_words() const { return ucode_data_.data(); }
|
const std::vector<uint32_t>& ucode_data() const { return ucode_data_; }
|
||||||
size_t ucode_word_count() const { return ucode_data_.size(); }
|
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_; }
|
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:
|
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_;
|
ShaderType shader_type_;
|
||||||
std::vector<uint32_t> ucode_data_;
|
std::vector<uint32_t> ucode_data_;
|
||||||
uint64_t ucode_data_hash_;
|
uint64_t ucode_data_hash_;
|
||||||
|
|
||||||
|
std::vector<VertexBinding> vertex_bindings_;
|
||||||
|
std::vector<TextureBinding> texture_bindings_;
|
||||||
|
|
||||||
bool is_valid_ = false;
|
bool is_valid_ = false;
|
||||||
|
std::vector<Error> errors_;
|
||||||
|
|
||||||
|
std::vector<uint8_t> binary_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderTranslator {
|
class ShaderTranslator {
|
||||||
public:
|
public:
|
||||||
ShaderTranslator();
|
virtual ~ShaderTranslator();
|
||||||
|
|
||||||
std::unique_ptr<TranslatedShader> Translate(ShaderType shader_type,
|
std::unique_ptr<TranslatedShader> Translate(ShaderType shader_type,
|
||||||
uint64_t ucode_data_hash,
|
uint64_t ucode_data_hash,
|
||||||
const uint32_t* ucode_words,
|
const uint32_t* ucode_dwords,
|
||||||
size_t ucode_word_count);
|
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:
|
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
|
} // namespace gpu
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1151,6 +1151,17 @@ Id SpirvEmitter::CreateExtendedInstructionCall(spv::Decoration precision,
|
||||||
return instr->result_id();
|
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.
|
// Accept all parameters needed to create a texture instruction.
|
||||||
// Create the correct instruction based on the inputs, and make the call.
|
// Create the correct instruction based on the inputs, and make the call.
|
||||||
Id SpirvEmitter::CreateTextureCall(spv::Decoration precision, Id result_type,
|
Id SpirvEmitter::CreateTextureCall(spv::Decoration precision, Id result_type,
|
||||||
|
|
|
@ -373,6 +373,10 @@ class SpirvEmitter {
|
||||||
Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type,
|
Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type,
|
||||||
Id instruction_set, int instruction_ordinal,
|
Id instruction_set, int instruction_ordinal,
|
||||||
std::initializer_list<Id> args);
|
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
|
// List of parameters used to create a texture operation
|
||||||
struct TextureParameters {
|
struct TextureParameters {
|
||||||
|
@ -655,6 +659,7 @@ class SpirvEmitter {
|
||||||
Id unique_id_ = 0;
|
Id unique_id_ = 0;
|
||||||
Function* main_function_ = nullptr;
|
Function* main_function_ = nullptr;
|
||||||
AccessChain access_chain_;
|
AccessChain access_chain_;
|
||||||
|
Id glsl_std_450_instruction_set_ = 0;
|
||||||
|
|
||||||
// special blocks of instructions for output
|
// special blocks of instructions for output
|
||||||
std::vector<Instruction*> imports_;
|
std::vector<Instruction*> imports_;
|
||||||
|
|
|
@ -23,94 +23,175 @@
|
||||||
/// the contents of this method with the code editor.
|
/// the contents of this method with the code editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent() {
|
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.sourceCodeTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.outputTextBox = new System.Windows.Forms.TextBox();
|
this.outputTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
this.compilerUcodeTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.wordsTextBox = new System.Windows.Forms.TextBox();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.splitContainer1.Panel1.SuspendLayout();
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
this.splitContainer1.Panel2.SuspendLayout();
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
this.splitContainer1.SuspendLayout();
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.compilerTranslatedTextBox = new System.Windows.Forms.TextBox();
|
||||||
|
this.tableLayoutPanel1.SuspendLayout();
|
||||||
this.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
|
// wordsTextBox
|
||||||
//
|
//
|
||||||
this.wordsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.wordsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| 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.Multiline = true;
|
||||||
this.wordsTextBox.Name = "wordsTextBox";
|
this.wordsTextBox.Name = "wordsTextBox";
|
||||||
this.wordsTextBox.ReadOnly = true;
|
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;
|
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
|
// Editor
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
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.wordsTextBox);
|
||||||
this.Controls.Add(this.splitContainer1);
|
|
||||||
this.Name = "Editor";
|
this.Name = "Editor";
|
||||||
this.Text = "Shader Playground";
|
this.Text = "Shader Playground";
|
||||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
this.tableLayoutPanel1.ResumeLayout(false);
|
||||||
this.splitContainer1.Panel1.PerformLayout();
|
this.tableLayoutPanel1.PerformLayout();
|
||||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
|
||||||
this.splitContainer1.Panel2.PerformLayout();
|
|
||||||
this.splitContainer1.ResumeLayout(false);
|
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
this.PerformLayout();
|
this.PerformLayout();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
private System.Windows.Forms.TextBox wordsTextBox;
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||||
private System.Windows.Forms.TextBox sourceCodeTextBox;
|
private System.Windows.Forms.TextBox sourceCodeTextBox;
|
||||||
private System.Windows.Forms.TextBox outputTextBox;
|
private System.Windows.Forms.TextBox outputTextBox;
|
||||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
private System.Windows.Forms.TextBox compilerUcodeTextBox;
|
||||||
private System.Windows.Forms.TextBox wordsTextBox;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -9,34 +10,84 @@ using System.Windows.Forms;
|
||||||
|
|
||||||
namespace shader_playground {
|
namespace shader_playground {
|
||||||
public partial class Editor : Form {
|
public partial class Editor : Form {
|
||||||
|
string compilerPath_ = @"..\..\..\..\..\build\bin\Windows\Debug\xenia-gpu-shader-compiler.exe";
|
||||||
|
|
||||||
|
FileSystemWatcher compilerWatcher_;
|
||||||
|
|
||||||
public Editor() {
|
public Editor() {
|
||||||
InitializeComponent();
|
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(
|
sourceCodeTextBox.Text = string.Join(
|
||||||
"\r\n", new string[] {
|
"\r\n", new string[] {
|
||||||
"xps_3_0",
|
"xps_3_0",
|
||||||
"dcl_texcoord1 r0",
|
"dcl_texcoord1 r0",
|
||||||
"dcl_color r1.xy",
|
"dcl_color r1.xy",
|
||||||
"exec",
|
"exec",
|
||||||
"alloc colors",
|
"alloc colors",
|
||||||
"exece",
|
"exec",
|
||||||
"mad oC0, r0, r1.y, c0",
|
"tfetch1D r2, r0.y, tf0, FetchValidOnly=false",
|
||||||
"mul r4.xyz, r1.xyz, c0.xyz",
|
"tfetch1D r2, r0.x, tf2",
|
||||||
"+ adds r5.w, r0.xy",
|
"tfetch2D r3, r3.wx, tf13",
|
||||||
"cnop",
|
"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",
|
||||||
private void WordsTextBox_Click(object sender, EventArgs e) {
|
" setGradientH r1.zyx",
|
||||||
wordsTextBox.SelectAll();
|
"(!p0) setGradientV r1.zyx",
|
||||||
wordsTextBox.Copy();
|
" getGradients r5, r1.xy, tf3",
|
||||||
}
|
" mad oC0, r0, r1.yyyy, c0",
|
||||||
|
" mul r4.xyz, r1.xyzz, c5.xyzz",
|
||||||
void SourceCodeTextBox_TextChanged(object sender, EventArgs e) {
|
" mul r4.xyz, r1.xyzz, c[0 + aL].xyzz",
|
||||||
Assemble(sourceCodeTextBox.Text);
|
" 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 {
|
class NopIncludeHandler : CompilerIncludeHandler {
|
||||||
|
@ -46,7 +97,7 @@ namespace shader_playground {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assemble(string shaderSourceCode) {
|
void Process(string shaderSourceCode) {
|
||||||
shaderSourceCode += "\ncnop";
|
shaderSourceCode += "\ncnop";
|
||||||
shaderSourceCode += "\ncnop";
|
shaderSourceCode += "\ncnop";
|
||||||
var preprocessorDefines = new CompilerMacro[2];
|
var preprocessorDefines = new CompilerMacro[2];
|
||||||
|
@ -58,45 +109,171 @@ namespace shader_playground {
|
||||||
shaderSourceCode, preprocessorDefines, includeHandler, options,
|
shaderSourceCode, preprocessorDefines, includeHandler, options,
|
||||||
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
|
Microsoft.Xna.Framework.TargetPlatform.Xbox360);
|
||||||
|
|
||||||
DumpWords(compiledShader.GetShaderCode());
|
|
||||||
|
|
||||||
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
|
var disassembledSourceCode = compiledShader.ErrorsAndWarnings;
|
||||||
disassembledSourceCode = disassembledSourceCode.Replace("\n", "\r\n");
|
disassembledSourceCode = disassembledSourceCode.Replace("\n", "\r\n");
|
||||||
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
|
if (disassembledSourceCode.IndexOf("// PDB hint 00000000-00000000-00000000") == -1) {
|
||||||
outputTextBox.Text = disassembledSourceCode;
|
outputTextBox.Text = disassembledSourceCode;
|
||||||
return;
|
compilerUcodeTextBox.Text = "";
|
||||||
}
|
|
||||||
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) {
|
|
||||||
wordsTextBox.Text = "";
|
wordsTextBox.Text = "";
|
||||||
return;
|
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)];
|
string shaderType =
|
||||||
Buffer.BlockCopy(shaderCode, 0, swappedCode, 0, shaderCode.Length);
|
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) {
|
for (int i = 0; i < swappedCode.Length; ++i) {
|
||||||
swappedCode[i] = SwapBytes(swappedCode[i]);
|
swappedCode[i] = SwapBytes(swappedCode[i]);
|
||||||
}
|
}
|
||||||
var sb = new StringBuilder();
|
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) {
|
for (int i = 0; i < swappedCode.Length; ++i) {
|
||||||
sb.AppendFormat("0x{0:X8}, ", swappedCode[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.Text = sb.ToString();
|
||||||
wordsTextBox.SelectAll();
|
wordsTextBox.SelectAll();
|
||||||
|
|
||||||
|
return swappedCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint SwapBytes(uint x) {
|
uint SwapBytes(uint x) {
|
||||||
|
@ -105,6 +282,5 @@ namespace shader_playground {
|
||||||
((x & 0x00ff0000) >> 8) +
|
((x & 0x00ff0000) >> 8) +
|
||||||
((x & 0xff000000) >> 24);
|
((x & 0xff000000) >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</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>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
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
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
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
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
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
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
||||||
|
@ -117,4 +117,4 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
</root>
|
</root>
|
Loading…
Reference in New Issue