kopaka1822 / ImageViewer

HDR, PFM, DDS, KTX, EXR, PNG, JPG, BMP image viewer and manipulator
MIT License
324 stars 37 forks source link

KTX 1.1 load error "Attempted to divide by zero." Image Viewer v3.4 #19

Closed fdwr closed 3 years ago

fdwr commented 3 years ago

Describe the bug When I try to load a .ktx file, I just get an error dialog "Attempted to divide by zero".

image

To Reproduce Steps to reproduce the behavior:

  1. File / Open
  2. Load https://github.com/KhronosGroup/KTX-Software/blob/master/tests/testimages/hi_mark.ktx (tried a few others from https://github.com/KhronosGroup/KTX-Software/tree/master/tests/testimages, which failed too)
  3. See dialog "Attempted to divide by zero."

Expected behavior It opens the file, as it's evidently KTX 1.1 format (not KTX 2.0): image

Desktop (please complete the following information):

I don't have C# installed at the moment for Visual Studio, just C++, but if you need a stack, I can try to build the project.

[update] I see the error happens with DDS files too, but not PNG or JPEG.

kopaka1822 commented 3 years ago

Hello, this is an interesting issue. Unfortunately, I am not able to reproduce it, neither with 3.3 nor 3.4 (the hi_mark.ktx works for me). Both .ktx (<2.0) and .gli files are loaded with gli: https://github.com/g-truc/gli ktx v2 is loaded differently via libktx. Do .ktx2 files work for you? If so, the problem has probably something to do with gli. If you want to help me track down the error, you could download the newest version of gli from the githib and just run:

#include <gli/gli.hpp>
int main()
{
    gli::texture Texture = gli::load("hi_mark.ktx");
    return 0;
}

if this crashes with a similar error, then we might be able to find the error quickly. Otherwise I might actually need a stack trace to narrow down the error.

fdwr commented 3 years ago

If you want to help me track down the error,

Gladly. I tried a few KTX2 files:

βœ… https://github.com/KhronosGroup/KTX-Software/blob/master/tests/testimages/rgba-reference-u.ktx2 βœ… https://github.com/KhronosGroup/KTX-Software/blob/master/tests/testimages/cyan_rgba_reference_u.ktx2 ❌ https://github.com/KhronosGroup/KTX-Software/blob/master/tests/testimages/CesiumLogoFlat.ktx2 "error in D:\src\Pikselai\testdata\Khronos Texture\CesiumLogoFlat.ktx2: failed to transcode basis: File data is inconsistent with KTX spec."

I might actually need a stack trace to narrow down the error.

Turns out I added C# support after all for a different project. So I tried building the image viewer:

kopaka1822 commented 3 years ago

Did you build the project with x64? This is the only configuration where all include directories etc. are correctly configured. Also, I should probably add a "How to build" page

kopaka1822 commented 3 years ago

Maybe this helps you build and debug: https://github.com/kopaka1822/ImageViewer/blob/master/Docs/build.md

fdwr commented 3 years ago

Did you build the project with x64?

πŸ‘ Yeah, that was the only issue - don't leave it set to "AnyCPU". The build instructions will be good for others too.

the problem has probably something to do with gli.

Indeed, the issue is in GLI. So I'm closing this (and should probably open an issue here instead: https://github.com/g-truc/gli).

I tried "hi_mark.ktx" from here https://github.com/KhronosGroup/KTX-Software/blob/53aa501d12611543141fc7a4f67f03e53cefd83c/tests/testimages/hi_mark.ktx (not the latest file, which has been updated), and I get:

---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Assertion failed!

Program: ...\Kopaka1822ImageViewer\x64\Debug\DxImageLoader.dll
File: D:\srcex\Kopaka1822ImageViewer\dependenc...\load_ktx.inl
Line: 67

Expression: (Format != gli::FORMAT_UNDEFINED)
    DxImageLoader.dll!_wassert(const wchar_t * expression, const wchar_t * file_name, unsigned int line_number) Line 444    C++
