fix nvjpg icon loading if w*bpp != pitch. add build option to enable/disable nvjpg (for testing).

This commit is contained in:
ITotalJustice
2025-06-03 02:16:23 +01:00
parent 7a83269d98
commit e88ca8ede1
4 changed files with 52 additions and 14 deletions

View File

@@ -208,6 +208,8 @@ FetchContent_Declare(nvjpg
)
set(USE_NEW_ZSTD ON)
# has issues with some homebrew and game icons (oxenfree, overwatch2).
set(USE_NVJPG ON)
set(ZSTD_BUILD_STATIC ON)
set(ZSTD_BUILD_SHARED OFF)
@@ -310,13 +312,15 @@ add_library(libnxtc
)
target_include_directories(libnxtc PUBLIC ${libnxtc_SOURCE_DIR}/include)
add_library(nvjpg
${nvjpg_SOURCE_DIR}/lib/decoder.cpp
${nvjpg_SOURCE_DIR}/lib/image.cpp
${nvjpg_SOURCE_DIR}/lib/surface.cpp
)
target_include_directories(nvjpg PUBLIC ${nvjpg_SOURCE_DIR}/include)
set_target_properties(nvjpg PROPERTIES CXX_STANDARD 26)
if (USE_NVJPG)
add_library(nvjpg
${nvjpg_SOURCE_DIR}/lib/decoder.cpp
${nvjpg_SOURCE_DIR}/lib/image.cpp
${nvjpg_SOURCE_DIR}/lib/surface.cpp
)
target_include_directories(nvjpg PUBLIC ${nvjpg_SOURCE_DIR}/include)
set_target_properties(nvjpg PROPERTIES CXX_STANDARD 26)
endif()
find_package(ZLIB REQUIRED)
find_library(minizip_lib minizip REQUIRED)
@@ -348,7 +352,6 @@ target_link_libraries(sphaira PRIVATE
yyjson
# libusbhsfs
libnxtc
nvjpg
${minizip_lib}
ZLIB::ZLIB
@@ -365,6 +368,11 @@ else()
target_include_directories(sphaira PRIVATE ${zstd_inc})
endif()
if (USE_NVJPG)
target_link_libraries(sphaira PRIVATE nvjpg)
target_compile_definitions(sphaira PRIVATE USE_NVJPG)
endif()
target_include_directories(sphaira PRIVATE
include
${minizip_inc}

View File

@@ -10,7 +10,9 @@
#include "fs.hpp"
#include "log.hpp"
#ifdef USE_NVJPG
#include <nvjpg.hpp>
#endif
#include <switch.h>
#include <vector>
#include <string>
@@ -273,7 +275,9 @@ public:
PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{};
#ifdef USE_NVJPG
nj::Decoder m_decoder;
#endif
private: // from nanovg decko3d example by adubbz
static constexpr unsigned NumFramebuffers = 2;

View File

@@ -1400,9 +1400,11 @@ App::App(const char* argv0) {
curl::Init();
#ifdef USE_NVJPG
// this has to be init before deko3d.
nj::initialize();
m_decoder.initialize();
#endif
// get current size of the framebuffer
const auto fb = GetFrameBufferSize();
@@ -1883,8 +1885,10 @@ App::~App() {
nvgDeleteDk(this->vg);
this->renderer.reset();
#ifdef USE_NVJPG
m_decoder.finalize();
nj::finalize();
#endif
// backup hbmenu if it is not sphaira
if (App::GetReplaceHbmenuEnable() && !IsHbmenu()) {

View File

@@ -22,7 +22,9 @@
#include "app.hpp"
#include "log.hpp"
#ifdef USE_NVJPG
#include <nvjpg.hpp>
#endif
#include <cstring>
namespace sphaira {
@@ -45,6 +47,7 @@ auto ImageLoadInternal(stbi_uc* image_data, int x, int y) -> ImageResult {
return {};
}
#ifdef USE_NVJPG
auto ImageLoadInternal(nj::Image&& image) -> ImageResult {
if (!image.is_valid() || image.parse()) {
log_write("[NVJPG] failed to parse image\n");
@@ -68,17 +71,29 @@ auto ImageLoadInternal(nj::Image&& image) -> ImageResult {
}
ImageResult result{};
result.w = image.width;
result.h = image.height;
result.data.resize(surf.size());
std::memcpy(result.data.data(), surf.data(), result.data.size());
result.w = surf.width;
result.h = surf.height;
result.data.resize(surf.width * surf.height * surf.get_bpp());
// std::printf("[NVJPG] w: %zu h: %zu bpp: %u pitch: %zu size: %zu size2: %u\n", surf.width, surf.height, surf.get_bpp(), surf.pitch, surf.size(), 256*256*4);
if (surf.width * surf.get_bpp() == surf.pitch) [[likely]] {
std::memcpy(result.data.data(), surf.data(), result.data.size());
} else {
for (size_t i = 0; i < surf.height; i++) {
const auto src_pitch = surf.pitch;
const auto dst_pitch = surf.width * surf.get_bpp();
std::memcpy(result.data.data() + i * dst_pitch, surf.data() + i * src_pitch, dst_pitch);
}
}
return result;
}
#endif
} // namespace
auto ImageLoadFromMemory(std::span<const u8> data, u32 flags) -> ImageResult {
#ifdef USE_NVJPG
if (flags & ImageFlag_JPEG) {
auto shared_vec = std::make_shared<std::vector<u8>>(data.size());
std::memcpy(shared_vec->data(), data.data(), shared_vec->size());
@@ -86,19 +101,26 @@ auto ImageLoadFromMemory(std::span<const u8> data, u32 flags) -> ImageResult {
auto result = ImageLoadInternal(nj::Image{shared_vec});
// if it failed, try again but without using oss-jpg.
return result.data.empty() ? ImageLoadFromMemory(data, 0) : result;
} else {
}
else
#endif
{
int x, y, channels;
return ImageLoadInternal(stbi_load_from_memory(data.data(), data.size(), &x, &y, &channels, BPP), x, y);
}
}
auto ImageLoadFromFile(const fs::FsPath& file, u32 flags) -> ImageResult {
#ifdef USE_NVJPG
if (flags & ImageFlag_JPEG) {
// don't make const as it prevents RTO.
auto result = ImageLoadInternal(nj::Image{file});
// if it failed, try again but without using oss-jpg.
return result.data.empty() ? ImageLoadFromFile(file, 0) : result;
} else {
}
else
#endif
{
int x, y, channels;
return ImageLoadInternal(stbi_load(file, &x, &y, &channels, BPP), x, y);
}