Skip to content

Commit

Permalink
Merge pull request ddnet#7412 from Robyt3/Graphics-Invalid-TexLoad-Flags
Browse files Browse the repository at this point in the history
Fix flashing black screen when loading menu themes, fix some textures being loaded without mipmaps, refactoring
  • Loading branch information
def- authored Nov 4, 2023
2 parents 1d93695 + 367c7ba commit b60b14b
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 139 deletions.
44 changes: 24 additions & 20 deletions src/engine/client/graphics_threaded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void CGraphics_Threaded::FreeTextureIndex(CTextureHandle *pIndex)

int CGraphics_Threaded::UnloadTexture(CTextureHandle *pIndex)
{
if(pIndex->Id() == m_InvalidTexture.Id())
if(pIndex->Id() == m_NullTexture.Id())
return 0;

if(!pIndex->IsValid())
Expand Down Expand Up @@ -368,7 +368,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadSpriteTextureImpl(CImageInfo &
const size_t PixelSize = FromImageInfo.PixelSize();
m_vSpriteHelper.resize(w * h * PixelSize);
CopyTextureFromTextureBufferSub(m_vSpriteHelper.data(), w, h, (uint8_t *)FromImageInfo.m_pData, FromImageInfo.m_Width, FromImageInfo.m_Height, PixelSize, x, y, w, h);
return LoadTextureRaw(w, h, FromImageInfo.m_Format, m_vSpriteHelper.data(), FromImageInfo.m_Format, 0);
return LoadTextureRaw(w, h, FromImageInfo.m_Format, m_vSpriteHelper.data(), 0);
}

IGraphics::CTextureHandle CGraphics_Threaded::LoadSpriteTexture(CImageInfo &FromImageInfo, CDataSprite *pSprite)
Expand Down Expand Up @@ -482,19 +482,22 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTexture(const char *pFilename,
CImageInfo Img;
if(LoadPNG(&Img, pFilename, StorageType))
{
IGraphics::CTextureHandle ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, Flags, pFilename);
free(Img.m_pData);
if(ID.Id() != m_InvalidTexture.Id() && g_Config.m_Debug)
dbg_msg("graphics/texture", "loaded %s", pFilename);
return ID;
CTextureHandle ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, Flags, pFilename);
FreePNG(&Img);
if(ID.IsValid())
{
if(g_Config.m_Debug)
dbg_msg("graphics/texture", "loaded %s", pFilename);
return ID;
}
}

return m_InvalidTexture;
return m_NullTexture;
}

IGraphics::CTextureHandle CGraphics_Threaded::InvalidTexture() const
IGraphics::CTextureHandle CGraphics_Threaded::NullTexture() const
{
return m_InvalidTexture;
return m_NullTexture;
}

bool CGraphics_Threaded::LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData)
Expand Down Expand Up @@ -2609,27 +2612,28 @@ int CGraphics_Threaded::Init()
const unsigned char aGreen[] = {0x00, 0xff, 0x00, 0xff};
const unsigned char aBlue[] = {0x00, 0x00, 0xff, 0xff};
const unsigned char aYellow[] = {0xff, 0xff, 0x00, 0xff};
constexpr size_t InvalidTextureDimension = 16;
unsigned char aNullTextureData[InvalidTextureDimension * InvalidTextureDimension * PixelSize];
for(size_t y = 0; y < InvalidTextureDimension; ++y)
constexpr size_t NullTextureDimension = 16;
unsigned char aNullTextureData[NullTextureDimension * NullTextureDimension * PixelSize];
for(size_t y = 0; y < NullTextureDimension; ++y)
{
for(size_t x = 0; x < InvalidTextureDimension; ++x)
for(size_t x = 0; x < NullTextureDimension; ++x)
{
const unsigned char *pColor;
if(x < InvalidTextureDimension / 2 && y < InvalidTextureDimension / 2)
if(x < NullTextureDimension / 2 && y < NullTextureDimension / 2)
pColor = aRed;
else if(x >= InvalidTextureDimension / 2 && y < InvalidTextureDimension / 2)
else if(x >= NullTextureDimension / 2 && y < NullTextureDimension / 2)
pColor = aGreen;
else if(x < InvalidTextureDimension / 2 && y >= InvalidTextureDimension / 2)
else if(x < NullTextureDimension / 2 && y >= NullTextureDimension / 2)
pColor = aBlue;
else
pColor = aYellow;
mem_copy(&aNullTextureData[(y * InvalidTextureDimension + x) * PixelSize], pColor, PixelSize);
mem_copy(&aNullTextureData[(y * NullTextureDimension + x) * PixelSize], pColor, PixelSize);
}
}
const int TextureLoadFlags = HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
m_InvalidTexture.Invalidate();
m_InvalidTexture = LoadTextureRaw(InvalidTextureDimension, InvalidTextureDimension, CImageInfo::FORMAT_RGBA, aNullTextureData, TextureLoadFlags);
m_NullTexture.Invalidate();
m_NullTexture = LoadTextureRaw(NullTextureDimension, NullTextureDimension, CImageInfo::FORMAT_RGBA, aNullTextureData, TextureLoadFlags);
dbg_assert(m_NullTexture.IsNullTexture(), "Null texture invalid");
}

