- implemented a proper texture composition cache.

This will mostly ensure that each patch used for composition is only loaded once and automatically unloaded once no longer needed.
So far only for paletted rendering, but the same logic can be used for true color as well.
This commit is contained in:
Christoph Oelckers 2018-12-10 01:17:39 +01:00
parent 796c0fe931
commit 2e7bcf9e41
32 changed files with 367 additions and 60 deletions

View file

@ -373,7 +373,14 @@ void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
FHardwareTexture::UnbindAll();
}
FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
bool OpenGLFrameBuffer::CheckPrecacheMaterial(FMaterial *mat)
{
if (!mat->tex->GetImage()) return true;
auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0));
return base->Exists(0);
}
FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
{
return new FGLModelRenderer(nullptr, gl_RenderState, mli);
}

View file

@ -36,6 +36,7 @@ public:
void SetTextureFilterMode() override;
IHardwareTexture *CreateHardwareTexture(FTexture *tex) override;
void PrecacheMaterial(FMaterial *mat, int translation) override;
bool CheckPrecacheMaterial(FMaterial *mat) override;
FModelRenderer *CreateModelRenderer(int mli) override;
void TextureFilterChanged() override;
void BeginFrame() override;

View file

@ -467,4 +467,29 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i
return true;
}
//===========================================================================
//
// Binds a texture to the renderer
//
//===========================================================================
bool FHardwareTexture::Exists(int translation)
{
int usebright = false;
if (translation <= 0)
{
translation = -translation;
}
else
{
auto remap = TranslationToTable(translation);
translation = remap == nullptr ? 0 : remap->GetUniqueIndex();
}
TranslatedTexture *pTex = GetTexID(translation);
return (pTex->glTexID != 0);
}
}

View file

@ -81,6 +81,7 @@ public:
unsigned int Bind(int texunit, int translation, bool needmipmap);
bool BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags);
bool Exists(int translation);
void AllocateBuffer(int w, int h, int texelsize);
uint8_t *MapBuffer();

View file

@ -33,6 +33,7 @@
#include "r_data/models/models.h"
#include "textures/skyboxtexture.h"
#include "hwrenderer/textures/hw_material.h"
#include "image.h"
//==========================================================================
@ -189,6 +190,31 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
if (gl_precache)
{
FImageSource::BeginPrecaching();
// cache all used textures
for (int i = cnt - 1; i >= 0; i--)
{
FTexture *tex = TexMan.ByIndex(i);
if (tex != nullptr && tex->GetImage() != nullptr)
{
if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
{
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
if (gltex && !screen->CheckPrecacheMaterial(gltex))
{
FImageSource::RegisterForPrecache(tex->GetImage());
}
}
// Only register untranslated sprites. Translated ones are very unlikely to require data that can be reused.
if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CheckKey(0))
{
FImageSource::RegisterForPrecache(tex->GetImage());
}
}
}
// cache all used textures
for (int i = cnt - 1; i >= 0; i--)
{
@ -203,6 +229,9 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
}
}
FImageSource::EndPrecaching();
// cache all used models
FModelRenderer *renderer = screen->CreateModelRenderer(-1);
for (unsigned i = 0; i < Models.Size(); i++)

View file

@ -53,7 +53,7 @@ public:
FVoxelTexture(FVoxel *voxel);
int CopyPixels(FBitmap *bmp, int conversion) override;
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
protected:
FVoxel *SourceVox;
@ -79,7 +79,7 @@ FVoxelTexture::FVoxelTexture(FVoxel *vox)
//
//===========================================================================
TArray<uint8_t> FVoxelTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FVoxelTexture::CreatePalettedPixels(int conversion)
{
// GetPixels gets called when a translated palette is used so we still need to implement it here.
TArray<uint8_t> Pixels(256, true);

View file

@ -818,6 +818,7 @@ namespace swrenderer
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true);
mTopPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
if (mTopPart.Texture == nullptr) return;
mTopPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::top));
double rowoffset = sidedef->GetTextureYOffset(side_t::top);

View file

@ -51,6 +51,7 @@
#include "polyrenderer/poly_renderer.h"
#include "p_setup.h"
#include "g_levellocals.h"
#include "image.h"
// [BB] Use ZDoom's freelook limit for the sotfware renderer.
// Note: ZDoom's limit is chosen such that the sky is rendered properly.
@ -80,6 +81,25 @@ FRenderer *CreateSWRenderer()
return new FSoftwareRenderer;
}
void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache)
{
bool isbgra = V_IsTrueColor();
if (ttex != NULL && ttex->isValid())
{
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
if (tex->CheckPixels())
{
if (cache == 0) tex->Unload();
}
else if (cache != 0)
{
FImageSource::RegisterForPrecache(ttex->GetImage());
}
}
}
void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache)
{
bool isbgra = V_IsTrueColor();
@ -102,10 +122,6 @@ void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache)
else
tex->GetPixels (DefaultRenderStyle());
}
else
{
tex->Unload ();
}
}
}
@ -152,10 +168,18 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &
delete[] spritelist;
int cnt = TexMan.NumTextures();
FImageSource::BeginPrecaching();
for (int i = cnt - 1; i >= 0; i--)
{
PreparePrecache(TexMan.ByIndex(i), texhitlist[i]);
}
for (int i = cnt - 1; i >= 0; i--)
{
PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]);
}
FImageSource::EndPrecaching();
}
void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer)

View file

@ -27,6 +27,7 @@ struct FSoftwareRenderer : public FRenderer
void Init() override;
private:
void PreparePrecache(FTexture *tex, int cache);
void PrecacheTexture(FTexture *tex, int cache);
swrenderer::RenderScene mScene;

View file

@ -1,6 +1,6 @@
#pragma once
#include "textures/textures.h"
#include "v_video.h"
struct FSoftwareTextureSpan
{
@ -130,6 +130,12 @@ public:
return GetPixels(alpha);
}
// Checks if the pixel data is loaded.
bool CheckPixels() const
{
return V_IsTrueColor() ? PixelsBgra.Size() > 0 : Pixels.Size() > 0;
}
const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out)
{
bool alpha = !!(style.Flags & STYLEF_RedIsAlpha);

View file

@ -272,6 +272,18 @@ public:
return i;
}
template<class Func> const
unsigned int FindEx(Func compare) const
{
unsigned int i;
for (i = 0; i < Count; ++i)
{
if (compare(Array[i]))
break;
}
return i;
}
unsigned int Push (const T &item)
{
Grow (1);
@ -1019,7 +1031,7 @@ protected:
if (!nold[i].IsNil())
{
Node *n = NewKey(nold[i].Pair.Key);
::new(&n->Pair.Value) VT(nold[i].Pair.Value);
::new(&n->Pair.Value) VT(std::move(nold[i].Pair.Value));
nold[i].~Node();
}
}

View file

