2666: Non divisible by 16 texture resize and warning r=heinrich5991 a=Jupeyy



Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
bors[bot] 2020-08-29 15:25:35 +00:00 committed by GitHub
commit 3101747d46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 182 additions and 16 deletions

View file

@ -706,11 +706,31 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
p3DImageData = (uint8_t*)malloc(ImageColorChannels * Width * Height);
int Image3DWidth, Image3DHeight;
if(IsSingleLayer || (Width != 0 && Width % 16 == 0 && Height != 0 && Height % 16 == 0 && Texture2DTo3D(pTexData, Width, Height, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight)))
int ConvertWidth = Width;
int ConvertHeight = Height;
if(!IsSingleLayer)
{
if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0)
{
dbg_msg("gfx", "3D/2D array texture was resized");
int NewWidth = maximum<int>(HighestBit(ConvertWidth), 16);
int NewHeight = maximum<int>(HighestBit(ConvertHeight), 16);
uint8_t* pNewTexData = (uint8_t*)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t*)pTexData);
ConvertWidth = NewWidth;
ConvertHeight = NewHeight;
free(pTexData);
pTexData = pNewTexData;
}
}
if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight)))
{
if(IsSingleLayer)
{
glTexImage3D(Target, 0, StoreOglformat, Width, Height, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
glTexImage3D(Target, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
}
else
{
@ -2253,11 +2273,31 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe
p3DImageData = (uint8_t*)malloc(ImageColorChannels * Width * Height);
int Image3DWidth, Image3DHeight;
if(IsSingleLayer || (Width != 0 && Width % 16 == 0 && Height != 0 && Height % 16 == 0 && Texture2DTo3D(pTexData, Width, Height, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight)))
int ConvertWidth = Width;
int ConvertHeight = Height;
if(!IsSingleLayer)
{
if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0)
{
dbg_msg("gfx", "3D/2D array texture was resized");
int NewWidth = maximum<int>(HighestBit(ConvertWidth), 16);
int NewHeight = maximum<int>(HighestBit(ConvertHeight), 16);
uint8_t* pNewTexData = (uint8_t*)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t*)pTexData);
ConvertWidth = NewWidth;
ConvertHeight = NewHeight;
free(pTexData);
pTexData = pNewTexData;
}
}
if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight)))
{
if(IsSingleLayer)
{
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, Width, Height, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
}
else
{

View file

@ -408,7 +408,7 @@ int CGraphics_Threaded::LoadTextureRawSub(CTextureHandle TextureID, int x, int y
return 0;
}
IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags)
IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags, const char *pTexName)
{
// don't waste memory on texture if we are stress testing
#ifdef CONF_DEBUG
@ -448,6 +448,27 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
if((Flags&IGraphics::TEXLOAD_NO_2D_TEXTURE) != 0)
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NO_2D_TEXTURE;
if((Flags&IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE) != 0 || (Flags&IGraphics::TEXLOAD_TO_3D_TEXTURE) != 0)
{
if(Width == 0 || (Width % 16) != 0 || Height == 0 || (Height % 16) != 0)
{
SGraphicsWarning NewWarning;
char aText[128];
if(pTexName && *pTexName)
{
str_format(aText, sizeof(aText), ":\n\"%s\"\n", pTexName);
}
else
{
aText[0] = ' ';
aText[1] = 0;
}
str_format(NewWarning.m_aWarningMsg, sizeof(NewWarning.m_aWarningMsg), "The width and height of texture%sare not divisible by 16, which might cause visual bugs.", aText);
m_Warnings.emplace_back(NewWarning);
}
}
// copy texture data
int MemSize = Width*Height*Cmd.m_PixelSize;
void *pTmpData = malloc(MemSize);
@ -479,7 +500,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTexture(const char *pFilename,
if(StoreFormat == CImageInfo::FORMAT_AUTO)
StoreFormat = Img.m_Format;
ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, StoreFormat, Flags);
ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, StoreFormat, Flags, pFilename);
free(Img.m_pData);
if(ID != m_InvalidTexture && g_Config.m_Debug)
dbg_msg("graphics/texture", "loaded %s", pFilename);
@ -2318,6 +2339,15 @@ void CGraphics_Threaded::TakeCustomScreenshot(const char *pFilename)
void CGraphics_Threaded::Swap()
{
if(!m_Warnings.empty())
{
SGraphicsWarning* pCurWarning = GetCurWarning();
if(pCurWarning->m_WasShown)
{
m_Warnings.erase(m_Warnings.begin());
}
}
// TODO: screenshot support
if(m_DoScreenshot)
{
@ -2371,6 +2401,17 @@ void CGraphics_Threaded::WaitForIdle()
m_pBackend->WaitForIdle();
}
SGraphicsWarning *CGraphics_Threaded::GetCurWarning()
{
if(m_Warnings.empty())
return NULL;
else
{
SGraphicsWarning* pCurWarning = &m_Warnings[0];
return pCurWarning;
}
}
int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen)
{
if(g_Config.m_GfxDisplayAllModes)

View file

@ -663,6 +663,8 @@ class CGraphics_Threaded : public IEngineGraphics
int m_FirstFreeTexture;
int m_TextureMemoryUsage;
std::vector<SGraphicsWarning> m_Warnings;
struct SVertexArrayInfo
{
SVertexArrayInfo() : m_FreeIndex(-1) {}
@ -742,7 +744,7 @@ public:
virtual void LinesDraw(const CLineItem *pArray, int Num);
virtual int UnloadTexture(IGraphics::CTextureHandle Index);
virtual IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags);
virtual IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags, const char *pTexName = NULL);
virtual int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData);
// simple uncompressed RGBA loaders
@ -851,6 +853,8 @@ public:
virtual bool IsIdle();
virtual void WaitForIdle();
virtual SGraphicsWarning *GetCurWarning();
virtual bool IsTileBufferingEnabled() { return m_OpenGLTileBufferingEnabled; }
virtual bool IsQuadBufferingEnabled() { return m_OpenGLQuadBufferingEnabled; }
virtual bool IsTextBufferingEnabled() { return m_OpenGLTextBufferingEnabled; }

