Commit c77b1d8c by Alexis Hetu Committed by Alexis Hétu

Support for BC1, BC2, BC3, BC4 and BC5

Added a block compression (BCn) decoder and logic for all formats for n in the [1, 5] range. The decompression follows the same logic as the ETC2 decompression in vk::Image. Tests: dEQP-VK.*bc* Bug: b/146052572 Change-Id: I64fac0a7af52e1be209c1cfd5373744918c7df14 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/39369 Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 07958d45
// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "BC_Decoder.hpp"
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
{
Color c[4];
c[0].extract565(c0);
c[1].extract565(c1);
if(hasSeparateAlpha || (c0 > c1))
{
c[2] = ((c[0] * 2) + c[1]) / 3;
c[3] = ((c[1] * 2) + c[0]) / 3;
}
else
{
c[2] = (c[0] + c[1]) >> 1;
if(hasAlphaChannel)
{
c[3].clearAlpha();
}
}
for(int j = 0; j < BlockHeight && (y + j) < dstH; j++)
{
int dstOffset = j * dstPitch;
int idxOffset = j * BlockHeight;
for(int i = 0; i < BlockWidth && (x + i) < dstW; i++, idxOffset++, dstOffset += dstBpp)
{
*reinterpret_cast<unsigned int*>(dst + dstOffset) = c[getIdx(idxOffset)].pack8888();
}
}
}
private:
struct Color
{
Color()
{
c[0] = c[1] = c[2] = 0;
c[3] = 0xFF000000;
}
void extract565(const unsigned int c565)
{
c[0] = ((c565 & 0x0000001F) << 3) | ((c565 & 0x0000001C) >> 2);
c[1] = ((c565 & 0x000007E0) >> 3) | ((c565 & 0x00000600) >> 9);
c[2] = ((c565 & 0x0000F800) >> 8) | ((c565 & 0x0000E000) >> 13);
}
unsigned int pack8888() const
{
return ((c[2] & 0xFF) << 16) | ((c[1] & 0xFF) << 8) | (c[0] & 0xFF) | c[3];
}
void clearAlpha()
{
c[3] = 0;
}
Color operator*(int factor) const
{
Color res;
for(int i = 0; i < 4; ++i)
{
res.c[i] = c[i] * factor;
}
return res;
}
Color operator/(int factor) const
{
Color res;
for(int i = 0; i < 4; ++i)
{
res.c[i] = c[i] / factor;
}
return res;
}
Color operator>>(int shift) const
{
Color res;
for(int i = 0; i < 4; ++i)
{
res.c[i] = c[i] >> shift;
}
return res;
}
Color operator+(Color const& obj) const
{
Color res;
for(int i = 0; i < 4; ++i)
{
res.c[i] = c[i] + obj.c[i];
}
return res;
}
private:
int c[4];
};
unsigned int getIdx(int i) const
{
int offset = i << 1; // 2 bytes per index
return (idx & (0x3 << offset)) >> offset;
}
unsigned short c0;
unsigned short c1;
unsigned int idx;
};
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
{
int c[8] = { 0 };
if(isSigned)
{
c[0] = static_cast<signed char>(data & 0xFF);
c[1] = static_cast<signed char>((data & 0xFF00) >> 8);
}
else
{
c[0] = static_cast<unsigned char>(data & 0xFF);
c[1] = static_cast<unsigned char>((data & 0xFF00) >> 8);
}
if(c[0] > c[1])
{
for(int i = 2; i < 8; ++i)
{
c[i] = ((8 - i) * c[0] + (i - 1) * c[1]) / 7;
}
}
else
{
for(int i = 2; i < 6; ++i)
{
c[i] = ((6 - i) * c[0] + (i - 1) * c[1]) / 5;
}
c[6] = isSigned ? -128 : 0;
c[7] = isSigned ? 127 : 255;
}
for(int j = 0; j < BlockHeight && (y + j) < dstH; j++)
{
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)]);
}
}
}
private:
unsigned char getIdx(int i) const
{
int offset = i * 3 + 16;
return static_cast<unsigned char>((data & (0x7ull << offset)) >> offset);
}
unsigned long long data;
};
struct BC_alpha
{
void decode(unsigned char* 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;
for(int i = 0; i < BlockWidth && (x + i) < dstW; i++, dstRow += dstBpp)
{
*dstRow = getAlpha(j * BlockHeight + i);
}
}
}
private:
unsigned char getAlpha(int i) const
{
int offset = i << 2;
int alpha = (data & (0xFull << offset)) >> offset;
return static_cast<unsigned char>(alpha | (alpha << 4));
}
unsigned long long data;
};
} // end 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)
{
static_assert(sizeof(BC_color) == 8, "BC_color must be 8 bytes");
static_assert(sizeof(BC_channel) == 8, "BC_channel must be 8 bytes");
static_assert(sizeof(BC_alpha) == 8, "BC_alpha must be 8 bytes");
const int dx = BlockWidth * dstBpp;
const int dy = BlockHeight * dstPitch;
const bool isAlpha = (n == 1) && !isNoAlphaU;
const bool isSigned = ((n == 4) || (n == 5) || (n == 6)) && !isNoAlphaU;
switch(n)
{
case 1: // BC1
{
const BC_color* color = reinterpret_cast<const BC_color*>(src);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
unsigned char* dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, ++color, dstRow += dx)
{
color->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, isAlpha, false);
}
}
}
break;
case 2: // BC2
{
const BC_alpha* alpha = reinterpret_cast<const BC_alpha*>(src);
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;
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);
}
}
}
break;
case 3: // BC3
{
const BC_channel* alpha = reinterpret_cast<const BC_channel*>(src);
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;
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);
}
}
}
break;
case 4: // BC4
{
const BC_channel* red = reinterpret_cast<const BC_channel*>(src);
for(int y = 0; y < h; y += BlockHeight, dst += dy)
{
unsigned char* dstRow = dst;
for(int x = 0; x < w; x += BlockWidth, ++red, dstRow += dx)
{
red->decode(dstRow, x, y, dstW, dstH, dstPitch, dstBpp, 0, isSigned);
}
}
}
break;
case 5: // BC5
{
const BC_channel* red = reinterpret_cast<const BC_channel*>(src);
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;
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);
}
}
}
break;
default:
return false;
}
return true;
}
// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
class BC_Decoder
{
public:
/// 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 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);
};
...@@ -16,6 +16,7 @@ import("../swiftshader.gni") ...@@ -16,6 +16,7 @@ import("../swiftshader.gni")
swiftshader_source_set("Device_headers") { swiftshader_source_set("Device_headers") {
sources = [ sources = [
"BC_Decoder.hpp",
"Blitter.hpp", "Blitter.hpp",
"Clipper.hpp", "Clipper.hpp",
"Color.hpp", "Color.hpp",
...@@ -37,6 +38,7 @@ swiftshader_source_set("Device_headers") { ...@@ -37,6 +38,7 @@ swiftshader_source_set("Device_headers") {
swiftshader_source_set("Device") { swiftshader_source_set("Device") {
sources = [ sources = [
"BC_Decoder.cpp",
"Blitter.cpp", "Blitter.cpp",
"Clipper.cpp", "Clipper.cpp",
"Color.cpp", "Color.cpp",
......
...@@ -305,6 +305,10 @@ bool Format::isSRGBformat() const ...@@ -305,6 +305,10 @@ bool Format::isSRGBformat() const
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
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:
return true; return true;
default: default:
return false; return false;
...@@ -555,6 +559,24 @@ VkFormat Format::getDecompressedFormat() const ...@@ -555,6 +559,24 @@ VkFormat Format::getDecompressedFormat() const
return VK_FORMAT_R16G16_UNORM; return VK_FORMAT_R16G16_UNORM;
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
return VK_FORMAT_R16G16_SNORM; return VK_FORMAT_R16G16_SNORM;
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC3_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:
return VK_FORMAT_B8G8R8A8_SRGB;
case VK_FORMAT_BC4_UNORM_BLOCK:
return VK_FORMAT_R8_UNORM;
case VK_FORMAT_BC4_SNORM_BLOCK:
return VK_FORMAT_R8_SNORM;
case VK_FORMAT_BC5_UNORM_BLOCK:
return VK_FORMAT_R8G8_UNORM;
case VK_FORMAT_BC5_SNORM_BLOCK:
return VK_FORMAT_R8G8_SNORM;
default: default:
UNIMPLEMENTED("format: %d", int(format)); UNIMPLEMENTED("format: %d", int(format));
return VK_FORMAT_UNDEFINED; return VK_FORMAT_UNDEFINED;
...@@ -1112,6 +1134,8 @@ int Format::componentCount() const ...@@ -1112,6 +1134,8 @@ int Format::componentCount() const
case VK_FORMAT_D16_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT: case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT: case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK: case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK: case VK_FORMAT_EAC_R11_SNORM_BLOCK:
return 1; return 1;
...@@ -1136,6 +1160,8 @@ int Format::componentCount() const ...@@ -1136,6 +1160,8 @@ int Format::componentCount() const
case VK_FORMAT_R64G64_UINT: case VK_FORMAT_R64G64_UINT:
case VK_FORMAT_R64G64_SINT: case VK_FORMAT_R64G64_SINT:
case VK_FORMAT_R64G64_SFLOAT: case VK_FORMAT_R64G64_SFLOAT:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
return 2; return 2;
...@@ -1172,6 +1198,8 @@ int Format::componentCount() const ...@@ -1172,6 +1198,8 @@ int Format::componentCount() const
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 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_ETC2_R8G8B8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
return 3; return 3;
...@@ -1226,6 +1254,12 @@ int Format::componentCount() const ...@@ -1226,6 +1254,12 @@ int Format::componentCount() const
case VK_FORMAT_R64G64B64A64_UINT: case VK_FORMAT_R64G64B64A64_UINT:
case VK_FORMAT_R64G64B64A64_SINT: case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT: case VK_FORMAT_R64G64B64A64_SFLOAT:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
...@@ -1313,11 +1347,24 @@ bool Format::isUnsignedComponent(int component) const ...@@ -1313,11 +1347,24 @@ bool Format::isUnsignedComponent(int component) const
case VK_FORMAT_D24_UNORM_S8_UINT: case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT: case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT: case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK: case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
return true; return true;
case VK_FORMAT_R8G8B8A8_SNORM: case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_SSCALED: case VK_FORMAT_R8G8B8A8_SSCALED:
...@@ -1342,11 +1389,10 @@ bool Format::isUnsignedComponent(int component) const ...@@ -1342,11 +1389,10 @@ bool Format::isUnsignedComponent(int component) const
case VK_FORMAT_R32G32B32A32_SFLOAT: case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R64G64B64A64_SINT: case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT: case VK_FORMAT_R64G64B64A64_SFLOAT:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK: case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
// YCbCr formats treated as signed because VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY // YCbCr formats treated as signed because VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY
// expects chroma components to be in range [-0.5, 0.5] // expects chroma components to be in range [-0.5, 0.5]
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
...@@ -1636,6 +1682,12 @@ int Format::pitchB(int width, int border, bool target) const ...@@ -1636,6 +1682,12 @@ int Format::pitchB(int width, int border, bool target) const
switch(format) switch(format)
{ {
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK: case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK: case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
...@@ -1643,6 +1695,12 @@ int Format::pitchB(int width, int border, bool target) const ...@@ -1643,6 +1695,12 @@ int Format::pitchB(int width, int border, bool target) const
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
return 8 * ((width + 3) / 4); // 64 bit per 4x4 block, computed per 4 rows return 8 * ((width + 3) / 4); // 64 bit per 4x4 block, computed per 4 rows
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
...@@ -1701,6 +1759,18 @@ int Format::sliceBUnpadded(int width, int height, int border, bool target) const ...@@ -1701,6 +1759,18 @@ int Format::sliceBUnpadded(int width, int height, int border, bool target) const
switch(format) switch(format)
{ {
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK: case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK: case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "VkDevice.hpp" #include "VkDevice.hpp"
#include "VkImage.hpp" #include "VkImage.hpp"
#include "Device/Blitter.hpp" #include "Device/Blitter.hpp"
#include "Device/BC_Decoder.hpp"
#include "Device/ETC_Decoder.hpp" #include "Device/ETC_Decoder.hpp"
#include <cstring> #include <cstring>
...@@ -53,6 +54,60 @@ ETC_Decoder::InputType GetInputType(const vk::Format& format) ...@@ -53,6 +54,60 @@ ETC_Decoder::InputType GetInputType(const vk::Format& format)
} }
} }
int GetBCn(const vk::Format& format)
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
return 1;
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
return 2;
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
return 3;
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
return 4;
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
return 5;
default:
UNIMPLEMENTED("format: %d", int(format));
return 0;
}
}
// 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
bool GetNoAlphaOrUnsigned(const vk::Format& format)
{
switch(format)
{
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
return true;
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
return false;
default:
UNIMPLEMENTED("format: %d", int(format));
return false;
}
}
} // anonymous namespace } // anonymous namespace
namespace vk { namespace vk {
...@@ -917,6 +972,20 @@ void Image::prepareForSampling(const VkImageSubresourceRange& subresourceRange) ...@@ -917,6 +972,20 @@ void Image::prepareForSampling(const VkImageSubresourceRange& subresourceRange)
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
decodeETC2(subresourceRange); decodeETC2(subresourceRange);
break; break;
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
decodeBC(subresourceRange);
break;
default: default:
break; break;
} }
...@@ -992,4 +1061,37 @@ void Image::decodeETC2(const VkImageSubresourceRange& subresourceRange) const ...@@ -992,4 +1061,37 @@ void Image::decodeETC2(const VkImageSubresourceRange& subresourceRange) const
} }
} }
} // namespace vk void Image::decodeBC(const VkImageSubresourceRange& subresourceRange) const
{
ASSERT(decompressedImage);
int n = GetBCn(format);
int noAlphaU = GetNoAlphaOrUnsigned(format);
uint32_t lastLayer = getLastLayerIndex(subresourceRange);
uint32_t lastMipLevel = getLastMipLevel(subresourceRange);
int bytes = decompressedImage->format.bytes();
VkImageSubresourceLayers subresourceLayers = { subresourceRange.aspectMask, subresourceRange.baseMipLevel, subresourceRange.baseArrayLayer, 1 };
for(; subresourceLayers.baseArrayLayer <= lastLayer; subresourceLayers.baseArrayLayer++)
{
for(; subresourceLayers.mipLevel <= lastMipLevel; subresourceLayers.mipLevel++)
{
VkExtent3D mipLevelExtent = getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceLayers.aspectMask), subresourceLayers.mipLevel);
int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresourceLayers.mipLevel);
for(int32_t depth = 0; depth < static_cast<int32_t>(mipLevelExtent.depth); depth++)
{
uint8_t* source = static_cast<uint8_t*>(getTexelPointer({ 0, 0, depth }, subresourceLayers));
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);
}
}
}
}
} // namespace vk
...@@ -108,6 +108,7 @@ private: ...@@ -108,6 +108,7 @@ private:
void clear(void* pixelData, VkFormat pixelFormat, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D& renderArea); void clear(void* pixelData, VkFormat pixelFormat, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D& renderArea);
int borderSize() const; int borderSize() const;
void decodeETC2(const VkImageSubresourceRange& subresourceRange) const; void decodeETC2(const VkImageSubresourceRange& subresourceRange) const;
void decodeBC(const VkImageSubresourceRange& subresourceRange) const;
const Device *const device = nullptr; const Device *const device = nullptr;
DeviceMemory* deviceMemory = nullptr; DeviceMemory* deviceMemory = nullptr;
......
...@@ -475,6 +475,18 @@ void PhysicalDevice::getFormatProperties(Format format, VkFormatProperties* pFor ...@@ -475,6 +475,18 @@ void PhysicalDevice::getFormatProperties(Format format, VkFormatProperties* pFor
case VK_FORMAT_R16G16B16A16_SFLOAT: case VK_FORMAT_R16G16B16A16_SFLOAT:
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment