1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-23 08:52:12 +01:00
dxvk/src/spirv/spirv_compression.cpp
Philip Rebohle da4baefdf0
[spirv] Fix initial allocation size for compressed buffer
The old initial size was still for uint8.
2019-04-04 13:15:59 +02:00

110 lines
2.7 KiB
C++

#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 + 1) / 2);
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;
}
}