This commit is contained in:
Bill Hollings 2016-04-11 13:35:14 -04:00
commit 6236cc79f0
5 changed files with 88 additions and 19 deletions

View File

@ -1,27 +1,37 @@
TARGET := spirv-cross
SOURCES := $(wildcard *.cpp)
SOURCES := $(wildcard spirv_*.cpp)
CLI_SOURCES := main.cpp
OBJECTS := $(SOURCES:.cpp=.o)
DEPS := $(OBJECTS:.o=.d)
CLI_OBJECTS := $(CLI_SOURCES:.cpp=.o)
STATIC_LIB := lib$(TARGET).a
DEPS := $(OBJECTS:.o=.d) $(CLI_OBJECTS:.o=.d)
CXXFLAGS += -std=c++11 -Wall -Wextra
ifeq ($(DEBUG), 1)
CXXFLAGS += -O0 -gdwarf-2
CXXFLAGS += -O0
else
CXXFLAGS += -O2 -gdwarf-2
CXXFLAGS += -O2
endif
all: $(TARGET)
-include $(DEPS)
$(TARGET): $(OBJECTS)
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)
$(TARGET): $(CLI_OBJECTS) $(STATIC_LIB)
$(CXX) -o $@ $(CLI_OBJECTS) $(STATIC_LIB) $(LDFLAGS)
$(STATIC_LIB): $(OBJECTS)
$(AR) rcs $@ $(OBJECTS)
%.o: %.cpp
$(CXX) -c -o $@ $< $(CXXFLAGS) -MMD
clean:
rm -f $(TARGET) $(OBJECTS) $(DEPS)
rm -f $(TARGET) $(OBJECTS) $(CLI_OBJECTS) $(STATIC_LIB) $(DEPS)
.PHONY: clean

View File

@ -33,6 +33,59 @@ MinGW-w64 based compilation works with `make`, and an MSVC 2013 solution is also
## Usage
### Using the C++ API
To perform reflection and convert to other shader languages you can use the SPIRV-Cross API.
For example:
```
#include "spirv_glsl.hpp"
#include <vector>
#include <utility>
extern std::vector<uint32_t> load_spirv_file();
int main()
{
// Read SPIR-V from disk or similar.
std::vector<uint32_t> spirv_binary = load_spirv_file();
spirv_cross::CompilerGLSL glsl(std::move(spirv_binary));
// The SPIR-V is now parsed, and we can perform reflection on it.
spirv_cross::ShaderResources resources = glsl.get_shader_resources();
// Get all sampled images in the shader.
for (auto &resource : resources.sampled_images)
{
unsigned set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet);
unsigned binding = glsl.get_decoration(resource.id, spv::DecorationBinding);
printf("Image %s at set = %u, binding = %u\n", resource.name.c_str(), set, binding);
// Modify the decoration to prepare it for GLSL.
glsl.unset_decoration(resource.id, spv::DecorationDescriptorSet);
// Some arbitrary remapping if we want.
glsl.set_decoration(resource.id, spv::DecorationBinding, set * 16 + binding);
}
// Set some options.
spirv_cross::CompilerGLSL::Options options;
options.version = 310;
options.es = true;
glsl.set_options(options);
// Compile to GLSL, ready to give to GL driver.
std::string source = glsl.compile();
}
```
#### Integrating SPIRV-Cross in a custom build system
To add SPIRV-Cross to your own codebase, just copy the source and header files from root directory
and build the relevant .cpp files you need. Make sure to build with C++11 support, e.g. `-std=c++11` in GCC and Clang.
Alternatively, the Makefile generates a libspirv-cross.a static library during build that can be linked in.
### Creating a SPIR-V file from GLSL with glslang
```

View File

@ -60,7 +60,7 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
{
for (auto &i : block.ops)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
switch (op)
@ -119,7 +119,7 @@ void Compiler::register_global_read_dependencies(const SPIRBlock &block, uint32_
{
for (auto &i : block.ops)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
switch (op)
@ -458,11 +458,11 @@ static string extract_string(const vector<uint32_t> &spirv, uint32_t offset)
void Compiler::parse()
{
auto len = spirv.size();
auto s = stream(0);
if (len < 5)
throw CompilerError("SPIRV file too small.");
auto s = spirv.data();
// Endian-swap if we need to.
if (s[0] == swap_endian(MagicNumber))
transform(begin(spirv), end(spirv), begin(spirv), [](uint32_t c) { return swap_endian(c); });
@ -793,7 +793,7 @@ void Compiler::unset_decoration(uint32_t id, Decoration decoration)
void Compiler::parse(const Instruction &i)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
uint32_t length = i.length;
@ -1666,7 +1666,7 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand
// inside dead blocks ...
for (auto &i : block.ops)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
if (!handler.handle(op, ops, i.length))

View File

@ -173,11 +173,17 @@ namespace spirv_cross
ShaderResources get_shader_resources() const;
protected:
const uint32_t* stream(uint32_t offset) const
const uint32_t* stream(const Instruction &instr) const
{
if (offset > spirv.size())
// If we're not going to use any arguments, just return nullptr.
// We want to avoid case where we return an out of range pointer
// that trips debug assertions on some platforms.
if (!instr.length)
return nullptr;
if (instr.offset + instr.length > spirv.size())
throw CompilerError("Compiler::stream() out of range.");
return &spirv[offset];
return &spirv[instr.offset];
}
std::vector<uint32_t> spirv;

View File

@ -1353,7 +1353,7 @@ void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id,
void CompilerGLSL::emit_texture_op(const Instruction &i)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
uint32_t length = i.length;
@ -2274,7 +2274,7 @@ string CompilerGLSL::build_composite_combiner(const uint32_t *elems, uint32_t le
void CompilerGLSL::emit_instruction(const Instruction &i)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
uint32_t length = i.length;
@ -3615,7 +3615,7 @@ void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
auto &b = get<SPIRBlock>(block);
for (auto &i : b.ops)
{
auto ops = stream(i.offset);
auto ops = stream(i);
auto op = static_cast<Op>(i.op);
if (op == OpFunctionCall)