mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-18 05:58:19 +00:00
Avoid copying texture memory when possible
Add separate `IGraphics::LoadTextureRawMove` function with non-`const` `void *pData` argument in addition to existing `LoadTextureRaw` function with `const void *pData` argument. The former function takes ownership of the data and avoids copying the texture data into an additional buffer, if the texture data is already in RGBA format. Non-RGBA texture data always needs to be converted and therefore also copied. The `LoadTextureRaw` function is split into smaller functions to share common code with the `LoadTextureRawMove` function. Alternatively to this, a flag `TEXLOAD_MOVE_DATA` could have been added to the existing `LoadTextureRaw` function, which would have required the use of `const_cast` to free the texture data.
This commit is contained in:
parent
022cae6f20
commit
abc7b602b2
|
@ -290,10 +290,7 @@ void CGraphics_Threaded::FreeTextureIndex(CTextureHandle *pIndex)
|
|||
|
||||
int CGraphics_Threaded::UnloadTexture(CTextureHandle *pIndex)
|
||||
{
|
||||
if(pIndex->Id() == m_NullTexture.Id())
|
||||
return 0;
|
||||
|
||||
if(!pIndex->IsValid())
|
||||
if(pIndex->IsNullTexture() || !pIndex->IsValid())
|
||||
return 0;
|
||||
|
||||
CCommandBuffer::SCommand_Texture_Destroy Cmd;
|
||||
|
@ -416,7 +413,7 @@ bool CGraphics_Threaded::IsSpriteTextureFullyTransparent(CImageInfo &FromImageIn
|
|||
return IsImageSubFullyTransparent(FromImageInfo, x, y, w, h);
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData, int Flags, const char *pTexName)
|
||||
static void LoadTextureAddWarning(size_t Width, size_t Height, int Flags, const char *pTexName, std::vector<SWarning> &vWarnings)
|
||||
{
|
||||
if((Flags & IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE) != 0 || (Flags & IGraphics::TEXLOAD_TO_3D_TEXTURE) != 0)
|
||||
{
|
||||
|
@ -424,30 +421,22 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(size_t Width, size_
|
|||
{
|
||||
SWarning NewWarning;
|
||||
char aText[128];
|
||||
aText[0] = '\0';
|
||||
if(pTexName)
|
||||
{
|
||||
str_format(aText, sizeof(aText), "\"%s\"", pTexName);
|
||||
}
|
||||
str_format(aText, sizeof(aText), "\"%s\"", pTexName ? pTexName : "(no name)");
|
||||
str_format(NewWarning.m_aWarningMsg, sizeof(NewWarning.m_aWarningMsg), Localize("The width of texture %s is not divisible by %d, or the height is not divisible by %d, which might cause visual bugs."), aText, 16, 16);
|
||||
|
||||
m_vWarnings.emplace_back(NewWarning);
|
||||
vWarnings.emplace_back(NewWarning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Width == 0 || Height == 0)
|
||||
return IGraphics::CTextureHandle();
|
||||
|
||||
IGraphics::CTextureHandle TextureHandle = FindFreeTextureIndex();
|
||||
|
||||
static CCommandBuffer::SCommand_Texture_Create LoadTextureCreateCommand(int TextureId, size_t Width, size_t Height, int Flags)
|
||||
{
|
||||
CCommandBuffer::SCommand_Texture_Create Cmd;
|
||||
Cmd.m_Slot = TextureHandle.Id();
|
||||
Cmd.m_Slot = TextureId;
|
||||
Cmd.m_Width = Width;
|
||||
Cmd.m_Height = Height;
|
||||
Cmd.m_Format = CCommandBuffer::TEXFORMAT_RGBA;
|
||||
Cmd.m_StoreFormat = CCommandBuffer::TEXFORMAT_RGBA;
|
||||
|
||||
// flags
|
||||
Cmd.m_Flags = 0;
|
||||
if(Flags & IGraphics::TEXLOAD_NOMIPMAPS)
|
||||
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NOMIPMAPS;
|
||||
|
@ -458,14 +447,51 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(size_t Width, size_
|
|||
if((Flags & IGraphics::TEXLOAD_NO_2D_TEXTURE) != 0)
|
||||
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NO_2D_TEXTURE;
|
||||
|
||||
// copy texture data
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData, int Flags, const char *pTexName)
|
||||
{
|
||||
LoadTextureAddWarning(Width, Height, Flags, pTexName, m_vWarnings);
|
||||
|
||||
if(Width == 0 || Height == 0)
|
||||
return IGraphics::CTextureHandle();
|
||||
|
||||
IGraphics::CTextureHandle TextureHandle = FindFreeTextureIndex();
|
||||
CCommandBuffer::SCommand_Texture_Create Cmd = LoadTextureCreateCommand(TextureHandle.Id(), Width, Height, Flags);
|
||||
|
||||
// Copy texture data and convert if necessary
|
||||
const size_t MemSize = Width * Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA);
|
||||
void *pTmpData = malloc(MemSize);
|
||||
if(!ConvertToRGBA((uint8_t *)pTmpData, (const uint8_t *)pData, Width, Height, Format))
|
||||
if(!ConvertToRGBA(static_cast<uint8_t *>(pTmpData), static_cast<const uint8_t *>(pData), Width, Height, Format))
|
||||
{
|
||||
dbg_msg("graphics", "converted image %s to RGBA, consider making its file format RGBA", pTexName ? pTexName : "(no name)");
|
||||
dbg_msg("graphics", "converted image '%s' to RGBA, consider making its file format RGBA", pTexName ? pTexName : "(no name)");
|
||||
}
|
||||
Cmd.m_pData = pTmpData;
|
||||
|
||||
AddCmd(Cmd);
|
||||
|
||||
return TextureHandle;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRawMove(size_t Width, size_t Height, CImageInfo::EImageFormat Format, void *pData, int Flags, const char *pTexName)
|
||||
{
|
||||
if(Format != CImageInfo::FORMAT_RGBA)
|
||||
{
|
||||
// Moving not possible, texture needs to be converted
|
||||
return LoadTextureRaw(Width, Height, Format, pData, Flags, pTexName);
|
||||
}
|
||||
|
||||
LoadTextureAddWarning(Width, Height, Flags, pTexName, m_vWarnings);
|
||||
|
||||
if(Width == 0 || Height == 0)
|
||||
return IGraphics::CTextureHandle();
|
||||
|
||||
IGraphics::CTextureHandle TextureHandle = FindFreeTextureIndex();
|
||||
CCommandBuffer::SCommand_Texture_Create Cmd = LoadTextureCreateCommand(TextureHandle.Id(), Width, Height, Flags);
|
||||
|
||||
Cmd.m_pData = pData;
|
||||
|
||||
AddCmd(Cmd);
|
||||
|
||||
return TextureHandle;
|
||||
|
@ -479,8 +505,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTexture(const char *pFilename,
|
|||
CImageInfo Img;
|
||||
if(LoadPNG(&Img, pFilename, StorageType))
|
||||
{
|
||||
CTextureHandle ID = LoadTextureRaw(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, Flags, pFilename);
|
||||
FreePNG(&Img);
|
||||
CTextureHandle ID = LoadTextureRawMove(Img.m_Width, Img.m_Height, Img.m_Format, Img.m_pData, Flags, pFilename);
|
||||
if(ID.IsValid())
|
||||
{
|
||||
if(g_Config.m_Debug)
|
||||
|
|
|
@ -951,6 +951,7 @@ public:
|
|||
void FreeTextureIndex(CTextureHandle *pIndex);
|
||||
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;
|
||||
IGraphics::CTextureHandle LoadTextureRawMove(size_t Width, size_t Height, CImageInfo::EImageFormat Format, 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 NullTexture() const override;
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ public:
|
|||
|
||||
virtual int UnloadTexture(CTextureHandle *pIndex) = 0;
|
||||
virtual CTextureHandle LoadTextureRaw(size_t Width, size_t Height, CImageInfo::EImageFormat Format, const void *pData, int Flags, const char *pTexName = nullptr) = 0;
|
||||
virtual CTextureHandle LoadTextureRawMove(size_t Width, size_t Height, CImageInfo::EImageFormat Format, 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 NullTexture() const = 0;
|
||||
|
|
|
@ -75,8 +75,7 @@ void CCountryFlags::LoadCountryflagsIndexfile()
|
|||
CCountryFlag CountryFlag;
|
||||
CountryFlag.m_CountryCode = CountryCode;
|
||||
str_copy(CountryFlag.m_aCountryCodeString, aOrigin);
|
||||
CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0, aOrigin);
|
||||
Graphics()->FreePNG(&Info);
|
||||
CountryFlag.m_Texture = Graphics()->LoadTextureRawMove(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0, aOrigin);
|
||||
|
||||
if(g_Config.m_Debug)
|
||||
{
|
||||
|
|
|
@ -445,10 +445,7 @@ IGraphics::CTextureHandle CMapImages::UploadEntityLayerText(int TextureSize, int
|
|||
UpdateEntityLayerText(pMem, PixelSize, Width, Height, TextureSize, MaxWidth, YOffset, 2, 255);
|
||||
|
||||
const int TextureLoadFlag = (Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE) | IGraphics::TEXLOAD_NO_2D_TEXTURE;
|
||||
IGraphics::CTextureHandle Texture = Graphics()->LoadTextureRaw(Width, Height, CImageInfo::FORMAT_RGBA, pMem, TextureLoadFlag);
|
||||
free(pMem);
|
||||
|
||||
return Texture;
|
||||
return Graphics()->LoadTextureRawMove(Width, Height, CImageInfo::FORMAT_RGBA, pMem, TextureLoadFlag);
|
||||
}
|
||||
|
||||
void CMapImages::UpdateEntityLayerText(void *pTexBuffer, size_t PixelSize, size_t TexWidth, size_t TexHeight, int TextureSize, int MaxWidth, int YOffset, int NumbersPower, int MaxNumber)
|
||||
|
|
|
@ -2197,8 +2197,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, 0);
|
||||
pSelf->Graphics()->FreePNG(&Info);
|
||||
MenuImage.m_GreyTexture = pSelf->Graphics()->LoadTextureRawMove(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0);
|
||||
|
||||
str_truncate(MenuImage.m_aName, sizeof(MenuImage.m_aName), pName, str_length(pName) - str_length(pExtension));
|
||||
pSelf->m_vMenuImages.push_back(MenuImage);
|
||||
|
|
|
@ -1908,8 +1908,8 @@ void CMenus::LoadCommunityIconFinish(const char *pCommunityId, CImageInfo &&Info
|
|||
pData[i * Step + 1] = v;
|
||||
pData[i * Step + 2] = v;
|
||||
}
|
||||
CommunityIcon.m_GreyTexture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0);
|
||||
Graphics()->FreePNG(&Info);
|
||||
CommunityIcon.m_GreyTexture = Graphics()->LoadTextureRawMove(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, 0);
|
||||
Info.m_pData = nullptr;
|
||||
|
||||
auto ExistingIcon = std::find_if(m_vCommunityIcons.begin(), m_vCommunityIcons.end(), [pCommunityId](const SCommunityIcon &Element) {
|
||||
return str_comp(Element.m_aCommunityId, pCommunityId) == 0;
|
||||
|
|
|
@ -5166,8 +5166,8 @@ void CEditor::RenderFileDialog()
|
|||
if(Graphics()->LoadPNG(&m_FilePreviewImageInfo, aBuffer, m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType))
|
||||
{
|
||||
Graphics()->UnloadTexture(&m_FilePreviewImage);
|
||||
m_FilePreviewImage = Graphics()->LoadTextureRaw(m_FilePreviewImageInfo.m_Width, m_FilePreviewImageInfo.m_Height, m_FilePreviewImageInfo.m_Format, m_FilePreviewImageInfo.m_pData, 0);
|
||||
Graphics()->FreePNG(&m_FilePreviewImageInfo);
|
||||
m_FilePreviewImage = Graphics()->LoadTextureRawMove(m_FilePreviewImageInfo.m_Width, m_FilePreviewImageInfo.m_Height, m_FilePreviewImageInfo.m_Format, m_FilePreviewImageInfo.m_pData, 0);
|
||||
m_FilePreviewImageInfo.m_pData = nullptr;
|
||||
m_FilePreviewState = PREVIEW_LOADED;
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in a new issue