nothings / stb

stb single-file public domain libraries for C/C++
https://twitter.com/nothings
Other
25.99k stars 7.67k forks source link

texture random flipped orientation #1489

Closed ghost closed 1 year ago

ghost commented 1 year ago
    bool LoadTextureFromMemory(unsigned char* buffer, unsigned int buffer_size, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height)
    {
        // Load from memory into a raw RGBA buffer
        int image_width = 0;
        int image_height = 0;
        unsigned char* image_data = stbi_load_from_memory(buffer, buffer_size, &image_width, &image_height, NULL, 4);
        if (image_data == NULL)
            return false;

        // Create texture
        D3D11_TEXTURE2D_DESC desc;
        ZeroMemory(&desc, sizeof(desc));
        desc.Width = image_width;
        desc.Height = image_height;
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        desc.SampleDesc.Count = 1;
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = 0;

        ID3D11Texture2D* pTexture = NULL;
        D3D11_SUBRESOURCE_DATA subResource;
        subResource.pSysMem = image_data;
        subResource.SysMemPitch = desc.Width * 4;
        subResource.SysMemSlicePitch = 0;
        if (device->CreateTexture2D(&desc, &subResource, &pTexture) != S_OK)
        {
            *out_width = 0;
            *out_height = 0;
            stbi_image_free(image_data);

            return false;
        }

        // Create texture view
        D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
        ZeroMemory(&srvDesc, sizeof(srvDesc));
        srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Texture2D.MipLevels = desc.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = 0;
        device->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
        pTexture->Release();

        *out_width = image_width;
        *out_height = image_height;
        stbi_image_free(image_data);

        return true;
    }

The texture orientation that this code loads from memory is random, restarting the program multiple times will see the texture facing a different orientation (flipped)

https://github.com/ocornut/imgui/issues/6530

nothings commented 1 year ago

As far as I know, the above function as written will never cause the image to be flipped unless (a) you're manipulating stbi_set_flip_vertically_on_load or (b) you have a memory write error and are randomly writing into the variable set by stbi_set_flip_vertically_on_load. Without knowing more info, it's impossible to know if this is a bug in stb_image or a bug in your code.

ghost commented 1 year ago

I found that using stbi_set_flip_vertically_on_load(0) and stbi_set_flip_vertically_on_load_thread(0) before stbi_load_from_memory will not randomly flip the texture.

#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO
#define STBI_ONLY_JPEG
#define STBI_ONLY_PNG
#include "stb_image.h"

...
stbi_set_flip_vertically_on_load(0);
stbi_set_flip_vertically_on_load_thread(0);
unsigned char* image_data = stbi_load_from_memory(buffer, buffer_size, &image_width, &image_height, NULL, 4);

But if I don't add these codes, the texture is randomly flipped.

nothings commented 1 year ago

Both of those default to 0. So most likely you're either using another library that is using stb_image and setting that value, or you're randomly trashing memory.

Either way it seems unlikely to be a bug in stb_image, so I'm closing this issue, but you can continue to post here if you gather additional data.

zao commented 1 year ago

I pointed the user over here from the Dear ImGui issue where they first reported the problem. There I suggested this as a further avenue of investigation:

If it's varying per-run, a wild guess is that the code might be expecting thread-local variables to be zero-initialized but your platform's thread-local variables might not give that guarantee, or it might differ based on whether your STB_IMAGE_IMPLEMENTATION inclusion is in a C or C++ source file.

It would be interesting if @git-xiaocao could tell more about what platform and compiler this is and which implementation of STBI_THREAD_LOCAL is used there. While the workarounds are likely sufficient to mask the problem, there's definitely an underlying problem at hand, may it be overwritten variables or insufficient platform guarantees.

It might also be worthwhile to inspect it in a debugger to see what values the three implementation variables have in runs without the workarounds - that would help to tell if they seem to be legitimately set or have indeterminate or overwritten values.

ghost commented 1 year ago

I used stb_image like this before.

#include "imgui/imgui.h"
#include "imgui/imgui_impl_win32.h"
#include "imgui/imgui_impl_dx11.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
bool LoadTextureFromMemory(unsigned char* buffer, unsigned int buffer_size, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height)
{
    // Load from memory into a raw RGBA buffer
    int image_width = 0;
    int image_height = 0;
    unsigned char* image_data = stbi_load_from_memory(buffer, buffer_size, &image_width, &image_height, NULL, 4);
    if (image_data == NULL)
        return false;

    // Create texture
    D3D11_TEXTURE2D_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.Width = image_width;
    desc.Height = image_height;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    desc.SampleDesc.Count = 1;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = 0;

    ID3D11Texture2D* pTexture = NULL;
    D3D11_SUBRESOURCE_DATA subResource;
    subResource.pSysMem = image_data;
    subResource.SysMemPitch = desc.Width * 4;
    subResource.SysMemSlicePitch = 0;
    if (device->CreateTexture2D(&desc, &subResource, &pTexture) != S_OK)
    {
        *out_width = 0;
        *out_height = 0;
        stbi_image_free(image_data);

        return false;
    }

    // Create texture view
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    ZeroMemory(&srvDesc, sizeof(srvDesc));
    srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MipLevels = desc.MipLevels;
    srvDesc.Texture2D.MostDetailedMip = 0;
    device->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
    pTexture->Release();

    *out_width = image_width;
    *out_height = image_height;
    stbi_image_free(image_data);

    return true;
}

Dear ImGui Platform see include header file.

Development Platform is Visual Studio 2022 MSVC C++17 Windows 11 SDK 10.0.22621.0