forked from suyu/suyu
Merge pull request #2149 from ReinUsesLisp/decoders-style
gl_rasterizer_cache: Move format conversion functions to their own file
This commit is contained in:
commit
076c76f4e4
8 changed files with 183 additions and 150 deletions
|
@ -94,6 +94,8 @@ add_library(video_core STATIC
|
||||||
surface.h
|
surface.h
|
||||||
textures/astc.cpp
|
textures/astc.cpp
|
||||||
textures/astc.h
|
textures/astc.h
|
||||||
|
textures/convert.cpp
|
||||||
|
textures/convert.h
|
||||||
textures/decoders.cpp
|
textures/decoders.cpp
|
||||||
textures/decoders.h
|
textures/decoders.h
|
||||||
textures/texture.h
|
textures/texture.h
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
#include "video_core/textures/astc.h"
|
#include "video_core/textures/convert.h"
|
||||||
#include "video_core/textures/decoders.h"
|
#include "video_core/textures/decoders.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
@ -597,103 +597,6 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bool reverse) {
|
|
||||||
union S8Z24 {
|
|
||||||
BitField<0, 24, u32> z24;
|
|
||||||
BitField<24, 8, u32> s8;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(S8Z24) == 4, "S8Z24 is incorrect size");
|
|
||||||
|
|
||||||
union Z24S8 {
|
|
||||||
BitField<0, 8, u32> s8;
|
|
||||||
BitField<8, 24, u32> z24;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size");
|
|
||||||
|
|
||||||
S8Z24 s8z24_pixel{};
|
|
||||||
Z24S8 z24s8_pixel{};
|
|
||||||
constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
|
|
||||||
for (std::size_t y = 0; y < height; ++y) {
|
|
||||||
for (std::size_t x = 0; x < width; ++x) {
|
|
||||||
const std::size_t offset{bpp * (y * width + x)};
|
|
||||||
if (reverse) {
|
|
||||||
std::memcpy(&z24s8_pixel, &data[offset], sizeof(Z24S8));
|
|
||||||
s8z24_pixel.s8.Assign(z24s8_pixel.s8);
|
|
||||||
s8z24_pixel.z24.Assign(z24s8_pixel.z24);
|
|
||||||
std::memcpy(&data[offset], &s8z24_pixel, sizeof(S8Z24));
|
|
||||||
} else {
|
|
||||||
std::memcpy(&s8z24_pixel, &data[offset], sizeof(S8Z24));
|
|
||||||
z24s8_pixel.s8.Assign(s8z24_pixel.s8);
|
|
||||||
z24s8_pixel.z24.Assign(s8z24_pixel.z24);
|
|
||||||
std::memcpy(&data[offset], &z24s8_pixel, sizeof(Z24S8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to perform software conversion (as needed) when loading a buffer from Switch
|
|
||||||
* memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
|
|
||||||
* typical desktop GPUs.
|
|
||||||
*/
|
|
||||||
static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
|
|
||||||
u32 width, u32 height, u32 depth) {
|
|
||||||
switch (pixel_format) {
|
|
||||||
case PixelFormat::ASTC_2D_4X4:
|
|
||||||
case PixelFormat::ASTC_2D_8X8:
|
|
||||||
case PixelFormat::ASTC_2D_8X5:
|
|
||||||
case PixelFormat::ASTC_2D_5X4:
|
|
||||||
case PixelFormat::ASTC_2D_5X5:
|
|
||||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_5X5_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_10X8:
|
|
||||||
case PixelFormat::ASTC_2D_10X8_SRGB: {
|
|
||||||
// Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
|
|
||||||
u32 block_width{};
|
|
||||||
u32 block_height{};
|
|
||||||
std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
|
|
||||||
data =
|
|
||||||
Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PixelFormat::S8Z24:
|
|
||||||
// Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24.
|
|
||||||
ConvertS8Z24ToZ24S8(data, width, height, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to perform software conversion (as needed) when flushing a buffer from OpenGL to
|
|
||||||
* Switch memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or
|
|
||||||
* with typical desktop GPUs.
|
|
||||||
*/
|
|
||||||
static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
|
|
||||||
u32 width, u32 height) {
|
|
||||||
switch (pixel_format) {
|
|
||||||
case PixelFormat::ASTC_2D_4X4:
|
|
||||||
case PixelFormat::ASTC_2D_8X8:
|
|
||||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_5X5:
|
|
||||||
case PixelFormat::ASTC_2D_5X5_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_10X8:
|
|
||||||
case PixelFormat::ASTC_2D_10X8_SRGB: {
|
|
||||||
LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
|
|
||||||
static_cast<u32>(pixel_format));
|
|
||||||
UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PixelFormat::S8Z24:
|
|
||||||
// Convert the Z24S8 depth format to S8Z24, as OpenGL does not support S8Z24.
|
|
||||||
ConvertS8Z24ToZ24S8(data, width, height, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::LoadGLBuffer() {
|
void CachedSurface::LoadGLBuffer() {
|
||||||
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
||||||
|
@ -722,8 +625,16 @@ void CachedSurface::LoadGLBuffer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < params.max_mip_level; i++) {
|
for (u32 i = 0; i < params.max_mip_level; i++) {
|
||||||
ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
|
const u32 width = params.MipWidth(i);
|
||||||
params.MipHeight(i), params.MipDepth(i));
|
const u32 height = params.MipHeight(i);
|
||||||
|
const u32 depth = params.MipDepth(i);
|
||||||
|
if (VideoCore::Surface::IsPixelFormatASTC(params.pixel_format)) {
|
||||||
|
// Reserve size for RGBA8 conversion
|
||||||
|
constexpr std::size_t rgba_bpp = 4;
|
||||||
|
gl_buffer[i].resize(std::max(gl_buffer[i].size(), width * height * depth * rgba_bpp));
|
||||||
|
}
|
||||||
|
Tegra::Texture::ConvertFromGuestToHost(gl_buffer[i].data(), params.pixel_format, width,
|
||||||
|
height, depth, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,8 +657,8 @@ void CachedSurface::FlushGLBuffer() {
|
||||||
glGetTextureImage(texture.handle, 0, tuple.format, tuple.type,
|
glGetTextureImage(texture.handle, 0, tuple.format, tuple.type,
|
||||||
static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data());
|
static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data());
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||||
ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width,
|
Tegra::Texture::ConvertFromHostToGuest(gl_buffer[0].data(), params.pixel_format, params.width,
|
||||||
params.height);
|
params.height, params.depth, true, true);
|
||||||
const u8* const texture_src_data = Memory::GetPointer(params.addr);
|
const u8* const texture_src_data = Memory::GetPointer(params.addr);
|
||||||
ASSERT(texture_src_data);
|
ASSERT(texture_src_data);
|
||||||
if (params.is_tiled) {
|
if (params.is_tiled) {
|
||||||
|
|
|
@ -23,28 +23,12 @@
|
||||||
|
|
||||||
#include "video_core/textures/astc.h"
|
#include "video_core/textures/astc.h"
|
||||||
|
|
||||||
class BitStream {
|
class InputBitStream {
|
||||||
public:
|
public:
|
||||||
explicit BitStream(unsigned char* ptr, int nBits = 0, int start_offset = 0)
|
explicit InputBitStream(const unsigned char* ptr, int nBits = 0, int start_offset = 0)
|
||||||
: m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {}
|
: m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {}
|
||||||
|
|
||||||
~BitStream() = default;
|
~InputBitStream() = default;
|
||||||
|
|
||||||
int GetBitsWritten() const {
|
|
||||||
return m_BitsWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteBitsR(unsigned int val, unsigned int nBits) {
|
|
||||||
for (unsigned int i = 0; i < nBits; i++) {
|
|
||||||
WriteBit((val >> (nBits - i - 1)) & 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteBits(unsigned int val, unsigned int nBits) {
|
|
||||||
for (unsigned int i = 0; i < nBits; i++) {
|
|
||||||
WriteBit((val >> i) & 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetBitsRead() const {
|
int GetBitsRead() const {
|
||||||
return m_BitsRead;
|
return m_BitsRead;
|
||||||
|
@ -70,6 +54,38 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int m_NumBits;
|
||||||
|
const unsigned char* m_CurByte;
|
||||||
|
int m_NextBit = 0;
|
||||||
|
int m_BitsRead = 0;
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OutputBitStream {
|
||||||
|
public:
|
||||||
|
explicit OutputBitStream(unsigned char* ptr, int nBits = 0, int start_offset = 0)
|
||||||
|
: m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {}
|
||||||
|
|
||||||
|
~OutputBitStream() = default;
|
||||||
|
|
||||||
|
int GetBitsWritten() const {
|
||||||
|
return m_BitsWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteBitsR(unsigned int val, unsigned int nBits) {
|
||||||
|
for (unsigned int i = 0; i < nBits; i++) {
|
||||||
|
WriteBit((val >> (nBits - i - 1)) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteBits(unsigned int val, unsigned int nBits) {
|
||||||
|
for (unsigned int i = 0; i < nBits; i++) {
|
||||||
|
WriteBit((val >> i) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteBit(int b) {
|
void WriteBit(int b) {
|
||||||
|
|
||||||
|
@ -238,8 +254,8 @@ public:
|
||||||
// Fills result with the values that are encoded in the given
|
// Fills result with the values that are encoded in the given
|
||||||
// bitstream. We must know beforehand what the maximum possible
|
// bitstream. We must know beforehand what the maximum possible
|
||||||
// value is, and how many values we're decoding.
|
// value is, and how many values we're decoding.
|
||||||
static void DecodeIntegerSequence(std::vector<IntegerEncodedValue>& result, BitStream& bits,
|
static void DecodeIntegerSequence(std::vector<IntegerEncodedValue>& result,
|
||||||
uint32_t maxRange, uint32_t nValues) {
|
InputBitStream& bits, uint32_t maxRange, uint32_t nValues) {
|
||||||
// Determine encoding parameters
|
// Determine encoding parameters
|
||||||
IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(maxRange);
|
IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(maxRange);
|
||||||
|
|
||||||
|
@ -267,7 +283,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void DecodeTritBlock(BitStream& bits, std::vector<IntegerEncodedValue>& result,
|
static void DecodeTritBlock(InputBitStream& bits, std::vector<IntegerEncodedValue>& result,
|
||||||
uint32_t nBitsPerValue) {
|
uint32_t nBitsPerValue) {
|
||||||
// Implement the algorithm in section C.2.12
|
// Implement the algorithm in section C.2.12
|
||||||
uint32_t m[5];
|
uint32_t m[5];
|
||||||
|
@ -327,7 +343,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DecodeQuintBlock(BitStream& bits, std::vector<IntegerEncodedValue>& result,
|
static void DecodeQuintBlock(InputBitStream& bits, std::vector<IntegerEncodedValue>& result,
|
||||||
uint32_t nBitsPerValue) {
|
uint32_t nBitsPerValue) {
|
||||||
// Implement the algorithm in section C.2.12
|
// Implement the algorithm in section C.2.12
|
||||||
uint32_t m[3];
|
uint32_t m[3];
|
||||||
|
@ -406,7 +422,7 @@ struct TexelWeightParams {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static TexelWeightParams DecodeBlockInfo(BitStream& strm) {
|
static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
|
||||||
TexelWeightParams params;
|
TexelWeightParams params;
|
||||||
|
|
||||||
// Read the entire block mode all at once
|
// Read the entire block mode all at once
|
||||||
|
@ -605,7 +621,7 @@ static TexelWeightParams DecodeBlockInfo(BitStream& strm) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FillVoidExtentLDR(BitStream& strm, uint32_t* const outBuf, uint32_t blockWidth,
|
static void FillVoidExtentLDR(InputBitStream& strm, uint32_t* const outBuf, uint32_t blockWidth,
|
||||||
uint32_t blockHeight) {
|
uint32_t blockHeight) {
|
||||||
// Don't actually care about the void extent, just read the bits...
|
// Don't actually care about the void extent, just read the bits...
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
@ -821,7 +837,7 @@ static void DecodeColorValues(uint32_t* out, uint8_t* data, const uint32_t* mode
|
||||||
|
|
||||||
// We now have enough to decode our integer sequence.
|
// We now have enough to decode our integer sequence.
|
||||||
std::vector<IntegerEncodedValue> decodedColorValues;
|
std::vector<IntegerEncodedValue> decodedColorValues;
|
||||||
BitStream colorStream(data);
|
InputBitStream colorStream(data);
|
||||||
IntegerEncodedValue::DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
|
IntegerEncodedValue::DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues);
|
||||||
|
|
||||||
// Once we have the decoded values, we need to dequantize them to the 0-255 range
|
// Once we have the decoded values, we need to dequantize them to the 0-255 range
|
||||||
|
@ -1365,9 +1381,9 @@ static void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const uint32_t*& colorValue
|
||||||
#undef READ_INT_VALUES
|
#undef READ_INT_VALUES
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
|
static void DecompressBlock(const uint8_t inBuf[16], const uint32_t blockWidth,
|
||||||
const uint32_t blockHeight, uint32_t* outBuf) {
|
const uint32_t blockHeight, uint32_t* outBuf) {
|
||||||
BitStream strm(inBuf);
|
InputBitStream strm(inBuf);
|
||||||
TexelWeightParams weightParams = DecodeBlockInfo(strm);
|
TexelWeightParams weightParams = DecodeBlockInfo(strm);
|
||||||
|
|
||||||
// Was there an error?
|
// Was there an error?
|
||||||
|
@ -1421,7 +1437,7 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
|
||||||
// Define color data.
|
// Define color data.
|
||||||
uint8_t colorEndpointData[16];
|
uint8_t colorEndpointData[16];
|
||||||
memset(colorEndpointData, 0, sizeof(colorEndpointData));
|
memset(colorEndpointData, 0, sizeof(colorEndpointData));
|
||||||
BitStream colorEndpointStream(colorEndpointData, 16 * 8, 0);
|
OutputBitStream colorEndpointStream(colorEndpointData, 16 * 8, 0);
|
||||||
|
|
||||||
// Read extra config data...
|
// Read extra config data...
|
||||||
uint32_t baseCEM = 0;
|
uint32_t baseCEM = 0;
|
||||||
|
@ -1549,7 +1565,7 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
|
||||||
memset(texelWeightData + clearByteStart, 0, 16 - clearByteStart);
|
memset(texelWeightData + clearByteStart, 0, 16 - clearByteStart);
|
||||||
|
|
||||||
std::vector<IntegerEncodedValue> texelWeightValues;
|
std::vector<IntegerEncodedValue> texelWeightValues;
|
||||||
BitStream weightStream(texelWeightData);
|
InputBitStream weightStream(texelWeightData);
|
||||||
|
|
||||||
IntegerEncodedValue::DecodeIntegerSequence(texelWeightValues, weightStream,
|
IntegerEncodedValue::DecodeIntegerSequence(texelWeightValues, weightStream,
|
||||||
weightParams.m_MaxWeight,
|
weightParams.m_MaxWeight,
|
||||||
|
@ -1597,7 +1613,7 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
|
||||||
|
|
||||||
namespace Tegra::Texture::ASTC {
|
namespace Tegra::Texture::ASTC {
|
||||||
|
|
||||||
std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
|
std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t height,
|
||||||
uint32_t depth, uint32_t block_width, uint32_t block_height) {
|
uint32_t depth, uint32_t block_width, uint32_t block_height) {
|
||||||
uint32_t blockIdx = 0;
|
uint32_t blockIdx = 0;
|
||||||
std::vector<uint8_t> outData(height * width * depth * 4);
|
std::vector<uint8_t> outData(height * width * depth * 4);
|
||||||
|
@ -1605,7 +1621,7 @@ std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint
|
||||||
for (uint32_t j = 0; j < height; j += block_height) {
|
for (uint32_t j = 0; j < height; j += block_height) {
|
||||||
for (uint32_t i = 0; i < width; i += block_width) {
|
for (uint32_t i = 0; i < width; i += block_width) {
|
||||||
|
|
||||||
uint8_t* blockPtr = data.data() + blockIdx * 16;
|
const uint8_t* blockPtr = data + blockIdx * 16;
|
||||||
|
|
||||||
// Blocks can be at most 12x12
|
// Blocks can be at most 12x12
|
||||||
uint32_t uncompData[144];
|
uint32_t uncompData[144];
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace Tegra::Texture::ASTC {
|
namespace Tegra::Texture::ASTC {
|
||||||
|
|
||||||
std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
|
std::vector<uint8_t> Decompress(const uint8_t* data, uint32_t width, uint32_t height,
|
||||||
uint32_t depth, uint32_t block_width, uint32_t block_height);
|
uint32_t depth, uint32_t block_width, uint32_t block_height);
|
||||||
|
|
||||||
} // namespace Tegra::Texture::ASTC
|
} // namespace Tegra::Texture::ASTC
|
||||||
|
|
92
src/video_core/textures/convert.cpp
Normal file
92
src/video_core/textures/convert.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "video_core/textures/astc.h"
|
||||||
|
#include "video_core/textures/convert.h"
|
||||||
|
|
||||||
|
namespace Tegra::Texture {
|
||||||
|
|
||||||
|
using VideoCore::Surface::PixelFormat;
|
||||||
|
|
||||||
|
template <bool reverse>
|
||||||
|
void SwapS8Z24ToZ24S8(u8* data, u32 width, u32 height) {
|
||||||
|
union S8Z24 {
|
||||||
|
BitField<0, 24, u32> z24;
|
||||||
|
BitField<24, 8, u32> s8;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(S8Z24) == 4, "S8Z24 is incorrect size");
|
||||||
|
|
||||||
|
union Z24S8 {
|
||||||
|
BitField<0, 8, u32> s8;
|
||||||
|
BitField<8, 24, u32> z24;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size");
|
||||||
|
|
||||||
|
S8Z24 s8z24_pixel{};
|
||||||
|
Z24S8 z24s8_pixel{};
|
||||||
|
constexpr auto bpp{
|
||||||
|
VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8Z24)};
|
||||||
|
for (std::size_t y = 0; y < height; ++y) {
|
||||||
|
for (std::size_t x = 0; x < width; ++x) {
|
||||||
|
const std::size_t offset{bpp * (y * width + x)};
|
||||||
|
if constexpr (reverse) {
|
||||||
|
std::memcpy(&z24s8_pixel, &data[offset], sizeof(Z24S8));
|
||||||
|
s8z24_pixel.s8.Assign(z24s8_pixel.s8);
|
||||||
|
s8z24_pixel.z24.Assign(z24s8_pixel.z24);
|
||||||
|
std::memcpy(&data[offset], &s8z24_pixel, sizeof(S8Z24));
|
||||||
|
} else {
|
||||||
|
std::memcpy(&s8z24_pixel, &data[offset], sizeof(S8Z24));
|
||||||
|
z24s8_pixel.s8.Assign(s8z24_pixel.s8);
|
||||||
|
z24s8_pixel.z24.Assign(s8z24_pixel.z24);
|
||||||
|
std::memcpy(&data[offset], &z24s8_pixel, sizeof(Z24S8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertS8Z24ToZ24S8(u8* data, u32 width, u32 height) {
|
||||||
|
SwapS8Z24ToZ24S8<false>(data, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertZ24S8ToS8Z24(u8* data, u32 width, u32 height) {
|
||||||
|
SwapS8Z24ToZ24S8<true>(data, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertFromGuestToHost(u8* data, PixelFormat pixel_format, u32 width, u32 height, u32 depth,
|
||||||
|
bool convert_astc, bool convert_s8z24) {
|
||||||
|
if (convert_astc && IsPixelFormatASTC(pixel_format)) {
|
||||||
|
// Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
|
||||||
|
u32 block_width{};
|
||||||
|
u32 block_height{};
|
||||||
|
std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
|
||||||
|
const std::vector<u8> rgba8_data =
|
||||||
|
Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height);
|
||||||
|
std::copy(rgba8_data.begin(), rgba8_data.end(), data);
|
||||||
|
|
||||||
|
} else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) {
|
||||||
|
Tegra::Texture::ConvertS8Z24ToZ24S8(data, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertFromHostToGuest(u8* data, PixelFormat pixel_format, u32 width, u32 height, u32 depth,
|
||||||
|
bool convert_astc, bool convert_s8z24) {
|
||||||
|
if (convert_astc && IsPixelFormatASTC(pixel_format)) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
|
||||||
|
static_cast<u32>(pixel_format));
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
} else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) {
|
||||||
|
Tegra::Texture::ConvertZ24S8ToS8Z24(data, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tegra::Texture
|
18
src/video_core/textures/convert.h
Normal file
18
src/video_core/textures/convert.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
|
|
||||||
|
namespace Tegra::Texture {
|
||||||
|
|
||||||
|
void ConvertFromGuestToHost(u8* data, VideoCore::Surface::PixelFormat pixel_format, u32 width,
|
||||||
|
u32 height, u32 depth, bool convert_astc, bool convert_s8z24);
|
||||||
|
|
||||||
|
void ConvertFromHostToGuest(u8* data, VideoCore::Surface::PixelFormat pixel_format, u32 width,
|
||||||
|
u32 height, u32 depth, bool convert_astc, bool convert_s8z24);
|
||||||
|
|
||||||
|
} // namespace Tegra::Texture
|
|
@ -103,8 +103,8 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const
|
||||||
const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]};
|
const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]};
|
||||||
const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
|
const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
|
||||||
const u32 pixel_index{out_x + pixel_base};
|
const u32 pixel_index{out_x + pixel_base};
|
||||||
data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
|
data_ptrs[unswizzle ? 1 : 0] = swizzled_data + swizzle_offset;
|
||||||
data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
|
data_ptrs[unswizzle ? 0 : 1] = unswizzled_data + pixel_index;
|
||||||
std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align);
|
std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align);
|
||||||
}
|
}
|
||||||
pixel_base += stride_x;
|
pixel_base += stride_x;
|
||||||
|
@ -154,7 +154,7 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool
|
||||||
for (u32 xb = 0; xb < blocks_on_x; xb++) {
|
for (u32 xb = 0; xb < blocks_on_x; xb++) {
|
||||||
const u32 x_start = xb * block_x_elements;
|
const u32 x_start = xb * block_x_elements;
|
||||||
const u32 x_end = std::min(width, x_start + block_x_elements);
|
const u32 x_end = std::min(width, x_start + block_x_elements);
|
||||||
if (fast) {
|
if constexpr (fast) {
|
||||||
FastProcessBlock(swizzled_data, unswizzled_data, unswizzle, x_start, y_start,
|
FastProcessBlock(swizzled_data, unswizzled_data, unswizzle, x_start, y_start,
|
||||||
z_start, x_end, y_end, z_end, tile_offset, xy_block_size,
|
z_start, x_end, y_end, z_end, tile_offset, xy_block_size,
|
||||||
layer_z, stride_x, bytes_per_pixel, out_bytes_per_pixel);
|
layer_z, stride_x, bytes_per_pixel, out_bytes_per_pixel);
|
||||||
|
|
|
@ -16,16 +16,13 @@ inline std::size_t GetGOBSize() {
|
||||||
return 512;
|
return 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Unswizzles a swizzled texture without changing its format.
|
||||||
* Unswizzles a swizzled texture without changing its format.
|
|
||||||
*/
|
|
||||||
void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
|
void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y,
|
||||||
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||||
u32 block_height = TICEntry::DefaultBlockHeight,
|
u32 block_height = TICEntry::DefaultBlockHeight,
|
||||||
u32 block_depth = TICEntry::DefaultBlockHeight, u32 width_spacing = 0);
|
u32 block_depth = TICEntry::DefaultBlockHeight, u32 width_spacing = 0);
|
||||||
/**
|
|
||||||
* Unswizzles a swizzled texture without changing its format.
|
/// Unswizzles a swizzled texture without changing its format.
|
||||||
*/
|
|
||||||
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
|
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
|
||||||
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||||
u32 block_height = TICEntry::DefaultBlockHeight,
|
u32 block_height = TICEntry::DefaultBlockHeight,
|
||||||
|
@ -37,15 +34,11 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel,
|
||||||
u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data,
|
u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data,
|
||||||
bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing);
|
bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing);
|
||||||
|
|
||||||
/**
|
/// Decodes an unswizzled texture into a A8R8G8B8 texture.
|
||||||
* Decodes an unswizzled texture into a A8R8G8B8 texture.
|
|
||||||
*/
|
|
||||||
std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
|
std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
|
||||||
u32 height);
|
u32 height);
|
||||||
|
|
||||||
/**
|
/// This function calculates the correct size of a texture depending if it's tiled or not.
|
||||||
* This function calculates the correct size of a texture depending if it's tiled or not.
|
|
||||||
*/
|
|
||||||
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||||
u32 block_height, u32 block_depth);
|
u32 block_height, u32 block_depth);
|
||||||
|
|
||||||
|
@ -53,6 +46,7 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height
|
||||||
void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
|
void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
|
||||||
u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
|
u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
|
||||||
u32 block_height);
|
u32 block_height);
|
||||||
|
|
||||||
/// Copies a tiled subrectangle into a linear surface.
|
/// Copies a tiled subrectangle into a linear surface.
|
||||||
void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width,
|
void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width,
|
||||||
u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
|
u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
|
||||||
|
|
Loading…
Reference in a new issue