VkImage: Implement BC7 texture format
Also contains the following changes:
* Replace the use of `unsigned char` with `uint8_t`. `char` is not guaranteed to be 8-bit.
* Remove the `dstW` and `dstH` parameters from `BC_Decoder::Decode` and `ETC_Decoder::Decode`. They're always the same as the `w` and `h` parameters.
* Add BC6 types to various switch cases. The actual decode logic is not implemented for these formats.
Tests: *bc7*
Bug: b/151203718
Change-Id: I7b232b9dc3a9b02d172f87a62c88ce56b2cca956
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/41508
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/BC_Decoder.cpp b/src/Device/BC_Decoder.cpp
index f29b839..909ef8c 100644
--- a/src/Device/BC_Decoder.cpp
+++ b/src/Device/BC_Decoder.cpp
@@ -14,13 +14,22 @@
#include "BC_Decoder.hpp"
+#include "System/Debug.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+
+#include <assert.h>
+#include <stdint.h>
+
namespace {
static constexpr int BlockWidth = 4;
static constexpr int BlockHeight = 4;
struct BC_color
{
- void decode(unsigned char *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, bool hasAlphaChannel, bool hasSeparateAlpha) const
+ void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, bool hasAlphaChannel, bool hasSeparateAlpha) const
{
Color c[4];
c[0].extract565(c0);
@@ -133,7 +142,7 @@
struct BC_channel
{
- void decode(unsigned char *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, int channel, bool isSigned) const
+ void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp, int channel, bool isSigned) const
{
int c[8] = { 0 };
@@ -144,8 +153,8 @@
}
else
{
- c[0] = static_cast<unsigned char>(data & 0xFF);
- c[1] = static_cast<unsigned char>((data & 0xFF00) >> 8);
+ c[0] = static_cast<uint8_t>(data & 0xFF);
+ c[1] = static_cast<uint8_t>((data & 0xFF00) >> 8);
}
if(c[0] > c[1])
@@ -169,29 +178,29 @@
{
for(int i = 0; i < BlockWidth && (x + i) < dstW; i++)
{
- dst[channel + (i * dstBpp) + (j * dstPitch)] = static_cast<unsigned char>(c[getIdx((j * BlockHeight) + i)]);
+ dst[channel + (i * dstBpp) + (j * dstPitch)] = static_cast<uint8_t>(c[getIdx((j * BlockHeight) + i)]);
}
}
}
private:
- unsigned char getIdx(int i) const
+ uint8_t getIdx(int i) const
{
int offset = i * 3 + 16;
- return static_cast<unsigned char>((data & (0x7ull << offset)) >> offset);
+ return static_cast<uint8_t>((data & (0x7ull << offset)) >> offset);
}
- unsigned long long data;
+ uint64_t data;
};
struct BC_alpha
{
- void decode(unsigned char *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp) const
+ void decode(uint8_t *dst, int x, int y, int dstW, int dstH, int dstPitch, int dstBpp) const
{
dst += 3; // Write only to alpha (channel 3)
for(int j = 0; j < BlockHeight && (y + j) < dstH; j++, dst += dstPitch)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int i = 0; i < BlockWidth && (x + i) < dstW; i++, dstRow += dstBpp)
{
*dstRow = getAlpha(j * BlockHeight + i);
@@ -200,19 +209,587 @@
}
private:
- unsigned char getAlpha(int i) const
+ uint8_t getAlpha(int i) const
{
int offset = i << 2;
int alpha = (data & (0xFull << offset)) >> offset;
- return static_cast<unsigned char>(alpha | (alpha << 4));
+ return static_cast<uint8_t>(alpha | (alpha << 4));
}
- unsigned long long data;
+ uint64_t data;
};
-} // end namespace
+
+namespace BC7 {
+// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
+// https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format
+
+struct Bitfield
+{
+ int offset;
+ int count;
+ constexpr Bitfield Then(const int bits) { return { offset + count, bits }; }
+ constexpr bool operator==(const Bitfield &rhs)
+ {
+ return offset == rhs.offset && count == rhs.count;
+ }
+};
+
+struct Mode
+{
+ const int IDX; // Mode index
+ const int NS; // Number of subsets in each partition
+ const int PB; // Partition bits
+ const int RB; // Rotation bits
+ const int ISB; // Index selection bits
+ const int CB; // Color bits
+ const int AB; // Alpha bits
+ const int EPB; // Endpoint P-bits
+ const int SPB; // Shared P-bits
+ const int IB; // Primary index bits per element
+ const int IBC; // Primary index bits total
+ const int IB2; // Secondary index bits per element
+
+ constexpr int NumColors() const { return NS * 2; }
+ constexpr Bitfield Partition() const { return { IDX + 1, PB }; }
+ constexpr Bitfield Rotation() const { return Partition().Then(RB); }
+ constexpr Bitfield IndexSelection() const { return Rotation().Then(ISB); }
+ constexpr Bitfield Red(int idx) const
+ {
+ return IndexSelection().Then(CB * idx).Then(CB);
+ }
+ constexpr Bitfield Green(int idx) const
+ {
+ return Red(NumColors() - 1).Then(CB * idx).Then(CB);
+ }
+ constexpr Bitfield Blue(int idx) const
+ {
+ return Green(NumColors() - 1).Then(CB * idx).Then(CB);
+ }
+ constexpr Bitfield Alpha(int idx) const
+ {
+ return Blue(NumColors() - 1).Then(AB * idx).Then(AB);
+ }
+ constexpr Bitfield EndpointPBit(int idx) const
+ {
+ return Alpha(NumColors() - 1).Then(EPB * idx).Then(EPB);
+ }
+ constexpr Bitfield SharedPBit0() const
+ {
+ return EndpointPBit(NumColors() - 1).Then(SPB);
+ }
+ constexpr Bitfield SharedPBit1() const
+ {
+ return SharedPBit0().Then(SPB);
+ }
+ constexpr Bitfield PrimaryIndex(int offset, int count) const
+ {
+ return SharedPBit1().Then(offset).Then(count);
+ }
+ constexpr Bitfield SecondaryIndex(int offset, int count) const
+ {
+ return SharedPBit1().Then(IBC + offset).Then(count);
+ }
+};
+
+static constexpr Mode Modes[] = {
+ // IDX NS PB RB ISB CB AB EPB SPB IB IBC, IB2
+ /**/ { 0x0, 0x3, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x0, 0x3, 0x2d, 0x0 },
+ /**/ { 0x1, 0x2, 0x6, 0x0, 0x0, 0x6, 0x0, 0x0, 0x1, 0x3, 0x2e, 0x0 },
+ /**/ { 0x2, 0x3, 0x6, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x2, 0x1d, 0x0 },
+ /**/ { 0x3, 0x2, 0x6, 0x0, 0x0, 0x7, 0x0, 0x1, 0x0, 0x2, 0x1e, 0x0 },
+ /**/ { 0x4, 0x1, 0x0, 0x2, 0x1, 0x5, 0x6, 0x0, 0x0, 0x2, 0x1f, 0x3 },
+ /**/ { 0x5, 0x1, 0x0, 0x2, 0x0, 0x7, 0x8, 0x0, 0x0, 0x2, 0x1f, 0x2 },
+ /**/ { 0x6, 0x1, 0x0, 0x0, 0x0, 0x7, 0x7, 0x1, 0x0, 0x4, 0x3f, 0x0 },
+ /**/ { 0x7, 0x2, 0x6, 0x0, 0x0, 0x5, 0x5, 0x1, 0x0, 0x2, 0x1e, 0x0 },
+ /**/ { -1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x0 },
+};
+
+static_assert(Modes[0].NumColors() == 6, "BC7 sanity checks failed");
+static_assert(Modes[0].Partition() == Bitfield{ 1, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Red(0) == Bitfield{ 5, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Red(5) == Bitfield{ 25, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Green(0) == Bitfield{ 29, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Green(5) == Bitfield{ 49, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Blue(0) == Bitfield{ 53, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].Blue(5) == Bitfield{ 73, 4 }, "BC7 sanity checks failed");
+static_assert(Modes[0].EndpointPBit(0) == Bitfield{ 77, 1 }, "BC7 sanity checks failed");
+static_assert(Modes[0].EndpointPBit(5) == Bitfield{ 82, 1 }, "BC7 sanity checks failed");
+static_assert(Modes[0].PrimaryIndex(0, 2) == Bitfield{ 83, 2 }, "BC7 sanity checks failed");
+static_assert(Modes[0].PrimaryIndex(43, 1) == Bitfield{ 126, 1 }, "BC7 sanity checks failed");
+
+static constexpr int MaxPartitions = 64;
+static constexpr int MaxSubsets = 3;
+
+static constexpr uint8_t PartitionTable2[MaxPartitions][16] = {
+ { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
+ { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
+ { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
+ { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
+ { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
+ { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
+ { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
+ { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
+ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
+ { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
+ { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+ { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
+ { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
+ { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
+ { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
+ { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
+ { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
+ { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
+ { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
+ { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
+ { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
+ { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
+ { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
+ { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
+ { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
+ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
+ { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
+ { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
+ { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
+ { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
+ { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
+ { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
+ { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
+ { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+ { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 },
+};
+
+static constexpr uint8_t PartitionTable3[MaxPartitions][16] = {
+ { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
+ { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
+ { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
+ { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
+ { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
+ { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
+ { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
+ { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
+ { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
+ { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
+ { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
+ { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
+ { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
+ { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
+ { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
+ { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
+ { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
+ { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
+ { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
+ { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
+ { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
+ { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
+ { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
+ { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
+ { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
+ { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
+ { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
+ { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
+ { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
+ { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
+ { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
+ { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
+ { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
+ { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
+ { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
+ { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
+ { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
+ { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
+ { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
+ { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
+ { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
+ { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
+ { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
+ { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
+ { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
+ { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
+ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
+ { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
+ { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
+ { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
+ { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
+ { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 },
+};
+
+static constexpr uint8_t AnchorTable2[MaxPartitions] = {
+ // clang-format off
+ 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
+ 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
+ 0xf, 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0xf,
+ 0x2, 0x8, 0x2, 0x2, 0x8, 0x8, 0x2, 0x2,
+ 0xf, 0xf, 0x6, 0x8, 0x2, 0x8, 0xf, 0xf,
+ 0x2, 0x8, 0x2, 0x2, 0x2, 0xf, 0xf, 0x6,
+ 0x6, 0x2, 0x6, 0x8, 0xf, 0xf, 0x2, 0x2,
+ 0xf, 0xf, 0xf, 0xf, 0xf, 0x2, 0x2, 0xf,
+ // clang-format on
+};
+
+static constexpr uint8_t AnchorTable3a[MaxPartitions] = {
+ // clang-format off
+ 0x3, 0x3, 0xf, 0xf, 0x8, 0x3, 0xf, 0xf,
+ 0x8, 0x8, 0x6, 0x6, 0x6, 0x5, 0x3, 0x3,
+ 0x3, 0x3, 0x8, 0xf, 0x3, 0x3, 0x6, 0xa,
+ 0x5, 0x8, 0x8, 0x6, 0x8, 0x5, 0xf, 0xf,
+ 0x8, 0xf, 0x3, 0x5, 0x6, 0xa, 0x8, 0xf,
+ 0xf, 0x3, 0xf, 0x5, 0xf, 0xf, 0xf, 0xf,
+ 0x3, 0xf, 0x5, 0x5, 0x5, 0x8, 0x5, 0xa,
+ 0x5, 0xa, 0x8, 0xd, 0xf, 0xc, 0x3, 0x3,
+ // clang-format on
+};
+
+static constexpr uint8_t AnchorTable3b[MaxPartitions] = {
+ // clang-format off
+ 0xf, 0x8, 0x8, 0x3, 0xf, 0xf, 0x3, 0x8,
+ 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x8,
+ 0xf, 0x8, 0xf, 0x3, 0xf, 0x8, 0xf, 0x8,
+ 0x3, 0xf, 0x6, 0xa, 0xf, 0xf, 0xa, 0x8,
+ 0xf, 0x3, 0xf, 0xa, 0xa, 0x8, 0x9, 0xa,
+ 0x6, 0xf, 0x8, 0xf, 0x3, 0x6, 0x6, 0x8,
+ 0xf, 0x3, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
+ 0xf, 0xf, 0xf, 0xf, 0x3, 0xf, 0xf, 0x8,
+ // clang-format on
+};
+
+struct Color
+{
+ struct RGB
+ {
+ RGB() = default;
+ RGB(uint8_t r, uint8_t g, uint8_t b)
+ : b(b)
+ , g(g)
+ , r(r)
+ {}
+ RGB(int r, int g, int b)
+ : b(static_cast<uint8_t>(b))
+ , g(static_cast<uint8_t>(g))
+ , r(static_cast<uint8_t>(r))
+ {}
+
+ RGB operator<<(int shift) const { return { r << shift, g << shift, b << shift }; }
+ RGB operator>>(int shift) const { return { r >> shift, g >> shift, b >> shift }; }
+ RGB operator|(int bits) const { return { r | bits, g | bits, b | bits }; }
+ RGB operator|(const RGB &rhs) const { return { r | rhs.r, g | rhs.g, b | rhs.b }; }
+ RGB operator+(const RGB &rhs) const { return { r + rhs.r, g + rhs.g, b + rhs.b }; }
+
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ };
+
+ RGB rgb;
+ uint8_t a;
+};
+
+static_assert(sizeof(Color) == 4, "Color size must be 4 bytes");
+
+struct Block
+{
+ constexpr uint64_t Get(const Bitfield &bf) const
+ {
+ uint64_t mask = (1ULL << bf.count) - 1;
+ if(bf.offset + bf.count <= 64)
+ {
+ return (low >> bf.offset) & mask;
+ }
+ if(bf.offset >= 64)
+ {
+ return (high >> (bf.offset - 64)) & mask;
+ }
+ return ((low >> bf.offset) | (high << (64 - bf.offset))) & mask;
+ }
+
+ const Mode &mode() const
+ {
+ if((low & 0b00000001) != 0) { return Modes[0]; }
+ if((low & 0b00000010) != 0) { return Modes[1]; }
+ if((low & 0b00000100) != 0) { return Modes[2]; }
+ if((low & 0b00001000) != 0) { return Modes[3]; }
+ if((low & 0b00010000) != 0) { return Modes[4]; }
+ if((low & 0b00100000) != 0) { return Modes[5]; }
+ if((low & 0b01000000) != 0) { return Modes[6]; }
+ if((low & 0b10000000) != 0) { return Modes[7]; }
+ return Modes[8]; // Invalid mode
+ }
+
+ struct IndexInfo
+ {
+ uint64_t value;
+ int numBits;
+ };
+
+ uint8_t interpolate(uint8_t e0, uint8_t e1, const IndexInfo &index) const
+ {
+ static constexpr uint16_t weights2[] = { 0, 21, 43, 64 };
+ static constexpr uint16_t weights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
+ static constexpr uint16_t weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30,
+ 34, 38, 43, 47, 51, 55, 60, 64 };
+ static constexpr uint16_t const *weightsN[] = {
+ nullptr, nullptr, weights2, weights3, weights4
+ };
+ auto weights = weightsN[index.numBits];
+ ASSERT_MSG(weights != nullptr, "Unexpected number of index bits: %d", (int)index.numBits);
+ return (uint8_t)(((64 - weights[index.value]) * uint16_t(e0) + weights[index.value] * uint16_t(e1) + 32) >> 6);
+ }
+
+ void decode(uint8_t *dst, int dstX, int dstY, int dstWidth, int dstHeight, size_t dstPitch) const
+ {
+ auto const &mode = this->mode();
+
+ if(mode.IDX < 0) // Invalid mode:
+ {
+ for(int y = 0; y < 4 && y + dstY < dstHeight; y++)
+ {
+ for(int x = 0; x < 4 && x + dstX < dstWidth; x++)
+ {
+ auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
+ out->rgb = { 0, 0, 0 };
+ out->a = 0;
+ }
+ }
+ return;
+ }
+
+ using Endpoint = std::array<Color, 2>;
+ std::array<Endpoint, MaxSubsets> subsets;
+
+ for(int i = 0; i < mode.NS; i++)
+ {
+ auto &subset = subsets[i];
+ subset[0].rgb.r = Get(mode.Red(i * 2 + 0));
+ subset[0].rgb.g = Get(mode.Green(i * 2 + 0));
+ subset[0].rgb.b = Get(mode.Blue(i * 2 + 0));
+ subset[0].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 0)) : 255;
+
+ subset[1].rgb.r = Get(mode.Red(i * 2 + 1));
+ subset[1].rgb.g = Get(mode.Green(i * 2 + 1));
+ subset[1].rgb.b = Get(mode.Blue(i * 2 + 1));
+ subset[1].a = (mode.AB > 0) ? Get(mode.Alpha(i * 2 + 1)) : 255;
+ }
+
+ if(mode.SPB > 0)
+ {
+ auto pbit0 = Get(mode.SharedPBit0());
+ auto pbit1 = Get(mode.SharedPBit1());
+ subsets[0][0].rgb = (subsets[0][0].rgb << 1) | pbit0;
+ subsets[0][1].rgb = (subsets[0][1].rgb << 1) | pbit0;
+ subsets[1][0].rgb = (subsets[1][0].rgb << 1) | pbit1;
+ subsets[1][1].rgb = (subsets[1][1].rgb << 1) | pbit1;
+ }
+
+ if(mode.EPB > 0)
+ {
+ for(int i = 0; i < mode.NS; i++)
+ {
+ auto &subset = subsets[i];
+ auto pbit0 = Get(mode.EndpointPBit(i * 2 + 0));
+ auto pbit1 = Get(mode.EndpointPBit(i * 2 + 1));
+ subset[0].rgb = (subset[0].rgb << 1) | pbit0;
+ subset[1].rgb = (subset[1].rgb << 1) | pbit1;
+ if(mode.AB > 0)
+ {
+ subset[0].a = (subset[0].a << 1) | pbit0;
+ subset[1].a = (subset[1].a << 1) | pbit1;
+ }
+ }
+ }
+
+ auto const colorBits = mode.CB + mode.SPB + mode.EPB;
+ auto const alphaBits = mode.AB + mode.SPB + mode.EPB;
+
+ for(int i = 0; i < mode.NS; i++)
+ {
+ auto &subset = subsets[i];
+ subset[0].rgb = subset[0].rgb << (8 - colorBits);
+ subset[1].rgb = subset[1].rgb << (8 - colorBits);
+ subset[0].rgb = subset[0].rgb | (subset[0].rgb >> colorBits);
+ subset[1].rgb = subset[1].rgb | (subset[1].rgb >> colorBits);
+
+ if(mode.AB > 0)
+ {
+ subset[0].a = subset[0].a << (8 - alphaBits);
+ subset[1].a = subset[1].a << (8 - alphaBits);
+ subset[0].a = subset[0].a | (subset[0].a >> alphaBits);
+ subset[1].a = subset[1].a | (subset[1].a >> alphaBits);
+ }
+ }
+
+ int colorIndexBitOffset = 0;
+ int alphaIndexBitOffset = 0;
+ for(int y = 0; y < 4; y++)
+ {
+ for(int x = 0; x < 4; x++)
+ {
+ auto texelIdx = y * 4 + x;
+ auto partitionIdx = Get(mode.Partition());
+ ASSERT(partitionIdx < MaxPartitions);
+ auto subsetIdx = subsetIndex(mode, partitionIdx, texelIdx);
+ ASSERT(subsetIdx < MaxSubsets);
+ auto const &subset = subsets[subsetIdx];
+
+ auto anchorIdx = anchorIndex(mode, partitionIdx, subsetIdx);
+ auto isAnchor = anchorIdx == texelIdx;
+ auto colorIdx = colorIndex(mode, isAnchor, colorIndexBitOffset);
+ auto alphaIdx = alphaIndex(mode, isAnchor, alphaIndexBitOffset);
+
+ if(y + dstY >= dstHeight || x + dstX >= dstWidth)
+ {
+ // Don't be tempted to skip early at the loops:
+ // The calls to colorIndex() and alphaIndex() adjust bit
+ // offsets that need to be carefully tracked.
+ continue;
+ }
+
+ Color output;
+ output.rgb.r = interpolate(subset[0].rgb.r, subset[1].rgb.r, colorIdx);
+ output.rgb.g = interpolate(subset[0].rgb.g, subset[1].rgb.g, colorIdx);
+ output.rgb.b = interpolate(subset[0].rgb.b, subset[1].rgb.b, colorIdx);
+ output.a = interpolate(subset[0].a, subset[1].a, alphaIdx);
+
+ switch(Get(mode.Rotation()))
+ {
+ default:
+ break;
+ case 1:
+ std::swap(output.a, output.rgb.r);
+ break;
+ case 2:
+ std::swap(output.a, output.rgb.g);
+ break;
+ case 3:
+ std::swap(output.a, output.rgb.b);
+ break;
+ }
+
+ auto out = reinterpret_cast<Color *>(dst + sizeof(Color) * x + dstPitch * y);
+ *out = output;
+ }
+ }
+ }
+
+ int subsetIndex(const Mode &mode, int partitionIdx, int texelIndex) const
+ {
+ switch(mode.NS)
+ {
+ default:
+ return 0;
+ case 2:
+ return PartitionTable2[partitionIdx][texelIndex];
+ case 3:
+ return PartitionTable3[partitionIdx][texelIndex];
+ }
+ }
+
+ int anchorIndex(const Mode &mode, int partitionIdx, int subsetIdx) const
+ {
+ // ARB_texture_compression_bptc states:
+ // "In partition zero, the anchor index is always index zero.
+ // In other partitions, the anchor index is specified by tables
+ // Table.A2 and Table.A3.""
+ // Note: This is really confusing - I believe they meant subset instead
+ // of partition here.
+ switch(subsetIdx)
+ {
+ default:
+ return 0;
+ case 1:
+ return mode.NS == 2 ? AnchorTable2[partitionIdx] : AnchorTable3a[partitionIdx];
+ case 2:
+ return AnchorTable3b[partitionIdx];
+ }
+ }
+
+ IndexInfo colorIndex(const Mode &mode, bool isAnchor,
+ int &indexBitOffset) const
+ {
+ // ARB_texture_compression_bptc states:
+ // "The index value for interpolating color comes from the secondary
+ // index for the texel if the format has an index selection bit and its
+ // value is one and from the primary index otherwise.""
+ auto idx = Get(mode.IndexSelection());
+ ASSERT(idx <= 1);
+ bool secondary = idx == 1;
+ auto numBits = secondary ? mode.IB2 : mode.IB;
+ auto numReadBits = numBits - (isAnchor ? 1 : 0);
+ auto index =
+ Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
+ : mode.PrimaryIndex(indexBitOffset, numReadBits));
+ indexBitOffset += numReadBits;
+ return { index, numBits };
+ }
+
+ IndexInfo alphaIndex(const Mode &mode, bool isAnchor,
+ int &indexBitOffset) const
+ {
+ // ARB_texture_compression_bptc states:
+ // "The alpha index comes from the secondary index if the block has a
+ // secondary index and the block either doesn't have an index selection
+ // bit or that bit is zero and the primary index otherwise."
+ auto idx = Get(mode.IndexSelection());
+ ASSERT(idx <= 1);
+ bool secondary = (mode.IB2 != 0) && (idx == 0);
+ auto numBits = secondary ? mode.IB2 : mode.IB;
+ auto numReadBits = numBits - (isAnchor ? 1 : 0);
+ auto index =
+ Get(secondary ? mode.SecondaryIndex(indexBitOffset, numReadBits)
+ : mode.PrimaryIndex(indexBitOffset, numReadBits));
+ indexBitOffset += numReadBits;
+ return { index, numBits };
+ }
+
+ // Assumes little-endian
+ uint64_t low;
+ uint64_t high;
+};
+
+} // namespace BC7
+} // anonymous namespace
// Decodes 1 to 4 channel images to 8 bit output
-bool BC_Decoder::Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, int n, bool isNoAlphaU)
+bool BC_Decoder::Decode(const uint8_t *src, uint8_t *dst, int w, int h, int dstPitch, int dstBpp, int n, bool isNoAlphaU)
{
static_assert(sizeof(BC_color) == 8, "BC_color must be 8 bytes");
static_assert(sizeof(BC_channel) == 8, "BC_channel must be 8 bytes");
@@ -230,10 +807,10 @@
const BC_color *color = reinterpret_cast<const BC_color *>(src);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, ++color, dstRow += dx)
{
- color->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, isAlpha, false);
+ color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, false);
}
}
}
@@ -244,11 +821,11 @@
const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, alpha += 2, color += 2, dstRow += dx)
{
- color->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, isAlpha, true);
- alpha->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp);
+ color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
+ alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp);
}
}
}
@@ -259,11 +836,11 @@
const BC_color *color = reinterpret_cast<const BC_color *>(src + 8);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, alpha += 2, color += 2, dstRow += dx)
{
- color->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, isAlpha, true);
- alpha->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, 3, isSigned);
+ color->decode(dstRow, x, y, w, h, dstPitch, dstBpp, isAlpha, true);
+ alpha->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 3, isSigned);
}
}
}
@@ -273,10 +850,10 @@
const BC_channel *red = reinterpret_cast<const BC_channel *>(src);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, ++red, dstRow += dx)
{
- red->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, 0, isSigned);
+ red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
}
}
}
@@ -287,11 +864,24 @@
const BC_channel *green = reinterpret_cast<const BC_channel *>(src + 8);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
- unsigned char *dstRow = dst;
+ uint8_t *dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, red += 2, green += 2, dstRow += dx)
{
- red->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, 0, isSigned);
- green->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, 1, isSigned);
+ red->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 0, isSigned);
+ green->decode(dstRow, x, y, w, h, dstPitch, dstBpp, 1, isSigned);
+ }
+ }
+ }
+ break;
+ case 7: // BC7
+ {
+ const BC7::Block *block = reinterpret_cast<const BC7::Block *>(src);
+ for(int y = 0; y < h; y += BlockHeight, dst += dy)
+ {
+ uint8_t *dstRow = dst;
+ for(int x = 0; x < w; x += BlockWidth, ++block, dstRow += dx)
+ {
+ block->decode(dstRow, x, y, w, h, dstPitch);
}
}
}
diff --git a/src/Device/BC_Decoder.hpp b/src/Device/BC_Decoder.hpp
index 8ebbb60..2b58349 100644
--- a/src/Device/BC_Decoder.hpp
+++ b/src/Device/BC_Decoder.hpp
@@ -18,15 +18,13 @@
/// BCn_Decoder::Decode - Decodes 1 to 4 channel images to 8 bit output
/// @param src Pointer to BCn encoded image
/// @param dst Pointer to decoded output image
- /// @param w src image width
- /// @param h src image height
- /// @param dstW dst image width
- /// @param dstH dst image height
+ /// @param w image width
+ /// @param h image height
/// @param dstPitch dst image pitch (bytes per row)
/// @param dstBpp dst image bytes per pixel
/// @param n n in BCn format
/// @param isNoAlphaU BC1: true if RGB, BC2/BC3: unused, BC4/BC5: true if unsigned
/// @return true if the decoding was performed
- static bool Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, int n, bool isNoAlphaU);
+ static bool Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstPitch, int dstBpp, int n, bool isNoAlphaU);
};
diff --git a/src/Device/ETC_Decoder.cpp b/src/Device/ETC_Decoder.cpp
index d3fcf6e..0f8ecaa 100644
--- a/src/Device/ETC_Decoder.cpp
+++ b/src/Device/ETC_Decoder.cpp
@@ -667,7 +667,7 @@
} // namespace
// Decodes 1 to 4 channel images to 8 bit output
-bool ETC_Decoder::Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType)
+bool ETC_Decoder::Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstPitch, int dstBpp, InputType inputType)
{
const ETC2 *sources[2];
sources[0] = (const ETC2 *)src;
@@ -683,7 +683,7 @@
unsigned char *dstRow = dst + (y * dstPitch);
for(int x = 0; x < w; x += 4, sources[0]++)
{
- ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED, true);
+ ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, w, h, dstPitch, inputType == ETC_R_SIGNED, true);
}
}
break;
@@ -695,7 +695,7 @@
unsigned char *dstRow = dst + (y * dstPitch);
for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2)
{
- ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED, true);
+ ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, w, h, dstPitch, inputType == ETC_RG_SIGNED, true);
}
}
break;
@@ -706,7 +706,7 @@
unsigned char *dstRow = dst + (y * dstPitch);
for(int x = 0; x < w; x += 4, sources[0]++)
{
- sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA);
+ sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, w, h, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA);
}
}
break;
@@ -717,11 +717,11 @@
for(int x = 0; x < w; x += 4)
{
// Decode Alpha
- ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false, false);
+ ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, w, h, 4, false, false);
sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color
// Decode RGB
- sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, false);
+ sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, w, h, dstPitch, alphaValues, false);
sources[0]++;
}
}
diff --git a/src/Device/ETC_Decoder.hpp b/src/Device/ETC_Decoder.hpp
index f202bec..f606753 100644
--- a/src/Device/ETC_Decoder.hpp
+++ b/src/Device/ETC_Decoder.hpp
@@ -29,13 +29,11 @@
/// ETC_Decoder::Decode - Decodes 1 to 4 channel images to 8 bit output
/// @param src Pointer to ETC2 encoded image
/// @param dst Pointer to BGRA, 8 bit output
- /// @param w src image width
- /// @param h src image height
- /// @param dstW dst image width
- /// @param dstH dst image height
+ /// @param w image width
+ /// @param h image height
/// @param dstPitch dst image pitch (bytes per row)
/// @param dstBpp dst image bytes per pixel
/// @param inputType src's format
/// @return true if the decoding was performed
- static bool Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType);
+ static bool Decode(const unsigned char *src, unsigned char *dst, int w, int h, int dstPitch, int dstBpp, InputType inputType);
};
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index 72cef97..2638439 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -592,11 +592,13 @@
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
return VK_FORMAT_B8G8R8A8_UNORM;
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
return VK_FORMAT_B8G8R8A8_SRGB;
case VK_FORMAT_BC4_UNORM_BLOCK:
return VK_FORMAT_R8_UNORM;
@@ -636,6 +638,8 @@
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
return VK_FORMAT_R8G8B8A8_SRGB;
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT:
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT:
@@ -1316,6 +1320,8 @@
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
return 3;
@@ -1376,6 +1382,8 @@
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
@@ -1515,6 +1523,9 @@
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
@@ -1577,6 +1588,7 @@
case VK_FORMAT_R64G64B64A64_SFLOAT:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
@@ -1916,6 +1928,10 @@
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 08e3d8e..4c6e110 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -78,6 +78,12 @@
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
return 5;
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+ return 6;
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
+ return 7;
default:
UNSUPPORTED("format: %d", int(format));
return 0;
@@ -86,7 +92,7 @@
// Returns true for BC1 if we have an RGB format, false for RGBA
// Returns true for BC4 and BC5 if we have an unsigned format, false for signed
-// Ignored by BC2 and BC3
+// Ignored by BC2, BC3, BC6 and BC7
bool GetNoAlphaOrUnsigned(const vk::Format &format)
{
switch(format)
@@ -104,6 +110,10 @@
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
return false;
default:
UNSUPPORTED("format: %d", int(format));
@@ -986,6 +996,10 @@
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
+ case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+ case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
decodeBC(subresourceRange);
break;
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
@@ -1103,7 +1117,7 @@
}
ETC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height,
- mipLevelExtent.width, mipLevelExtent.height, pitchB, bytes, inputType);
+ pitchB, bytes, inputType);
}
}
}
@@ -1136,7 +1150,7 @@
uint8_t *dest = static_cast<uint8_t *>(decompressedImage->getTexelPointer({ 0, 0, depth }, subresourceLayers));
BC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height,
- mipLevelExtent.width, mipLevelExtent.height, pitchB, bytes, n, noAlphaU);
+ pitchB, bytes, n, noAlphaU);
}
}
}
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 3cd4561..e50654b 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -521,6 +521,8 @@
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
+ case VK_FORMAT_BC7_UNORM_BLOCK:
+ case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: