1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05:52:11 +01:00

[spirv] Implement in-memory compression for shader modules

This commit is contained in:
Philip Rebohle 2019-04-04 02:46:41 +02:00
parent d2395180af
commit f32200b668
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
6 changed files with 163 additions and 0 deletions

View File

@ -1,5 +1,6 @@
spirv_src = files([ spirv_src = files([
'spirv_code_buffer.cpp', 'spirv_code_buffer.cpp',
'spirv_compression.cpp',
'spirv_module.cpp', 'spirv_module.cpp',
]) ])

View File

@ -9,6 +9,12 @@ namespace dxvk {
SpirvCodeBuffer::~SpirvCodeBuffer() { } SpirvCodeBuffer::~SpirvCodeBuffer() { }
SpirvCodeBuffer::SpirvCodeBuffer(uint32_t size)
: m_ptr(size) {
m_code.resize(size);
}
SpirvCodeBuffer::SpirvCodeBuffer(uint32_t size, const uint32_t* data) SpirvCodeBuffer::SpirvCodeBuffer(uint32_t size, const uint32_t* data)
: m_ptr(size) { : m_ptr(size) {
m_code.resize(size); m_code.resize(size);

View File

@ -21,6 +21,7 @@ namespace dxvk {
public: public:
SpirvCodeBuffer(); SpirvCodeBuffer();
explicit SpirvCodeBuffer(uint32_t size);
SpirvCodeBuffer(uint32_t size, const uint32_t* data); SpirvCodeBuffer(uint32_t size, const uint32_t* data);
SpirvCodeBuffer(std::istream& stream); SpirvCodeBuffer(std::istream& stream);
@ -37,6 +38,14 @@ namespace dxvk {
const uint32_t* data() const { return m_code.data(); } const uint32_t* data() const { return m_code.data(); }
uint32_t* data() { return m_code.data(); } uint32_t* data() { return m_code.data(); }
/**
* \brief Code size, in dwords
* \returns Code size, in dwords
*/
uint32_t dwords() const {
return m_code.size();
}
/** /**
* \brief Code size, in bytes * \brief Code size, in bytes
* \returns Code size, in bytes * \returns Code size, in bytes

View File

@ -0,0 +1,110 @@
#include "spirv_compression.h"
namespace dxvk {
SpirvCompressedBuffer::SpirvCompressedBuffer()
: m_size(0) {
}
SpirvCompressedBuffer::SpirvCompressedBuffer(
const SpirvCodeBuffer& code)
: m_size(code.dwords()) {
const uint32_t* data = code.data();
// The compression works by eliminating leading null bytes
// from DWORDs, exploiting that SPIR-V IDs are consecutive
// integers that usually fall into the 16-bit range. For
// each DWORD, a two-bit integer is stored which indicates
// the number of bytes it takes in the compressed buffer.
// This way, it can achieve a compression ratio of ~50%.
m_mask.reserve((m_size + NumMaskWords - 1) / NumMaskWords);
m_code.reserve(m_size * 4);
uint64_t dstWord = 0;
uint32_t dstShift = 0;
for (uint32_t i = 0; i < m_size; i += NumMaskWords) {
uint64_t byteCounts = 0;
for (uint32_t w = 0; w < NumMaskWords && i + w < m_size; w++) {
uint64_t word = data[i + w];
uint64_t bytes = 0;
if (word < (1 << 8)) bytes = 0;
else if (word < (1 << 16)) bytes = 1;
else if (word < (1 << 24)) bytes = 2;
else bytes = 3;
byteCounts |= bytes << (2 * w);
uint32_t bits = 8 * bytes + 8;
uint32_t rem = bit::pack(dstWord, dstShift, word, bits);
if (unlikely(rem != 0)) {
m_code.push_back(dstWord);
dstWord = 0;
dstShift = 0;
bit::pack(dstWord, dstShift, word >> (bits - rem), rem);
}
}
m_mask.push_back(byteCounts);
}
if (dstShift)
m_code.push_back(dstWord);
m_mask.shrink_to_fit();
m_code.shrink_to_fit();
}
SpirvCompressedBuffer::~SpirvCompressedBuffer() {
}
SpirvCodeBuffer SpirvCompressedBuffer::decompress() const {
SpirvCodeBuffer code(m_size);
uint32_t* data = code.data();
if (m_size == 0)
return code;
uint32_t maskIdx = 0;
uint32_t codeIdx = 0;
uint64_t srcWord = m_code[codeIdx++];
uint32_t srcShift = 0;
for (uint32_t i = 0; i < m_size; i += NumMaskWords) {
uint64_t srcMask = m_mask[maskIdx++];
for (uint32_t w = 0; w < NumMaskWords && i + w < m_size; w++) {
uint32_t bits = 8 * ((srcMask & 3) + 1);
uint64_t word = 0;
uint32_t rem = bit::unpack(word, srcWord, srcShift, bits);
if (unlikely(rem != 0)) {
srcWord = m_code[codeIdx++];
srcShift = 0;
uint64_t tmp = 0;
bit::unpack(tmp, srcWord, srcShift, rem);
word |= tmp << (bits - rem);
}
data[i + w] = word;
srcMask >>= 2;
}
}
return code;
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <vector>
#include "spirv_code_buffer.h"
namespace dxvk {
/**
* \brief Compressed SPIR-V code buffer
*
* Implements a fast in-memory compression
* to keep memory footprint low.
*/
class SpirvCompressedBuffer {
constexpr static uint32_t NumMaskWords = 32;
public:
SpirvCompressedBuffer();
SpirvCompressedBuffer(
const SpirvCodeBuffer& code);
~SpirvCompressedBuffer();
SpirvCodeBuffer decompress() const;
private:
uint32_t m_size;
std::vector<uint64_t> m_mask;
std::vector<uint64_t> m_code;
};
}

View File

@ -5,6 +5,7 @@
#include "../util/util_error.h" #include "../util/util_error.h"
#include "../util/util_flags.h" #include "../util/util_flags.h"
#include "../util/util_likely.h"
#include "../util/util_string.h" #include "../util/util_string.h"
#include "../util/rc/util_rc.h" #include "../util/rc/util_rc.h"