217 lines
6.1 KiB
C++
217 lines
6.1 KiB
C++
// Copyright (C) 2020 Jérôme Leclercq
|
|
// This file is part of the "Nazara Engine - Shader generator"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Shader/SpirvPrinter.hpp>
|
|
#include <Nazara/Core/CallOnExit.hpp>
|
|
#include <Nazara/Core/StackArray.hpp>
|
|
#include <Nazara/Shader/SpirvData.hpp>
|
|
#include <cassert>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <Nazara/Shader/Debug.hpp>
|
|
|
|
namespace Nz
|
|
{
|
|
struct SpirvPrinter::State
|
|
{
|
|
State(const Settings& s) :
|
|
settings(s)
|
|
{
|
|
}
|
|
|
|
std::size_t resultOffset;
|
|
std::ostringstream stream;
|
|
const Settings& settings;
|
|
};
|
|
|
|
std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count, const Settings& settings)
|
|
{
|
|
State state(settings);
|
|
|
|
m_currentState = &state;
|
|
CallOnExit resetOnExit([&] { m_currentState = nullptr; });
|
|
|
|
Decode(codepoints, count);
|
|
|
|
return m_currentState->stream.str();
|
|
}
|
|
|
|
bool SpirvPrinter::HandleHeader(const SpirvHeader& header)
|
|
{
|
|
UInt8 majorVersion = ((header.versionNumber) >> 16) & 0xFF;
|
|
UInt8 minorVersion = ((header.versionNumber) >> 8) & 0xFF;
|
|
|
|
m_currentState->resultOffset = std::snprintf(nullptr, 0, "%%%u = ", header.bound);
|
|
|
|
if (m_currentState->settings.printHeader)
|
|
{
|
|
m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n";
|
|
m_currentState->stream << "Generator: " << std::to_string(header.generatorId) << "\n";
|
|
m_currentState->stream << "Bound: " << std::to_string(header.bound) << "\n";
|
|
m_currentState->stream << "Schema: " << std::to_string(header.schema) << "\n";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SpirvPrinter::HandleOpcode(const SpirvInstruction& instruction, UInt32 wordCount)
|
|
{
|
|
const UInt32* startPtr = GetCurrentPtr();
|
|
|
|
if (m_currentState->settings.printParameters)
|
|
{
|
|
std::ostringstream instructionStream;
|
|
instructionStream << instruction.name;
|
|
|
|
UInt32 resultId = 0;
|
|
|
|
std::size_t currentOperand = 0;
|
|
const UInt32* endPtr = startPtr + wordCount - 1;
|
|
while (GetCurrentPtr() < endPtr)
|
|
{
|
|
const SpirvInstruction::Operand* operand = &instruction.operands[currentOperand];
|
|
|
|
if (operand->kind != SpirvOperandKind::IdResult)
|
|
{
|
|
switch (operand->kind)
|
|
{
|
|
case SpirvOperandKind::IdRef:
|
|
case SpirvOperandKind::IdResultType:
|
|
case SpirvOperandKind::IdMemorySemantics:
|
|
case SpirvOperandKind::IdScope:
|
|
{
|
|
UInt32 value = ReadWord();
|
|
instructionStream << " %" << value;
|
|
break;
|
|
}
|
|
|
|
case SpirvOperandKind::ImageOperands:
|
|
case SpirvOperandKind::FPFastMathMode:
|
|
case SpirvOperandKind::SelectionControl:
|
|
case SpirvOperandKind::LoopControl:
|
|
case SpirvOperandKind::FunctionControl:
|
|
case SpirvOperandKind::MemorySemantics:
|
|
case SpirvOperandKind::MemoryAccess:
|
|
case SpirvOperandKind::KernelProfilingInfo:
|
|
case SpirvOperandKind::RayFlags:
|
|
case SpirvOperandKind::SourceLanguage:
|
|
case SpirvOperandKind::ExecutionModel:
|
|
case SpirvOperandKind::AddressingModel:
|
|
case SpirvOperandKind::MemoryModel:
|
|
case SpirvOperandKind::ExecutionMode:
|
|
case SpirvOperandKind::StorageClass:
|
|
case SpirvOperandKind::Dim:
|
|
case SpirvOperandKind::SamplerAddressingMode:
|
|
case SpirvOperandKind::SamplerFilterMode:
|
|
case SpirvOperandKind::ImageFormat:
|
|
case SpirvOperandKind::ImageChannelOrder:
|
|
case SpirvOperandKind::ImageChannelDataType:
|
|
case SpirvOperandKind::FPRoundingMode:
|
|
case SpirvOperandKind::LinkageType:
|
|
case SpirvOperandKind::AccessQualifier:
|
|
case SpirvOperandKind::FunctionParameterAttribute:
|
|
case SpirvOperandKind::Decoration:
|
|
case SpirvOperandKind::BuiltIn:
|
|
case SpirvOperandKind::Scope:
|
|
case SpirvOperandKind::GroupOperation:
|
|
case SpirvOperandKind::KernelEnqueueFlags:
|
|
case SpirvOperandKind::Capability:
|
|
case SpirvOperandKind::RayQueryIntersection:
|
|
case SpirvOperandKind::RayQueryCommittedIntersectionType:
|
|
case SpirvOperandKind::RayQueryCandidateIntersectionType:
|
|
case SpirvOperandKind::LiteralInteger:
|
|
case SpirvOperandKind::LiteralExtInstInteger:
|
|
case SpirvOperandKind::LiteralSpecConstantOpInteger:
|
|
case SpirvOperandKind::LiteralContextDependentNumber: //< FIXME
|
|
{
|
|
UInt32 value = ReadWord();
|
|
instructionStream << " " << operand->name << "(" << value << ")";
|
|
break;
|
|
}
|
|
|
|
case SpirvOperandKind::LiteralString:
|
|
{
|
|
std::string str = ReadString();
|
|
instructionStream << " \"" << str << "\"";
|
|
|
|
/*
|
|
std::size_t offset = GetOutputOffset();
|
|
|
|
std::size_t size4 = CountWord(str);
|
|
for (std::size_t i = 0; i < size4; ++i)
|
|
{
|
|
UInt32 codepoint = 0;
|
|
for (std::size_t j = 0; j < 4; ++j)
|
|
{
|
|
std::size_t pos = i * 4 + j;
|
|
if (pos < str.size())
|
|
codepoint |= UInt32(str[pos]) << (j * 8);
|
|
}
|
|
|
|
Append(codepoint);
|
|
}
|
|
*/
|
|
break;
|
|
}
|
|
|
|
|
|
case SpirvOperandKind::PairLiteralIntegerIdRef:
|
|
{
|
|
ReadWord();
|
|
ReadWord();
|
|
break;
|
|
}
|
|
|
|
case SpirvOperandKind::PairIdRefLiteralInteger:
|
|
{
|
|
ReadWord();
|
|
ReadWord();
|
|
break;
|
|
}
|
|
|
|
case SpirvOperandKind::PairIdRefIdRef:
|
|
{
|
|
ReadWord();
|
|
ReadWord();
|
|
break;
|
|
}
|
|
|
|
/*case SpirvOperandKind::LiteralContextDependentNumber:
|
|
{
|
|
throw std::runtime_error("not yet implemented");
|
|
}*/
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
resultId = ReadWord();
|
|
|
|
if (currentOperand < instruction.minOperandCount - 1)
|
|
currentOperand++;
|
|
}
|
|
|
|
if (resultId != 0)
|
|
{
|
|
std::string resultInfo = "%" + std::to_string(resultId) + " = ";
|
|
m_currentState->stream << std::setw(m_currentState->resultOffset) << resultInfo;
|
|
}
|
|
else
|
|
m_currentState->stream << std::string(m_currentState->resultOffset, ' ');
|
|
|
|
m_currentState->stream << instructionStream.str();
|
|
|
|
assert(GetCurrentPtr() == startPtr + wordCount - 1);
|
|
}
|
|
else
|
|
m_currentState->stream << instruction.name;
|
|
|
|
m_currentState->stream << "\n";
|
|
|
|
return true;
|
|
}
|
|
}
|