ColorRGBA GPUInfoPrintColor{0.6f, 0.5f, 1.0f, 1.0f};
Expand Down
4 changes: 2 additions & 2 deletions src/engine/client/graphics_threaded.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ class CGraphics_Threaded : public IEngineGraphics
bool m_DoScreenshot;
char m_aScreenshotName[IO_MAX_PATH_LENGTH];

CTextureHandle m_InvalidTexture;
CTextureHandle m_NullTexture;

std::vector<int> m_vTextureIndices;
size_t m_FirstFreeTexture;
Expand Down Expand Up @@ -968,7 +968,7 @@ class CGraphics_Threaded : public IEngineGraphics
int UnloadTexture(IGraphics::CTextureHandle *pIndex) override;
IGraphics::CTextureHandle LoadTextureRaw(size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData, int Flags, const char *pTexName = nullptr) override;
int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData) override;
IGraphics::CTextureHandle InvalidTexture() const override;
IGraphics::CTextureHandle NullTexture() const override;

bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData) override;
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
Expand Down
3 changes: 2 additions & 1 deletion src/engine/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class IGraphics : public IInterface
}

bool IsValid() const { return Id() >= 0; }
bool IsNullTexture() const { return Id() == 0; }
int Id() const { return m_Id; }
void Invalidate() { m_Id = -1; }
};
Expand Down Expand Up @@ -337,7 +338,7 @@ class IGraphics : public IInterface
virtual CTextureHandle LoadTextureRaw(size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData, int Flags, const char *pTexName = nullptr) = 0;
virtual int LoadTextureRawSub(CTextureHandle TextureID, int x, int y, size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData) = 0;
virtual CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) = 0;
virtual CTextureHandle InvalidTexture() const = 0;
virtual CTextureHandle NullTexture() const = 0;
virtual void TextureSet(CTextureHandle Texture) = 0;
void TextureClear() { TextureSet(CTextureHandle()); }

Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/mapimages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void CMapImages::OnMapLoadImpl(class CLayers *pLayers, IMap *pMap)
pMap->UnloadData(pImg->m_ImageData);
}
pMap->UnloadData(pImg->m_ImageName);
ShowWarning = ShowWarning || m_aTextures[i].Id() == Graphics()->InvalidTexture().Id();
ShowWarning = ShowWarning || m_aTextures[i].IsNullTexture();
}
if(ShowWarning)
{
Expand Down
79 changes: 28 additions & 51 deletions src/game/client/components/menu_background.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
#include <game/client/components/camera.h>
#include <game/client/components/mapimages.h>
#include <game/client/components/maplayers.h>
#include <game/client/gameclient.h>

#include <game/layers.h>
#include <game/localization.h>
#include <game/mapitems.h>

#include "menu_background.h"
Expand Down Expand Up @@ -89,6 +91,20 @@ void CMenuBackground::ResetPositions()
m_aPositions = GenerateMenuBackgroundPositions();
}

void CMenuBackground::LoadThemeIcon(CTheme &Theme)
{
char aIconPath[IO_MAX_PATH_LENGTH];
str_format(aIconPath, sizeof(aIconPath), "themes/%s.png", Theme.m_Name.empty() ? "none" : Theme.m_Name.c_str());
Theme.m_IconTexture = Graphics()->LoadTexture(aIconPath, IStorage::TYPE_ALL);

char aBuf[32 + IO_MAX_PATH_LENGTH];
if(Theme.m_IconTexture.IsNullTexture())
str_format(aBuf, sizeof(aBuf), "failed to load theme icon '%s'", aIconPath);
else
str_format(aBuf, sizeof(aBuf), "loaded theme icon '%s'", aIconPath);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "menuthemes", aBuf);
}

int CMenuBackground::ThemeScan(const char *pName, int IsDir, int DirType, void *pUser)
{
CMenuBackground *pSelf = (CMenuBackground *)pUser;
Expand Down Expand Up @@ -131,60 +147,17 @@ int CMenuBackground::ThemeScan(const char *pName, int IsDir, int DirType, void *
}

// make new theme
CTheme Theme(aThemeName, IsDay, IsNight);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "added theme %s from themes/%s", aThemeName, pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
pSelf->m_vThemes.push_back(Theme);
auto TimeNow = time_get_nanoseconds();
if(TimeNow - pSelf->m_ThemeScanStartTime >= std::chrono::nanoseconds(1s) / 60)
{
pSelf->Client()->UpdateAndSwap();
pSelf->m_ThemeScanStartTime = TimeNow;
}
return 0;
}

