Assembler/disassembler via SPIRV-Tools.
This commit is contained in:
@@ -7,6 +7,7 @@ project("xenia-gpu-spirv")
|
||||
kind("StaticLib")
|
||||
language("C++")
|
||||
links({
|
||||
"spirv-tools",
|
||||
"xenia-base",
|
||||
"xenia-gpu",
|
||||
})
|
||||
@@ -14,6 +15,7 @@ project("xenia-gpu-spirv")
|
||||
})
|
||||
includedirs({
|
||||
project_root.."/build_tools/third_party/gflags/src",
|
||||
project_root.."/third_party/spirv-tools/external/include",
|
||||
})
|
||||
local_platform_files()
|
||||
|
||||
@@ -24,6 +26,7 @@ project("xenia-gpu-spirv-compiler")
|
||||
language("C++")
|
||||
links({
|
||||
"gflags",
|
||||
"spirv-tools",
|
||||
"xenia-base",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-spirv",
|
||||
|
||||
@@ -13,6 +13,16 @@
|
||||
#include "third_party/spirv/GLSL.std.450.h"
|
||||
#include "third_party/spirv/spirv.h"
|
||||
|
||||
// Forward declarations from SPIRV-Tools so we don't pollute /so/ much.
|
||||
struct spv_binary_t;
|
||||
typedef spv_binary_t* spv_binary;
|
||||
struct spv_context_t;
|
||||
typedef spv_context_t* spv_context;
|
||||
struct spv_diagnostic_t;
|
||||
typedef spv_diagnostic_t* spv_diagnostic;
|
||||
struct spv_text_t;
|
||||
typedef spv_text_t* spv_text;
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace spirv {
|
||||
|
||||
77
src/xenia/gpu/spirv/spv_assembler.cc
Normal file
77
src/xenia/gpu/spirv/spv_assembler.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/gpu/spirv/spv_assembler.h"
|
||||
|
||||
#include "third_party/spirv-tools/include/libspirv/libspirv.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace spirv {
|
||||
|
||||
SpvAssembler::Result::Result(spv_binary binary, spv_diagnostic diagnostic)
|
||||
: binary_(binary), diagnostic_(diagnostic) {}
|
||||
|
||||
SpvAssembler::Result::~Result() {
|
||||
if (binary_) {
|
||||
spvBinaryDestroy(binary_);
|
||||
}
|
||||
if (diagnostic_) {
|
||||
spvDiagnosticDestroy(diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
bool SpvAssembler::Result::has_error() const { return !!diagnostic_; }
|
||||
|
||||
size_t SpvAssembler::Result::error_source_line() const {
|
||||
return diagnostic_ ? diagnostic_->position.line : 0;
|
||||
}
|
||||
|
||||
size_t SpvAssembler::Result::error_source_column() const {
|
||||
return diagnostic_ ? diagnostic_->position.column : 0;
|
||||
}
|
||||
|
||||
const char* SpvAssembler::Result::error_string() const {
|
||||
return diagnostic_ ? diagnostic_->error : "";
|
||||
}
|
||||
|
||||
const uint32_t* SpvAssembler::Result::words() const {
|
||||
return binary_ ? binary_->code : nullptr;
|
||||
}
|
||||
|
||||
size_t SpvAssembler::Result::word_count() const {
|
||||
return binary_ ? binary_->wordCount : 0;
|
||||
}
|
||||
|
||||
SpvAssembler::SpvAssembler() : spv_context_(spvContextCreate()) {}
|
||||
|
||||
SpvAssembler::~SpvAssembler() { spvContextDestroy(spv_context_); }
|
||||
|
||||
std::unique_ptr<SpvAssembler::Result> SpvAssembler::Assemble(
|
||||
const char* source_text, size_t source_text_length) {
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
auto result_code = spvTextToBinary(spv_context_, source_text,
|
||||
source_text_length, &binary, &diagnostic);
|
||||
std::unique_ptr<Result> result(new Result(binary, diagnostic));
|
||||
if (result_code) {
|
||||
XELOGE("Failed to assemble spv: %d", result_code);
|
||||
if (result->has_error()) {
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
69
src/xenia/gpu/spirv/spv_assembler.h
Normal file
69
src/xenia/gpu/spirv/spv_assembler.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_GPU_SPIRV_SPV_ASSEMBLER_H_
|
||||
#define XENIA_GPU_SPIRV_SPV_ASSEMBLER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/gpu/spirv/spirv_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace spirv {
|
||||
|
||||
class SpvAssembler {
|
||||
public:
|
||||
class Result {
|
||||
public:
|
||||
Result(spv_binary binary, spv_diagnostic diagnostic);
|
||||
~Result();
|
||||
|
||||
// True if the result has an error associated with it.
|
||||
bool has_error() const;
|
||||
// Line of the error in the provided source text.
|
||||
size_t error_source_line() const;
|
||||
// Column of the error in the provided source text.
|
||||
size_t error_source_column() const;
|
||||
// Human-readable description of the error.
|
||||
const char* error_string() const;
|
||||
|
||||
// Assembled SPIRV binary.
|
||||
// Returned pointer lifetime is tied to this Result instance.
|
||||
const uint32_t* words() const;
|
||||
// Size of the SPIRV binary, in words.
|
||||
size_t word_count() const;
|
||||
|
||||
private:
|
||||
spv_binary binary_ = nullptr;
|
||||
spv_diagnostic diagnostic_ = nullptr;
|
||||
};
|
||||
|
||||
SpvAssembler();
|
||||
~SpvAssembler();
|
||||
|
||||
// Assembles the given source text into a SPIRV binary.
|
||||
// The return will be nullptr if assembly fails due to a library error.
|
||||
// The return may have an error set on it if the source text is malformed.
|
||||
std::unique_ptr<Result> Assemble(const char* source_text,
|
||||
size_t source_text_length);
|
||||
std::unique_ptr<Result> Assemble(const std::string& source_text) {
|
||||
return Assemble(source_text.c_str(), source_text.size());
|
||||
}
|
||||
|
||||
private:
|
||||
spv_context spv_context_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_GPU_SPIRV_SPV_ASSEMBLER_H_
|
||||
81
src/xenia/gpu/spirv/spv_disassembler.cc
Normal file
81
src/xenia/gpu/spirv/spv_disassembler.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/gpu/spirv/spv_disassembler.h"
|
||||
|
||||
#include "third_party/spirv-tools/include/libspirv/libspirv.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace spirv {
|
||||
|
||||
SpvDisassembler::Result::Result(spv_text text, spv_diagnostic diagnostic)
|
||||
: text_(text), diagnostic_(diagnostic) {}
|
||||
|
||||
SpvDisassembler::Result::~Result() {
|
||||
if (text_) {
|
||||
spvTextDestroy(text_);
|
||||
}
|
||||
if (diagnostic_) {
|
||||
spvDiagnosticDestroy(diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
bool SpvDisassembler::Result::has_error() const { return !!diagnostic_; }
|
||||
|
||||
size_t SpvDisassembler::Result::error_word_index() const {
|
||||
return diagnostic_ ? diagnostic_->position.index : 0;
|
||||
}
|
||||
|
||||
const char* SpvDisassembler::Result::error_string() const {
|
||||
return diagnostic_ ? diagnostic_->error : "";
|
||||
}
|
||||
|
||||
const char* SpvDisassembler::Result::text() const {
|
||||
return text_ ? text_->str : "";
|
||||
}
|
||||
|
||||
std::string SpvDisassembler::Result::to_string() const {
|
||||
return text_ ? std::string(text_->str, text_->length) : "";
|
||||
}
|
||||
|
||||
void SpvDisassembler::Result::AppendText(StringBuffer* target_buffer) const {
|
||||
if (text_) {
|
||||
target_buffer->AppendBytes(reinterpret_cast<const uint8_t*>(text_->str),
|
||||
text_->length);
|
||||
}
|
||||
}
|
||||
|
||||
SpvDisassembler::SpvDisassembler() : spv_context_(spvContextCreate()) {}
|
||||
|
||||
SpvDisassembler::~SpvDisassembler() { spvContextDestroy(spv_context_); }
|
||||
|
||||
std::unique_ptr<SpvDisassembler::Result> SpvDisassembler::Disassemble(
|
||||
const uint32_t* words, size_t word_count) {
|
||||
spv_text text = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
auto result_code =
|
||||
spvBinaryToText(spv_context_, words, word_count,
|
||||
SPV_BINARY_TO_TEXT_OPTION_INDENT, &text, &diagnostic);
|
||||
std::unique_ptr<Result> result(new Result(text, diagnostic));
|
||||
if (result_code) {
|
||||
XELOGE("Failed to disassemble spv: %d", result_code);
|
||||
if (result->has_error()) {
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
66
src/xenia/gpu/spirv/spv_disassembler.h
Normal file
66
src/xenia/gpu/spirv/spv_disassembler.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_GPU_SPIRV_SPV_DISASSEMBLER_H_
|
||||
#define XENIA_GPU_SPIRV_SPV_DISASSEMBLER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/gpu/spirv/spirv_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace spirv {
|
||||
|
||||
class SpvDisassembler {
|
||||
public:
|
||||
class Result {
|
||||
public:
|
||||
Result(spv_text text, spv_diagnostic diagnostic);
|
||||
~Result();
|
||||
|
||||
// True if the result has an error associated with it.
|
||||
bool has_error() const;
|
||||
// Index of the error in the provided binary word data.
|
||||
size_t error_word_index() const;
|
||||
// Human-readable description of the error.
|
||||
const char* error_string() const;
|
||||
|
||||
// Disassembled source text.
|
||||
// Returned pointer lifetime is tied to this Result instance.
|
||||
const char* text() const;
|
||||
// Converts the disassembled source text to a string.
|
||||
std::string to_string() const;
|
||||
// Appends the disassembled source text to the given buffer.
|
||||
void AppendText(StringBuffer* target_buffer) const;
|
||||
|
||||
private:
|
||||
spv_text text_ = nullptr;
|
||||
spv_diagnostic diagnostic_ = nullptr;
|
||||
};
|
||||
|
||||
SpvDisassembler();
|
||||
~SpvDisassembler();
|
||||
|
||||
// Disassembles the given SPIRV binary.
|
||||
// The return will be nullptr if disassembly fails due to a library error.
|
||||
// The return may have an error set on it if the SPIRV binary is malformed.
|
||||
std::unique_ptr<Result> Disassemble(const uint32_t* words, size_t word_count);
|
||||
|
||||
private:
|
||||
spv_context spv_context_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_GPU_SPIRV_SPV_DISASSEMBLER_H_
|
||||
Reference in New Issue
Block a user