@ -52,7 +52,7 @@ class FAutomapTexture : public FImageSource
{
public:
FAutomapTexture(int lumpnum);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
@ -91,7 +91,7 @@ FAutomapTexture::FAutomapTexture (int lumpnum)
//
//==========================================================================
TArray<uint8_t> FAutomapTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FAutomapTexture::CreatePalettedPixels(int conversion)
{
int x, y;
FMemLump data = Wads.ReadLump (SourceLump);

View file

@ -57,7 +57,7 @@ class FBuildTexture : public FImageSource
{
public:
FBuildTexture (const FString &pathprefix, int tilenum, const uint8_t *pixels, int translation, int width, int height, int left, int top);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
int CopyPixels(FBitmap *bmp, int conversion) override;
protected:
@ -81,7 +81,7 @@ FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8
TopOffset = top;
}
TArray<uint8_t> FBuildTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FBuildTexture::CreatePalettedPixels(int conversion)
{
TArray<uint8_t> Pixels(Width * Height, true);
FRemapTable *Remap = translationtables[TRANSLATION_Standard][Translation];

View file

@ -164,7 +164,7 @@ class FDDSTexture : public FImageSource
public:
FDDSTexture (FileReader &lump, int lumpnum, void *surfdesc);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
protected:
uint32_t Format;
@ -372,7 +372,7 @@ void FDDSTexture::CalcBitShift (uint32_t mask, uint8_t *lshiftp, uint8_t *rshift
//
//==========================================================================
TArray<uint8_t> FDDSTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FDDSTexture::CreatePalettedPixels(int conversion)
{
auto lump = Wads.OpenLumpReader (SourceLump);

View file

@ -51,7 +51,7 @@ class FEmptyTexture : public FImageSource
{
public:
FEmptyTexture (int lumpnum);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
//==========================================================================
@ -91,7 +91,7 @@ FEmptyTexture::FEmptyTexture (int lumpnum)
//
//==========================================================================
TArray<uint8_t> FEmptyTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FEmptyTexture::CreatePalettedPixels(int conversion)
{
TArray<uint8_t> Pixel(1, true);
Pixel[0] = 0;

View file

@ -50,7 +50,7 @@ class FFlatTexture : public FImageSource
{
public:
FFlatTexture (int lumpnum);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
@ -104,7 +104,7 @@ FFlatTexture::FFlatTexture (int lumpnum)
//
//==========================================================================
TArray<uint8_t> FFlatTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FFlatTexture::CreatePalettedPixels(int conversion)
{
auto lump = Wads.OpenLumpReader (SourceLump);
TArray<uint8_t> Pixels(Width*Height, true);

View file

@ -68,12 +68,12 @@ FFontChar1::FFontChar1 (FImageSource *sourcelump)
//
//==========================================================================
TArray<uint8_t> FFontChar1::GetPalettedPixels (int)
TArray<uint8_t> FFontChar1::CreatePalettedPixels (int)
{
// Make the texture as normal, then remap it so that all the colors
// are at the low end of the palette
// Why? It only creates unnecessary work!
auto Pixels = BaseTexture->GetPalettedPixels(normal);
auto Pixels = BaseTexture->CreatePalettedPixels(normal);
if (SourceRemap)
{
@ -132,7 +132,7 @@ void FFontChar2::SetSourceRemap(const uint8_t *sourceremap)
//
//==========================================================================
TArray<uint8_t> FFontChar2::GetPalettedPixels(int)
TArray<uint8_t> FFontChar2::CreatePalettedPixels(int)
{
auto lump = Wads.OpenLumpReader (SourceLump);
int destSize = Width * Height;

View file

@ -5,7 +5,7 @@ class FFontChar1 : public FImageSource
{
public:
FFontChar1 (FImageSource *sourcelump);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
void SetSourceRemap(const uint8_t *sourceremap);
protected:
@ -20,7 +20,7 @@ class FFontChar2 : public FImageSource
public:
FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
void SetSourceRemap(const uint8_t *sourceremap);
protected:

View file

@ -68,7 +68,7 @@ class FIMGZTexture : public FImageSource
public:
FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool isalpha);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
int CopyPixels(FBitmap *bmp, int conversion) override;
};
@ -120,7 +120,7 @@ FIMGZTexture::FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int1
//
//==========================================================================
TArray<uint8_t> FIMGZTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FIMGZTexture::CreatePalettedPixels(int conversion)
{
FMemLump lump = Wads.ReadLump (SourceLump);
const ImageHeader *imgz = (const ImageHeader *)lump.GetMem();

View file

@ -186,7 +186,7 @@ public:
FJPEGTexture (int lumpnum, int width, int height);
int CopyPixels(FBitmap *bmp, int conversion) override;
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
//==========================================================================
@ -260,7 +260,7 @@ FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height)
//
//==========================================================================
TArray<uint8_t> FJPEGTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FJPEGTexture::CreatePalettedPixels(int conversion)
{
auto lump = Wads.OpenLumpReader (SourceLump);
JSAMPLE *buff = NULL;

View file

@ -53,6 +53,7 @@
#include "image.h"
#include "multipatchtexture.h"
//==========================================================================
//
// FMultiPatchTexture :: FMultiPatchTexture
@ -142,7 +143,8 @@ static uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork)
void FMultiPatchTexture::CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style)
{
auto image = source->GetPalettedPixels(style); // should use composition cache
auto cimage = source->GetCachedPalettedPixels(style); // should use composition cache
auto &image = cimage.Pixels;
const uint8_t *pixels = image.Data();
int srcwidth = source->GetWidth();
int srcheight = source->GetHeight();
@ -188,7 +190,7 @@ void FMultiPatchTexture::CopyToBlock(uint8_t *dest, int dwidth, int dheight, FIm
//
//==========================================================================
TArray<uint8_t> FMultiPatchTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FMultiPatchTexture::CreatePalettedPixels(int conversion)
{
int numpix = Width * Height;
uint8_t blendwork[256];
@ -324,3 +326,29 @@ int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion)
return retv;
}
//==========================================================================
//
//
//
//==========================================================================
void FMultiPatchTexture::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor)
{
FImageSource::CollectForPrecache(info, requiretruecolor);
if (!requiretruecolor)
{
requiretruecolor = bComplex;
if (!requiretruecolor) for (int i = 0; i < NumParts; ++i)
{
if (Parts[i].op != OP_COPY) requiretruecolor = true;
}
}
for (int i = 0; i < NumParts; ++i)
{
Parts[i].Image->CollectForPrecache(info, requiretruecolor);
}
}

View file

@ -39,8 +39,10 @@ protected:
// The getters must optionally redirect if it's a simple one-patch texture.
int CopyPixels(FBitmap *bmp, int conversion) override;
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
void CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style);
void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor);
};

View file

@ -64,7 +64,7 @@ class FPatchTexture : public FImageSource
bool isalpha = false;
public:
FPatchTexture (int lumpnum, patch_t *header, bool isalphatex);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
int CopyPixels(FBitmap *bmp, int conversion) override;
void DetectBadPatches();
};
@ -163,7 +163,7 @@ FPatchTexture::FPatchTexture (int lumpnum, patch_t * header, bool isalphatex)
//
//==========================================================================
TArray<uint8_t> FPatchTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FPatchTexture::CreatePalettedPixels(int conversion)
{
uint8_t *remap, remaptable[256];
int numspans;

View file

@ -93,7 +93,7 @@ protected:
void ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr);
void ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr, int planes);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
@ -358,7 +358,7 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr
//
//==========================================================================
TArray<uint8_t> FPCXTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FPCXTexture::CreatePalettedPixels(int conversion)
{
uint8_t PaletteMap[256];
PCXHeader header;

View file

@ -55,7 +55,7 @@ public:
~FPNGTexture();
int CopyPixels(FBitmap *bmp, int conversion) override;
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
protected:
void ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap);
@ -367,7 +367,7 @@ void FPNGTexture::ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap)
//
//==========================================================================
TArray<uint8_t> FPNGTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FPNGTexture::CreatePalettedPixels(int conversion)
{
FileReader *lump;
FileReader lfr;

View file

@ -54,7 +54,7 @@ class FRawPageTexture : public FImageSource
int mPaletteLump = -1;
public:
FRawPageTexture (int lumpnum);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
int CopyPixels(FBitmap *bmp, int conversion) override;
};
@ -173,7 +173,7 @@ FRawPageTexture::FRawPageTexture (int lumpnum)
//
//==========================================================================
TArray<uint8_t> FRawPageTexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FRawPageTexture::CreatePalettedPixels(int conversion)
{
FMemLump lump = Wads.ReadLump (SourceLump);
const uint8_t *source = (const uint8_t *)lump.GetMem();

View file

@ -100,7 +100,7 @@ public:
}
}
TArray<uint8_t> GetPalettedPixels(int conversion) override
TArray<uint8_t> CreatePalettedPixels(int conversion) override
{
TArray<uint8_t> Pix(512, true);
if (conversion == luminance)

View file

@ -85,7 +85,7 @@ public:
protected:
void ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel);
TArray<uint8_t> GetPalettedPixels(int conversion) override;
TArray<uint8_t> CreatePalettedPixels(int conversion) override;
};
//==========================================================================
@ -179,7 +179,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe
//
//==========================================================================
TArray<uint8_t> FTGATexture::GetPalettedPixels(int conversion)
TArray<uint8_t> FTGATexture::CreatePalettedPixels(int conversion)
{
uint8_t PaletteMap[256];
auto lump = Wads.OpenLumpReader (SourceLump);

View file

@ -43,6 +43,24 @@
FMemArena FImageSource::ImageArena(32768);
TArray<FImageSource *>FImageSource::ImageForLump;
int FImageSource::NextID;
static PrecacheInfo precacheInfo;
struct PrecacheDataPaletted
{
TArray<uint8_t> Pixels;
int RefCount;
int ImageID;
};
struct PrecacheDataRgba
{
FBitmap Pixels;
int ImageID;
};
// TMap doesn't handle this kind of data well. std::map neither. The linear search is still faster, even for a few 100 entries because it doesn't have to access the heap as often..
TArray<PrecacheDataPaletted> precacheDataPaletted;
TArray<PrecacheDataRgba> precacheDataRgba;
//===========================================================================
//
@ -50,13 +68,97 @@ int FImageSource::NextID;
//
//===========================================================================
TArray<uint8_t> FImageSource::GetPalettedPixels(int conversion)
TArray<uint8_t> FImageSource::CreatePalettedPixels(int conversion)
{
TArray<uint8_t> Pixels(Width * Height, true);
memset(Pixels.Data(), 0, Width * Height);
return Pixels;
}
PalettedPixels FImageSource::GetCachedPalettedPixels(int conversion)
{
PalettedPixels ret;
FString name;
Wads.GetLumpName(name, SourceLump);
if (name.CompareNoCase("W_136") == 0)
{
int a = 0;
}
std::pair<int, int> *info = nullptr;
auto imageID = ImageID;
// Do we have this image in the cache?
unsigned index = precacheDataPaletted.FindEx([=](PrecacheDataPaletted &entry) { return entry.ImageID == imageID; });
if (index < precacheDataPaletted.Size())
{
auto cache = &precacheDataPaletted[index];
if (cache->RefCount > 1)
{
Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount);
ret.Pixels.Set(cache->Pixels.Data(), cache->Pixels.Size());
cache->RefCount--;
}
else if (cache->Pixels.Size() > 0)
{
Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount);
ret.PixelStore = std::move(cache->Pixels);
ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size());
precacheDataPaletted.Delete(index);
}
else
{
Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount);
}
}
else
{
// The image wasn't cached. Now there's two possibilities:
auto info = precacheInfo.CheckKey(ImageID);
if (!info || info->second <= 1 || conversion != normal)
{
// This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it.
Printf("returning fresh copy of %s\n", name.GetChars());
ret.PixelStore = CreatePalettedPixels(conversion);
ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size());
}
else
{
Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->second);
// This is the first time it gets accessed and needs to be placed in the cache.
PrecacheDataPaletted *pdp = &precacheDataPaletted[precacheDataPaletted.Reserve(1)];
pdp->ImageID = imageID;
pdp->RefCount = info->second - 1;
info->second = 0;
pdp->Pixels = CreatePalettedPixels(normal);
ret.Pixels.Set(pdp->Pixels.Data(), pdp->Pixels.Size());
}
}
return ret;
}
TArray<uint8_t> FImageSource::GetPalettedPixels(int conversion)
{
auto pix = GetCachedPalettedPixels(conversion);
if (pix.ownsPixels())
{
// return the pixel store of the returned data directly if this was the last reference.
auto array = std::move(pix.PixelStore);
return array;
}
else
{
// If there are pending references, make a copy.
TArray<uint8_t> array(pix.Pixels.Size(), true);
memcpy(array.Data(), pix.Pixels.Data(), array.Size());
return array;
}
}
//===========================================================================
//
@ -75,7 +177,7 @@ int FImageSource::CopyPixels(FBitmap *bmp, int conversion)
if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source.
PalEntry *palette = screen->GetPalette();
for(int i=1;i<256;i++) palette[i].a = 255; // set proper alpha values
auto ppix = GetPalettedPixels(conversion); // should use composition cache
auto ppix = CreatePalettedPixels(conversion);
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr);
for(int i=1;i<256;i++) palette[i].a = 0;
return 0;
@ -83,11 +185,54 @@ int FImageSource::CopyPixels(FBitmap *bmp, int conversion)
int FImageSource::CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap)
{
auto ppix = GetPalettedPixels(false); // should use composition cache
auto ppix = CreatePalettedPixels(false);
bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, remap, nullptr);
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
void FImageSource::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor)
{
auto val = info.CheckKey(ImageID);
bool tc = requiretruecolor || V_IsTrueColor();
if (val)
{
val->first += tc;
val->second += !tc;
}
else
{
auto pair = std::make_pair(tc, !tc);
info.Insert(ImageID, pair);
}
}
void FImageSource::BeginPrecaching()
{
precacheInfo.Clear();
}
void FImageSource::EndPrecaching()
{
precacheDataPaletted.Clear();
precacheDataRgba.Clear();
}
void FImageSource::RegisterForPrecache(FImageSource *img)
{
img->CollectForPrecache(precacheInfo);
}
FBitmap FImageSource::GetPixelsWithCache(int conversion)
{
return FBitmap();
}
//==========================================================================
//

View file

@ -5,6 +5,21 @@
#include "textures/bitmap.h"
#include "memarena.h"
class FImageSource;
using PrecacheInfo = TMap<int, std::pair<int, int>>;
struct PalettedPixels
{
friend class FImageSource;
TArrayView<uint8_t> Pixels;
private:
TArray<uint8_t> PixelStore;
bool ownsPixels() const
{
return Pixels.Data() == PixelStore.Data();
}
};
// This represents a naked image. It has no high level logic attached to it.
// All it can do is provide raw image data to its users.
@ -41,13 +56,27 @@ public:
bool bMasked = true; // Image (might) have holes (Assume true unless proven otherwise!)
int8_t bTranslucent = -1; // Image has pixels with a non-0/1 value. (-1 means the user needs to do a real check)
// Returns the whole texture, paletted and true color versions respectively.
virtual TArray<uint8_t> GetPalettedPixels(int conversion); // 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture.
// 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture.
// Always creates a new pixel buffer for the texture
virtual TArray<uint8_t> CreatePalettedPixels(int conversion);
// Either returns a reference to the cache, or a newly created item. The return of this has to be considered transient. If you need to store the result, use GetPalettedPixels
PalettedPixels GetCachedPalettedPixels(int conversion);
// tries to get a buffer from the cache. If not available, create a new one. If further references are pending, create a copy.
TArray<uint8_t> GetPalettedPixels(int conversion);
virtual int CopyPixels(FBitmap *bmp, int conversion); // This will always ignore 'luminance'.
int CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap);
static void ClearImages() { ImageArena.FreeAll(); ImageForLump.Clear(); NextID = 0; }
static FImageSource * FImageSource::GetImage(int lumpnum, ETextureType usetype);
// These functions either allocate a new buffer or reuse the last one, if its reference count was greater than 1 when last used.
FBitmap GetPixelsWithCache(int conversion);
// Conversion option
enum EType
{
@ -59,9 +88,6 @@ public:
FImageSource(int sourcelump = -1) : SourceLump(sourcelump) { ImageID = ++NextID; }
virtual ~FImageSource() {}
// Creates an image from the given lump.
static FImageSource *CreateImageSource(int lumpnum);
int GetWidth() const
{
return Width;
@ -91,6 +117,11 @@ public:
{
return bUseGamePalette;
}
virtual void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor = false);
static void BeginPrecaching();
static void EndPrecaching();
static void RegisterForPrecache(FImageSource *img);
};
//==========================================================================

View file

@ -307,14 +307,6 @@ public:
/*virtual*/ FBitmap GetBgraBitmap(PalEntry *remap, int *trans = nullptr);
public:
/*
static void FlipSquareBlock (uint8_t *block, int x, int y);
static void FlipSquareBlockBgra (uint32_t *block, int x, int y);
static void FlipSquareBlockRemap (uint8_t *block, int x, int y, const uint8_t *remap);
static void FlipNonSquareBlock (uint8_t *blockto, const uint8_t *blockfrom, int x, int y, int srcpitch);
static void FlipNonSquareBlockBgra (uint32_t *blockto, const uint32_t *blockfrom, int x, int y, int srcpitch);
static void FlipNonSquareBlockRemap (uint8_t *blockto, const uint8_t *blockfrom, int x, int y, int srcpitch, const uint8_t *remap);
*/
static bool SmoothEdges(unsigned char * buffer,int w, int h);
static PalEntry averageColor(const uint32_t *data, int size, int maxout);
@ -436,7 +428,7 @@ protected:
virtual void ResolvePatches() {}
virtual void SetFrontSkyLayer();
void SetFrontSkyLayer();
static void InitGrayMap();
@ -645,11 +637,12 @@ private:
TArray<int> FirstTextureForFile;
TArray<TArray<uint8_t> > BuildTileData;
TArray<FAnimDef *> mAnimations;
TArray<FSwitchDef *> mSwitchDefs;
TArray<FDoorAnimation> mAnimatedDoors;
public:
TArray<FAnimDef *> mAnimations;
bool HasGlobalBrightmap;
FRemapTable GlobalBrightmap;
short sintable[2048]; // for texture warping

View file

@ -428,6 +428,7 @@ public:
virtual void CleanForRestart() {}
virtual void SetTextureFilterMode() {}
virtual IHardwareTexture *CreateHardwareTexture(FTexture *tex) { return nullptr; }
virtual bool CheckPrecacheMaterial(FMaterial *mat) { return true; }
virtual void PrecacheMaterial(FMaterial *mat, int translation) {}
virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; }
virtual void UnbindTexUnit(int no) {}