int CMenuBackground::ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser)
{
CMenuBackground *pSelf = (CMenuBackground *)pUser;
const char *pSuffix = str_endswith(pName, ".png");
if(IsDir || !pSuffix)
return 0;
str_format(aBuf, sizeof(aBuf), "added theme '%s' from 'themes/%s'", aThemeName, pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "menuthemes", aBuf);
pSelf->m_vThemes.emplace_back(aThemeName, IsDay, IsNight);
pSelf->LoadThemeIcon(pSelf->m_vThemes.back());

auto TimeNow = time_get_nanoseconds();
if(TimeNow - pSelf->m_ThemeScanStartTime >= std::chrono::nanoseconds(1s) / 60)
if(time_get_nanoseconds() - pSelf->m_ThemeScanStartTime > 500ms)
{
pSelf->Client()->UpdateAndSwap();
pSelf->m_ThemeScanStartTime = TimeNow;
pSelf->GameClient()->m_Menus.RenderLoading(Localize("Loading menu themes"), "", 0, false);
}

char aThemeName[128];
str_truncate(aThemeName, sizeof(aThemeName), pName, pSuffix - pName);

// save icon for an existing theme
for(CTheme &Theme : pSelf->m_vThemes) // bit slow but whatever
{
if(str_comp(Theme.m_Name.c_str(), aThemeName) == 0 || (Theme.m_Name.empty() && str_comp(aThemeName, "none") == 0))
{
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aBuf, sizeof(aBuf), "themes/%s", pName);
CImageInfo Info;
if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType))
{
str_format(aBuf, sizeof(aBuf), "failed to load theme icon from %s", pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
return 0;
}
str_format(aBuf, sizeof(aBuf), "loaded theme icon %s", pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);

Theme.m_IconTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
pSelf->Graphics()->FreePNG(&Info);
return 0;
}
}
return 0; // no existing theme
return 0;
}

void CMenuBackground::LoadMenuBackground(bool HasDayHint, bool HasNightHint)
Expand Down Expand Up @@ -408,12 +381,16 @@ std::vector<CTheme> &CMenuBackground::GetThemes()
{
// when adding more here, make sure to change the value of PREDEFINED_THEMES_COUNT too
m_vThemes.emplace_back("", true, true); // no theme
LoadThemeIcon(m_vThemes.back());

m_vThemes.emplace_back("auto", true, true); // auto theme
LoadThemeIcon(m_vThemes.back());

m_vThemes.emplace_back("rand", true, true); // random theme
LoadThemeIcon(m_vThemes.back());

m_ThemeScanStartTime = time_get_nanoseconds();
Storage()->ListDirectory(IStorage::TYPE_ALL, "themes", ThemeScan, this);
Storage()->ListDirectory(IStorage::TYPE_ALL, "themes", ThemeIconScan, this);

std::sort(m_vThemes.begin() + PREDEFINED_THEMES_COUNT, m_vThemes.end());
}
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/menu_background.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ class CMenuBackground : public CBackground

void ResetPositions();

void LoadThemeIcon(CTheme &Theme);
static int ThemeScan(const char *pName, int IsDir, int DirType, void *pUser);
static int ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser);

std::vector<CTheme> m_vThemes;

Expand Down
4 changes: 2 additions & 2 deletions src/game/client/components/menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2195,7 +2195,7 @@ int CMenus::MenuImageScan(const char *pName, int IsDir, int DirType, void *pUser
return 0;
}

MenuImage.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
MenuImage.m_OrgTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0);

// create gray scale version
unsigned char *pData = static_cast<unsigned char *>(Info.m_pData);
Expand All @@ -2207,7 +2207,7 @@ int CMenus::MenuImageScan(const char *pName, int IsDir, int DirType, void *pUser
pData[i * Step + 1] = v;
pData[i * Step + 2] = v;
}
MenuImage.m_GreyTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
MenuImage.m_GreyTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0);
pSelf->Graphics()->FreePNG(&Info);

str_truncate(MenuImage.m_aName, sizeof(MenuImage.m_aName), pName, str_length(pName) - str_length(pExtension));
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/menus_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int Stora

if(time_get_nanoseconds() - pSelf->m_DemoPopulateStartTime > 500ms)
{
pSelf->GameClient()->m_Menus.RenderLoading(Localize("Loading demo files"), "", 0, false);
pSelf->RenderLoading(Localize("Loading demo files"), "", 0, false);
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/menus_ingame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ int CMenus::GhostlistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int Stor

if(time_get_nanoseconds() - pSelf->m_GhostPopulateStartTime > 500ms)
{
pSelf->GameClient()->m_Menus.RenderLoading(Localize("Loading ghost files"), "", 0, false);
pSelf->RenderLoading(Localize("Loading ghost files"), "", 0, false);
}

return 0;
Expand Down
Loading

0 comments on commit b60b14b

Please sign in to comment.