2017-10-11 23:29:05 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <spirv/spirv.hpp>
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-10-18 09:50:30 +02:00
|
|
|
#include "spirv_instruction.h"
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief SPIR-V code buffer
|
|
|
|
*
|
|
|
|
* Helper class for generating SPIR-V shaders.
|
|
|
|
* Stores arbitrary SPIR-V instructions in a
|
|
|
|
* format that can be read by Vulkan drivers.
|
|
|
|
*/
|
2017-10-18 10:36:47 +02:00
|
|
|
class SpirvCodeBuffer {
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-10-18 10:36:47 +02:00
|
|
|
SpirvCodeBuffer();
|
2019-04-04 02:46:41 +02:00
|
|
|
explicit SpirvCodeBuffer(uint32_t size);
|
2017-11-20 15:35:29 +01:00
|
|
|
SpirvCodeBuffer(uint32_t size, const uint32_t* data);
|
2018-03-23 18:17:16 +01:00
|
|
|
SpirvCodeBuffer(std::istream& stream);
|
2018-01-13 03:53:33 +01:00
|
|
|
|
|
|
|
template<size_t N>
|
|
|
|
SpirvCodeBuffer(const uint32_t (&data)[N])
|
|
|
|
: SpirvCodeBuffer(N, data) { }
|
|
|
|
|
2017-10-18 10:36:47 +02:00
|
|
|
~SpirvCodeBuffer();
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
/**
|
2017-10-14 23:52:47 +02:00
|
|
|
* \brief Code data
|
|
|
|
* \returns Code data
|
2017-10-11 23:29:05 +02:00
|
|
|
*/
|
2018-04-10 12:48:24 +02:00
|
|
|
const uint32_t* data() const { return m_code.data(); }
|
|
|
|
uint32_t* data() { return m_code.data(); }
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2019-04-04 02:46:41 +02:00
|
|
|
/**
|
|
|
|
* \brief Code size, in dwords
|
|
|
|
* \returns Code size, in dwords
|
|
|
|
*/
|
|
|
|
uint32_t dwords() const {
|
|
|
|
return m_code.size();
|
|
|
|
}
|
|
|
|
|
2017-10-11 23:29:05 +02:00
|
|
|
/**
|
|
|
|
* \brief Code size, in bytes
|
|
|
|
* \returns Code size, in bytes
|
|
|
|
*/
|
|
|
|
size_t size() const {
|
2017-10-15 17:56:06 +02:00
|
|
|
return m_code.size() * sizeof(uint32_t);
|
2017-10-11 23:29:05 +02:00
|
|
|
}
|
|
|
|
|
2017-10-17 13:02:57 +02:00
|
|
|
/**
|
|
|
|
* \brief Begin instruction iterator
|
|
|
|
*
|
|
|
|
* Points to the first instruction in the instruction
|
|
|
|
* block. The header, if any, will be skipped over.
|
|
|
|
* \returns Instruction iterator
|
|
|
|
*/
|
2017-12-08 22:30:41 +01:00
|
|
|
SpirvInstructionIterator begin() {
|
2018-04-10 12:48:24 +02:00
|
|
|
return SpirvInstructionIterator(
|
|
|
|
m_code.data(), 0, m_code.size());
|
2017-10-17 13:02:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief End instruction iterator
|
|
|
|
*
|
|
|
|
* Points to the end of the instruction block.
|
|
|
|
* \returns Instruction iterator
|
|
|
|
*/
|
2017-12-08 22:30:41 +01:00
|
|
|
SpirvInstructionIterator end() {
|
2018-04-10 12:48:24 +02:00
|
|
|
return SpirvInstructionIterator(nullptr, 0, 0);
|
2017-10-17 13:02:57 +02:00
|
|
|
}
|
|
|
|
|
2019-11-19 12:12:05 +01:00
|
|
|
/**
|
|
|
|
* \brief Allocates a new ID
|
|
|
|
*
|
|
|
|
* Returns a new valid ID and increments the
|
|
|
|
* maximum ID count stored in the header.
|
|
|
|
* \returns The new SPIR-V ID
|
|
|
|
*/
|
|
|
|
uint32_t allocId();
|
|
|
|
|
2017-10-11 23:29:05 +02:00
|
|
|
/**
|
|
|
|
* \brief Merges two code buffers
|
|
|
|
*
|
|
|
|
* This is useful to generate declarations or
|
|
|
|
* the SPIR-V header at the same time as the
|
|
|
|
* code when doing so in advance is impossible.
|
|
|
|
* \param [in] other Code buffer to append
|
|
|
|
*/
|
2017-10-18 10:36:47 +02:00
|
|
|
void append(const SpirvCodeBuffer& other);
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends an 32-bit word to the buffer
|
|
|
|
* \param [in] word The word to append
|
|
|
|
*/
|
|
|
|
void putWord(uint32_t word);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends an instruction word to the buffer
|
|
|
|
*
|
|
|
|
* Adds a single word containing both the word count
|
|
|
|
* and the op code number for a single instruction.
|
|
|
|
* \param [in] opCode Operand code
|
|
|
|
* \param [in] wordCount Number of words
|
|
|
|
*/
|
|
|
|
void putIns(spv::Op opCode, uint16_t wordCount);
|
2019-11-19 12:12:05 +01:00
|
|
|
|
2017-10-11 23:29:05 +02:00
|
|
|
/**
|
|
|
|
* \brief Appends a 32-bit integer to the buffer
|
|
|
|
* \param [in] value The number to add
|
|
|
|
*/
|
|
|
|
void putInt32(uint32_t word);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends a 64-bit integer to the buffer
|
|
|
|
*
|
|
|
|
* A 64-bit integer will take up two 32-bit words.
|
|
|
|
* \param [in] value 64-bit value to add
|
|
|
|
*/
|
|
|
|
void putInt64(uint64_t value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends a 32-bit float to the buffer
|
|
|
|
* \param [in] value The number to add
|
|
|
|
*/
|
|
|
|
void putFloat32(float value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends a 64-bit float to the buffer
|
|
|
|
* \param [in] value The number to add
|
|
|
|
*/
|
|
|
|
void putFloat64(double value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Appends a literal string to the buffer
|
|
|
|
* \param [in] str String to append to the buffer
|
|
|
|
*/
|
|
|
|
void putStr(const char* str);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Adds the header to the buffer
|
|
|
|
* \param [in] boundIds Number of bound IDs
|
|
|
|
*/
|
|
|
|
void putHeader(uint32_t boundIds);
|
2019-11-19 12:17:11 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Erases given number of dwords
|
|
|
|
*
|
|
|
|
* Removes data from the code buffer, starting
|
|
|
|
* at the current insertion offset.
|
|
|
|
* \param [in] size Number of words to remove
|
|
|
|
*/
|
|
|
|
void erase(size_t size);
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Computes length of a literal string
|
|
|
|
*
|
|
|
|
* \param [in] str The string to check
|
|
|
|
* \returns Number of words consumed by a string
|
|
|
|
*/
|
|
|
|
uint32_t strLen(const char* str);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Stores the SPIR-V module to a stream
|
|
|
|
*
|
|
|
|
* The ability to save modules to a file
|
|
|
|
* exists mostly for debugging purposes.
|
|
|
|
* \param [in] stream Output stream
|
|
|
|
*/
|
2018-03-23 18:17:16 +01:00
|
|
|
void store(std::ostream& stream) const;
|
2017-10-11 23:29:05 +02:00
|
|
|
|
2017-12-30 17:22:36 +01:00
|
|
|
/**
|
|
|
|
* \brief Retrieves current insertion pointer
|
|
|
|
*
|
|
|
|
* Sometimes it may be necessay to insert code into the
|
|
|
|
* middle of the stream rather than appending it. This
|
|
|
|
* retrieves the current function pointer. Note that the
|
|
|
|
* pointer will become invalid if any code is inserted
|
|
|
|
* before the current pointer location.
|
|
|
|
* \returns Current instruction pointr
|
|
|
|
*/
|
|
|
|
size_t getInsertionPtr() const {
|
|
|
|
return m_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Sets insertion pointer to a specific value
|
|
|
|
*
|
|
|
|
* Sets the insertion pointer to a value that was
|
|
|
|
* previously retrieved by \ref getInsertionPtr.
|
|
|
|
* \returns Current instruction pointr
|
|
|
|
*/
|
|
|
|
void beginInsertion(size_t ptr) {
|
|
|
|
m_ptr = ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Sets insertion pointer to the end
|
|
|
|
*
|
|
|
|
* After this call, new instructions will be
|
|
|
|
* appended to the stream. In other words,
|
|
|
|
* this will restore default behaviour.
|
|
|
|
*/
|
|
|
|
void endInsertion() {
|
|
|
|
m_ptr = m_code.size();
|
|
|
|
}
|
|
|
|
|
2017-10-11 23:29:05 +02:00
|
|
|
private:
|
|
|
|
|
|
|
|
std::vector<uint32_t> m_code;
|
2017-12-30 17:22:36 +01:00
|
|
|
size_t m_ptr = 0;
|
2017-10-11 23:29:05 +02:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|