View file

@ -6,6 +6,7 @@
#include "kernel.h"
#include <base/color.h>
#include <stddef.h>
#include <vector>
#define GRAPHICS_TYPE_UNSIGNED_BYTE 0x1401
@ -116,6 +117,13 @@ struct GL_SVertexTex3D
GL_STexCoord3D m_Tex;
};
struct SGraphicsWarning
{
SGraphicsWarning() : m_WasShown(false) {}
char m_aWarningMsg[128];
bool m_WasShown;
};
typedef void(*WINDOW_RESIZE_FUNC)(void *pUser);
class IGraphics : public IInterface
@ -186,7 +194,7 @@ public:
virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) = 0;
virtual int UnloadTexture(CTextureHandle Index) = 0;
virtual CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) = 0;
virtual CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags, const char *pTexName = NULL) = 0;
virtual int LoadTextureRawSub(CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData) = 0;
virtual CTextureHandle LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) = 0;
virtual void TextureSet(CTextureHandle Texture) = 0;
@ -309,6 +317,7 @@ public:
virtual void SetWindowGrab(bool Grab) = 0;
virtual void NotifyWindow() = 0;
virtual SGraphicsWarning *GetCurWarning() = 0;
protected:
inline CTextureHandle CreateTextureHandle(int Index)
{

View file

@ -116,6 +116,7 @@ MACRO_CONFIG_INT(GfxTextOverlay, gfx_text_overlay, 10, 1, 100, CFGFLAG_SAVE|CFGF
MACRO_CONFIG_INT(GfxAsyncRenderOld, gfx_asyncrender_old, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Do rendering async from the the update")
MACRO_CONFIG_INT(GfxTuneOverlay, gfx_tune_overlay, 20, 1, 100, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Stop rendering text overlay in tuning zone in editor: high value = less details = more speed")
MACRO_CONFIG_INT(GfxQuadAsTriangle, gfx_quad_as_triangle, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Render quads as triangles (fixes quad coloring on some GPUs)")
MACRO_CONFIG_INT(GfxShowWarnings, gfx_show_warnings, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Render gfx warnings to screen")
MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 200, 1, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity")
MACRO_CONFIG_INT(InpMouseOld, inp_mouseold, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Use old mouse mode (warp mouse instead of raw input)")

View file

@ -90,7 +90,10 @@ void CMapImages::OnMapLoadImpl(class CLayers *pLayers, IMap *pMap)
else
{
void *pData = pMap->GetData(pImg->m_ImageData);
m_aTextures[i] = Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, CImageInfo::FORMAT_RGBA, pData, CImageInfo::FORMAT_RGBA, LoadFlag);
char *pName = (char *)pMap->GetData(pImg->m_ImageName);
char aTexName[128];
str_format(aTexName, sizeof(aTexName), "%s %s", "embedded:", pName);
m_aTextures[i] = Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, CImageInfo::FORMAT_RGBA, pData, CImageInfo::FORMAT_RGBA, LoadFlag, aTexName);
pMap->UnloadData(pImg->m_ImageData);
}
}

View file

@ -974,12 +974,33 @@ void CMenus::PopupMessage(const char *pTopic, const char *pBody, const char *pBu
str_copy(m_aMessageTopic, pTopic, sizeof(m_aMessageTopic));
str_copy(m_aMessageBody, pBody, sizeof(m_aMessageBody));
str_copy(m_aMessageButton, pButton, sizeof(m_aMessageButton));
m_Popup = POPUP_MESSAGE;
}
void CMenus::PopupWarning(const char *pTopic, const char *pBody, const char *pButton, int64 Duration)
{
// reset active item
UI()->SetActiveItem(0);
str_copy(m_aMessageTopic, pTopic, sizeof(m_aMessageTopic));
str_copy(m_aMessageBody, pBody, sizeof(m_aMessageBody));
str_copy(m_aMessageButton, pButton, sizeof(m_aMessageButton));
m_Popup = POPUP_WARNING;
SetActive(true);
m_PopupWarningDuration = Duration;
m_PopupWarningLastTime = time_get_microseconds();
}
bool CMenus::CanDisplayWarning()
{
return m_Popup == POPUP_NONE && (Client()->State() == IClient::STATE_DEMOPLAYBACK || Client()->State() == IClient::STATE_ONLINE);
}
int CMenus::Render()
{
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_Popup == POPUP_NONE)
return 0;
CUIRect Screen = *UI()->Screen();
Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h);
@ -1008,7 +1029,7 @@ int CMenus::Render()
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
}
if(Client()->State() == IClient::STATE_ONLINE)
if(Client()->State() >= IClient::STATE_ONLINE)
{
ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame;
ms_ColorTabbarActive = ms_ColorTabbarActiveIngame;
@ -1095,6 +1116,7 @@ int CMenus::Render()
const char *pButtonText = "";
int ExtraAlign = 0;
ColorRGBA BgColor = ColorRGBA{0.0f, 0.0f, 0.0f, 0.5f};
if(m_Popup == POPUP_MESSAGE)
{
pTitle = m_aMessageTopic;
@ -1213,6 +1235,14 @@ int CMenus::Render()
pButtonText = Localize("Ok");
ExtraAlign = -1;
}
else if(m_Popup == POPUP_WARNING)
{
BgColor = ColorRGBA{0.5f, 0.0f, 0.0f, 0.7f};
pTitle = m_aMessageTopic;
pExtraText = m_aMessageBody;
pButtonText = m_aMessageButton;
ExtraAlign = -1;
}
CUIRect Box, Part;
Box = Screen;
@ -1223,7 +1253,7 @@ int CMenus::Render()
}
// render the box
RenderTools()->DrawUIRect(&Box, ColorRGBA(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f);
RenderTools()->DrawUIRect(&Box, BgColor, CUI::CORNER_ALL, 15.0f);
Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box);
Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box);
@ -1807,6 +1837,19 @@ int CMenus::Render()
static float Offset = 0.0f;
DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &Offset, false, CUI::CORNER_ALL, Client()->PlayerName());
}
else if(m_Popup == POPUP_WARNING)
{
Box.HSplitBottom(20.f, &Box, &Part);
Box.HSplitBottom(24.f, &Box, &Part);
Part.VMargin(120.0f, &Part);
static int s_Button = 0;
if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed || (time_get_microseconds() - m_PopupWarningLastTime >= m_PopupWarningDuration))
{
m_Popup = POPUP_NONE;
SetActive(false);
}
}
else
{
Box.HSplitBottom(20.f, &Box, &Part);
@ -1954,8 +1997,11 @@ void CMenus::OnStateChange(int NewState, int OldState)
m_Popup = POPUP_CONNECTING;
else if(NewState == IClient::STATE_ONLINE || NewState == IClient::STATE_DEMOPLAYBACK)
{
m_Popup = POPUP_NONE;
SetActive(false);
if(m_Popup != POPUP_WARNING)
{
m_Popup = POPUP_NONE;
SetActive(false);
}
}
}
@ -2025,8 +2071,7 @@ void CMenus::OnRender()
UI()->Update(mx,my,mx*3.0f,my*3.0f,Buttons);
// render
if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
Render();
Render();
// render cursor
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id);