>   DxImageLoader.dll!gli::detail::load_ktx10(const char * Data, unsigned __int64 Size) Line 67 C++
    DxImageLoader.dll!gli::load_ktx(const char * Data, unsigned __int64 Size) Line 108  C++
    DxImageLoader.dll!gli::load(const char * Data, unsigned __int64 Size) Line 22   C++
    DxImageLoader.dll!gli::load(const char * Filename) Line 47  C++
    DxImageLoader.dll!gli_load(const char * filename) Line 12   C++
    DxImageLoader.dll!image_open(const char * filename) Line 74 C++
...
    ImageFramework.dll!ImageFramework.ImageLoader.Resource.Resource(string file) Line 16    C#
    ImageFramework.dll!ImageFramework.ImageLoader.IO.LoadImage(string file) Line 41 C#
    ImageFramework.dll!ImageFramework.ImageLoader.IO.LoadImageTexture(string file, out ImageFramework.ImageLoader.GliFormat originalFormat) Line 53 C#
    ImageFramework.dll!ImageFramework.ImageLoader.IO.LoadImageTextureAsync.AnonymousMethod__0() Line 78 C#
    inline texture load_ktx10(char const* Data, std::size_t Size)
    {
        detail::ktx_header10 const & Header(*reinterpret_cast<detail::ktx_header10 const*>(Data));

        size_t Offset = sizeof(detail::ktx_header10);

        // Skip key value data
        Offset += Header.BytesOfKeyValueData;

        gl GL(gl::PROFILE_KTX);
        gli::format const Format = GL.find(
            static_cast<gli::gl::internal_format>(Header.GLInternalFormat),
            static_cast<gli::gl::external_format>(Header.GLFormat),
            static_cast<gli::gl::type_format>(Header.GLType));
        GLI_ASSERT(Format != gli::FORMAT_UNDEFINED); <-------------------------

However, if update to the latest "hi_mark.ktx" from the link above that I shared with you (I was actually using an older version that I had downloaded earlier), then it loads fine. The other DDS file I tried shows the same stack too in gli. It's just coincidence that the first four files I tried with your image viewer happen to not be supported by gli πŸ˜‹. Thanks. Cheers from near Seattle.

fdwr commented 3 years ago

p.s. The actual division by zero originates here:

dependencies\gli\external\glm\ext\scalar_integer.inl

template<>
struct compute_ceilMultiple<false, true>
{
    template<typename genType>
    GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
    {
        assert(Multiple > genType(0));
        if(Source > genType(0))
        {
            genType Tmp = Source - genType(1);
            return Tmp + (Multiple - (Tmp % Multiple));
        }
        else
            return Source + (-Source % Multiple); <----------------- "Multiple" == 0
    }
};

Their code should be a little more robust against unknown formats :b :

inline texture::texture
(
    target_type Target,
    format_type Format,
    extent_type const& Extent,
    size_type Layers,
    size_type Faces,
    size_type Levels,
    swizzles_type const& Swizzles
)
    : Storage(std::make_shared<storage_type>(Format, Extent, Layers, Faces, Levels)) <--- fails here, Format = FORMAT_UNDEFINED (0)
kopaka1822 commented 3 years ago

Thanks for the information! Is it correct that just some arbitrary test files do not work due to gli? If you have troubles opening actual files you need to work with I can also try to fix the error on my forked gli branch first. I know that it can take a few years for them to fix issues or even accept pull requests.

fdwr commented 3 years ago

Is it correct that just some arbitrary test files do not work due to gli?

Yep, the files I tried are arbitrary as I just randomly downloaded a few .ktx's from the Khronos Group repo (but they're AFAIK not particularly novel or anything).

it can take a few years for them to fix issues or even accept pull requests

Oh wow, a few years. Well I don't need a fix, because I found this converter online (https://comparecommander.com/convert-ktx-to-png/), but I wanted to report the issue either way. I stumbled across your viewer last night while looking for a way to display .ktx files because I've been collecting a large list of pixel formats from various API and file format specifications (DXGI, D3D, WIC, Vulkan, OpenGL, PVR, GenICam PFNC...). Thanks.