diff --git a/src/common/color.h b/src/common/color.h index 4ebd4f3d0..39bf65968 100644 --- a/src/common/color.h +++ b/src/common/color.h @@ -110,6 +110,12 @@ inline const Math::Vec4 DecodeRGBA4(const u8* bytes) { Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; } +// would an specialization but currently, you can't specialize static members. +inline const Math::Vec4 DecodeTexel(unsigned int rgba) { + return {(u8)(rgba & 0x00FF), (u8)((rgba >> 8) & 0x00FF), (u8)((rgba >> 16) & 0x00FF), + (u8)((rgba >> 24) & 0x00FF)}; +} + /** * Decode a depth value stored in D16 format * @param bytes Pointer to encoded source value diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b9f5d4533..e8ceee163 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -21,6 +21,8 @@ #include "video_core/pica_types.h" #include "video_core/rasterizer.h" #include "video_core/shader/shader.h" +#include "video_core/texture/codec.h" +#include "video_core/texture/formats.h" #include "video_core/utils.h" namespace Pica { @@ -399,6 +401,25 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, const Shader auto textures = regs.GetTextures(); auto tev_stages = regs.GetTevStages(); + std::unique_ptr decoded_textures[3]; + for (int i = 0; i < 3; i++) { + const auto& texture = textures[i]; + if (!texture.enabled) + continue; + u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); + auto format = Pica::Texture::Format::FromTextureFormat(texture.format); + auto tmp = Pica::Texture::CodecFactory::build(format, texture_data, texture.config.width, + texture.config.height); + Pica::Texture::Codec* codec = tmp.get(); + codec->configTiling(true, 8); + codec->configRGBATransform(true); + codec->validate(); + if (!codec->invalid()) { + codec->decode(); + decoded_textures[i] = codec->transferInternalBuffer(); + } + } + bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; const auto stencil_test = g_state.regs.output_merger.stencil_test; @@ -573,17 +594,17 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, const Shader // NOTE: This may not be the right place for the inversion. // TODO: Check if this applies to ETC textures, too. s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); - t = texture.config.height - 1 - - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); + t = GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); + u8* decoded_texture = decoded_textures[i].get(); + u64 pos = s + texture.config.width * t; + u32 texel; + std::memcpy(&texel, &decoded_texture[pos * 4], 4); + // TODO: Apply the min and mag filters to the texture + texture_color[i] = Color::DecodeTexel(texel); +#if PICA_DUMP_TEXTURES u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); - auto info = - DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); - - // TODO: Apply the min and mag filters to the texture - texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); -#if PICA_DUMP_TEXTURES DebugUtils::DumpTexture(texture.config, texture_data); #endif } @@ -958,8 +979,9 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, const Shader u8 new_stencil = PerformStencilAction(action, old_stencil, stencil_test.reference_value); if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) - SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | - (old_stencil & ~stencil_test.write_mask)); + SetStencil(x >> 4, y >> 4, + (new_stencil & stencil_test.write_mask) | + (old_stencil & ~stencil_test.write_mask)); }; if (stencil_action_enable) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 5389a8941..d831e3e91 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -17,7 +17,6 @@ #include "common/vector_math.h" #include "core/frontend/emu_window.h" #include "core/memory.h" -#include "video_core/debug_utils/debug_utils.h" #include "video_core/pica_state.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_state.h" @@ -461,8 +460,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( const Pica::Regs::FullTextureConfig& config) { - Pica::DebugUtils::TextureInfo info = - Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); + Pica::Texture::Info info = Pica::Texture::Info::FromPicaRegister(config.config, config.format); CachedSurface params; params.addr = info.physical_address; diff --git a/src/video_core/texture/codec.cpp b/src/video_core/texture/codec.cpp index d13a6dd45..e16d0589d 100644 --- a/src/video_core/texture/codec.cpp +++ b/src/video_core/texture/codec.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #include "common/color.h" #include "common/math_util.h" #include "common/swap.h" @@ -110,6 +113,30 @@ inline void Codec::encode_morton_pass() { this->start_nibbles_size * 4); } +u32 Codec::getTexel(u32 x, u32 y) { + const u32 tiling = this->morton_pass_tiling; + const u8* position = this->getTile(x, y); + const u32 bpp = this->start_nibbles_size * 4; // bits per pixel + const u32 mask = 0x0000FFFFFFFFUL >> (32 - bpp); + const u32 bit = (bpp % 8); + const u64 offset = (u64)EncodeMorton(x % tiling, y % tiling) % (tiling * tiling); + u32 result; + const u32 read_size = (bpp / 8) | ((bpp < 8) & 0x01); + std::memcpy(&result, &position[offset], read_size); + result >>= bit; + result &= mask; + return result; +} + +u8* Codec::getTile(u32 x, u32 y) { + const u32 tiling = this->morton_pass_tiling; + x = (x / tiling) * tiling; + y = (y / tiling) * tiling; + const u32 bpp = this->start_nibbles_size * 4; + const u64 offset = ((x + y * this->width) * bpp) / 8; + return (this->target_buffer + offset); +} + std::unique_ptr CodecFactory::build(Format::Type format, u8* target, u32 width, u32 height) { switch (format) { case Format::Type::RGBA8: diff --git a/src/video_core/texture/codec.h b/src/video_core/texture/codec.h index 5bcd653dc..c985aaa1c 100644 --- a/src/video_core/texture/codec.h +++ b/src/video_core/texture/codec.h @@ -4,6 +4,7 @@ #include #include #include "common/common_types.h" +#include "common/vector_math.h" #include "video_core/texture/formats.h" namespace Pica { @@ -23,6 +24,11 @@ public: virtual void decode(); virtual void encode(); + // for legacy code compatibility + // returns the corresponding texel in RGBA format. + // prefer full decode/encode than texel lookups for full image decoding. + virtual const Math::Vec4 lookupTexel(u32 x, u32 y) = 0; + inline void setWidth(u32 width) { this->width = width; } @@ -56,8 +62,6 @@ protected: u32 morton_pass_tiling = 8; bool raw_RGBA = false; bool preconverted = false; - bool disable_components = false; - u32 disable_components_mask = 0; u32 start_nibbles_size; u32 expected_nibbles_size; @@ -77,6 +81,8 @@ protected: inline void decode_morton_pass(); inline void encode_morton_pass(); + u32 getTexel(u32 x, u32 y); + u8* getTile(u32 x, u32 y); }; namespace CodecFactory { diff --git a/src/video_core/texture/formats.h b/src/video_core/texture/formats.h index 6418e780d..adbc72a68 100644 --- a/src/video_core/texture/formats.h +++ b/src/video_core/texture/formats.h @@ -10,6 +10,25 @@ namespace Pica { namespace Texture { +struct Info { + PAddr physical_address; + int width; + int height; + int stride; + Pica::Regs::TextureFormat format; + + static Info FromPicaRegister(const Pica::Regs::TextureConfig& config, + const Pica::Regs::TextureFormat& format) { + Info info; + info.physical_address = config.GetPhysicalAddress(); + info.width = config.width; + info.height = config.height; + info.format = format; + info.stride = Pica::Regs::NibblesPerPixel(info.format) * info.width / 2; + return info; + } +}; + struct Format { enum class Type { @@ -92,17 +111,6 @@ struct Format { }; // Format -struct Info { - PAddr physical_address; - int width; - int height; - int stride; - Pica::Regs::TextureFormat format; - - static Info FromPicaRegister(const Pica::Regs::TextureConfig& config, - const Pica::Regs::TextureFormat& format); -}; - } // Texture } // Pica diff --git a/src/video_core/texture/internal/codecs.cpp b/src/video_core/texture/internal/codecs.cpp index 753f33bdd..fdd8e1070 100644 --- a/src/video_core/texture/internal/codecs.cpp +++ b/src/video_core/texture/internal/codecs.cpp @@ -1,8 +1,10 @@ +#include "common/color.h" +#include "common/common_types.h" +#include "common/vector_math.h" #include "video_core/texture/internal/codecs.h" #include "video_core/texture/internal/etc1.h" #include "video_core/texture/internal/morton.h" #include "video_core/texture/internal/texture_utils.h" - /////////////////////////////////////////////////////////////////////////////// // Optimizations ////////////////////////////////////////////////////////////////////////////// @@ -20,3 +22,6 @@ // Encoders #include "encoders.cpp" + +// Lookup Texture +#include "lookup.cpp" diff --git a/src/video_core/texture/internal/codecs.h b/src/video_core/texture/internal/codecs.h index 5864d09b3..c6b570d22 100644 --- a/src/video_core/texture/internal/codecs.h +++ b/src/video_core/texture/internal/codecs.h @@ -4,15 +4,19 @@ #include #include #include "common/common_types.h" +#include "common/vector_math.h" #include "video_core/texture/codec.h" #include "video_core/texture/formats.h" // each texture format codec class RGBACodec : public Pica::Texture::Codec { public: - RGBACodec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RGBACodec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -26,9 +30,12 @@ protected: class RGBCodec : public Pica::Texture::Codec { public: - RGBCodec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RGBCodec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -42,9 +49,12 @@ protected: class RGB5A1Codec : public Pica::Texture::Codec { public: - RGB5A1Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RGB5A1Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -58,9 +68,12 @@ protected: class RGBA4Codec : public Pica::Texture::Codec { public: - RGBA4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RGBA4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -74,9 +87,12 @@ protected: class RGB565Codec : public Pica::Texture::Codec { public: - RGB565Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RGB565Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -90,9 +106,12 @@ protected: class RG8Codec : public Pica::Texture::Codec { public: - RG8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + RG8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -106,9 +125,12 @@ protected: class IA8Codec : public Pica::Texture::Codec { public: - IA8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + IA8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -122,9 +144,12 @@ protected: class I8Codec : public Pica::Texture::Codec { public: - I8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + I8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -138,9 +163,12 @@ protected: class A8Codec : public Pica::Texture::Codec { public: - A8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + A8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -154,9 +182,12 @@ protected: class IA4Codec : public Pica::Texture::Codec { public: - IA4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + IA4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -170,9 +201,12 @@ protected: class I4Codec : public Pica::Texture::Codec { public: - I4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + I4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -186,9 +220,12 @@ protected: class A4Codec : public Pica::Texture::Codec { public: - A4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + A4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -202,9 +239,12 @@ protected: class ETC1Codec : public Pica::Texture::Codec { public: - ETC1Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + ETC1Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -218,9 +258,12 @@ protected: class ETC1A4Codec : public Pica::Texture::Codec { public: - ETC1A4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + ETC1A4Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -234,9 +277,12 @@ protected: class D16Codec : public Pica::Texture::Codec { public: - D16Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + D16Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -250,9 +296,12 @@ protected: class D24Codec : public Pica::Texture::Codec { public: - D24Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + D24Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { @@ -266,9 +315,12 @@ protected: class D24S8Codec : public Pica::Texture::Codec { public: - D24S8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) {} + D24S8Codec(u8* target, u32 width, u32 height) : Pica::Texture::Codec(target, width, height) { + this->setSize(); + } void decode(); void encode(); + const Math::Vec4 lookupTexel(u32 x, u32 y); protected: virtual void setSize() { diff --git a/src/video_core/texture/internal/lookup.cpp b/src/video_core/texture/internal/lookup.cpp new file mode 100644 index 000000000..369fe326f --- /dev/null +++ b/src/video_core/texture/internal/lookup.cpp @@ -0,0 +1,110 @@ + +const Math::Vec4 RGBACodec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGBA8(tmp); +} + +const Math::Vec4 RGBCodec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGB8(tmp); +} + +const Math::Vec4 RGB5A1Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGB5A1(tmp); +} + +const Math::Vec4 RGB565Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGB565(tmp); +} + +const Math::Vec4 RGBA4Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGBA4(tmp); +} + +const Math::Vec4 RG8Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRG8(tmp); +} + +const Math::Vec4 IA8Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8 intensity = (texel & 0x00FF00) >> 8; + u8 alpha = (texel & 0x0000FF); + Math::Vec4 result(intensity, intensity, intensity, alpha); + return result; +} + +const Math::Vec4 IA4Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8 intensity = Color::Convert4To8((texel & 0x00F0) >> 4); + u8 alpha = Color::Convert4To8(texel & 0x0F); + Math::Vec4 result(intensity, intensity, intensity, alpha); + return result; +} + +const Math::Vec4 I8Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8 intensity = (texel & 0x0000FF); + Math::Vec4 result(intensity, intensity, intensity, 255); + return result; +} + +const Math::Vec4 I4Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + const u32 bit = 1 - (x % 2); + u8 intensity = Color::Convert4To8((texel & 0x0000FF) >> bit); + Math::Vec4 result(intensity, intensity, intensity, 255); + return result; +} + +const Math::Vec4 A8Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8 alpha = (texel & 0x0000FF); + Math::Vec4 result(0, 0, 0, alpha); + return result; +} + +const Math::Vec4 A4Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + const u32 bit = 1 - (x % 2); + u8 alpha = Color::Convert4To8((texel & 0x0000FF) >> bit); + Math::Vec4 result(0, 0, 0, alpha); + return result; +} + +const Math::Vec4 ETC1Codec::lookupTexel(u32 x, u32 y) { + Math::Vec4 result(0, 0, 0, 255); + return result; +} + +const Math::Vec4 ETC1A4Codec::lookupTexel(u32 x, u32 y) { + Math::Vec4 result(0, 0, 0, 255); + return result; +} + +const Math::Vec4 D16Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRG8(tmp); +} + +const Math::Vec4 D24Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGB8(tmp); +} + +const Math::Vec4 D24S8Codec::lookupTexel(u32 x, u32 y) { + u32 texel = super::getTexel(x, y); + u8* tmp = reinterpret_cast(&texel); + return Color::DecodeRGBA8(tmp); +} diff --git a/src/video_core/texture/internal/morton.cpp b/src/video_core/texture/internal/morton.cpp index 5b84db7a0..029d17955 100644 --- a/src/video_core/texture/internal/morton.cpp +++ b/src/video_core/texture/internal/morton.cpp @@ -19,22 +19,16 @@ static u32 Compact1By1(u32 x) { return x; } -static u32 EncodeMorton(u32 x, u32 y) { +u32 EncodeMorton(u32 x, u32 y) { return (Part1By1(y) << 1) | Part1By1(x); } -static u32 DecodeMortonX(u32 code) { +u32 DecodeMortonX(u32 code) { return Compact1By1(code >> 0); } -static u32 DecodeMortonY(u32 code) { +u32 DecodeMortonY(u32 code) { return Compact1By1(code >> 1); } -u32 MortonOffset(u32 x, u32 y, u32 width, u32 height, u32 tiling, u32 bpp) { - u32 tile = (x + y * height) * width / (tiling * tiling); - tile = (tile * bpp) / 8; - return tile + EncodeMorton(x % tiling, y % tiling); -} - #include "morton8x8_optimized.cpp" diff --git a/src/video_core/texture/internal/morton.h b/src/video_core/texture/internal/morton.h index 73fa22eb3..3bed308e7 100644 --- a/src/video_core/texture/internal/morton.h +++ b/src/video_core/texture/internal/morton.h @@ -2,7 +2,9 @@ #include "common/common_types.h" -u32 MortonOffset(u32 x, u32 y, u32 width, u32 height, u32 tiling, u32 bpp); +u32 EncodeMorton(u32 x, u32 y); +u32 DecodeMortonX(u32 code); +u32 DecodeMortonY(u32 code); namespace Decoders { bool Morton_8x8(u8* morton_buffer, u8* matrix_buffer, u32 width, u32 height, u32 bpp);