View file

@ -396,6 +396,13 @@ public:
void DeleteGhostItem(int Index);
void setPopup(int Popup) { m_Popup = Popup; }
int GetCurPopup() { return m_Popup; }
bool CanDisplayWarning();
void PopupWarning(const char *pTopic, const char *pBody, const char *pButton, int64 Duration);
int64 m_PopupWarningLastTime;
int64 m_PopupWarningDuration;
int m_DemoPlayerState;
char m_aDemoPlayerPopupHint[256];
@ -420,6 +427,7 @@ public:
POPUP_QUIT,
POPUP_DISCONNECT,
POPUP_DISCONNECT_DUMMY,
POPUP_WARNING,
// demo player states
DEMOPLAYER_NONE=0,

View file

@ -623,6 +623,21 @@ void CGameClient::OnRender()
// update the local character and spectate position
UpdatePositions();
// display gfx warnings
if(g_Config.m_GfxShowWarnings == 1)
{
SGraphicsWarning* pWarning = Graphics()->GetCurWarning();
if(pWarning != NULL)
{
if(m_pMenus->CanDisplayWarning())
{
m_pMenus->PopupWarning("Warning!", pWarning->m_aWarningMsg, "Ok", 10000000);
pWarning->m_WasShown = true;
}
}
}
// render all systems
for(int i = 0; i < m_All.m_Num; i++)
m_All.m_paComponents[i]->OnRender();