diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 314426ff0..050ff41ff 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -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(mat->GetLayer(0)); + return base->Exists(0); +} + +FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) { return new FGLModelRenderer(nullptr, gl_RenderState, mli); } diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index c2a26650f..72ec2a9c2 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -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; diff --git a/src/gl/textures/gl_hwtexture.cpp b/src/gl/textures/gl_hwtexture.cpp index f6cdc8415..f3c78b6e6 100644 --- a/src/gl/textures/gl_hwtexture.cpp +++ b/src/gl/textures/gl_hwtexture.cpp @@ -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); +} + + } diff --git a/src/gl/textures/gl_hwtexture.h b/src/gl/textures/gl_hwtexture.h index 6c693a998..f864d073b 100644 --- a/src/gl/textures/gl_hwtexture.h +++ b/src/gl/textures/gl_hwtexture.h @@ -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(); diff --git a/src/hwrenderer/textures/hw_precache.cpp b/src/hwrenderer/textures/hw_precache.cpp index 492610a7c..b927463a2 100644 --- a/src/hwrenderer/textures/hw_precache.cpp +++ b/src/hwrenderer/textures/hw_precache.cpp @@ -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 &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 &actorhitl } } + + FImageSource::EndPrecaching(); + // cache all used models FModelRenderer *renderer = screen->CreateModelRenderer(-1); for (unsigned i = 0; i < Models.Size(); i++) diff --git a/src/r_data/models/models_voxel.cpp b/src/r_data/models/models_voxel.cpp index 1774354bf..8cda437bc 100644 --- a/src/r_data/models/models_voxel.cpp +++ b/src/r_data/models/models_voxel.cpp @@ -53,7 +53,7 @@ public: FVoxelTexture(FVoxel *voxel); int CopyPixels(FBitmap *bmp, int conversion) override; - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; protected: FVoxel *SourceVox; @@ -79,7 +79,7 @@ FVoxelTexture::FVoxelTexture(FVoxel *vox) // //=========================================================================== -TArray FVoxelTexture::GetPalettedPixels(int conversion) +TArray FVoxelTexture::CreatePalettedPixels(int conversion) { // GetPixels gets called when a translated palette is used so we still need to implement it here. TArray Pixels(256, true); diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index c3bc08d9f..0a376c791 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -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); diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index 721873da1..9cd3fb309 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -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 & 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) diff --git a/src/swrenderer/r_swrenderer.h b/src/swrenderer/r_swrenderer.h index 864cbb665..b9bb28019 100644 --- a/src/swrenderer/r_swrenderer.h +++ b/src/swrenderer/r_swrenderer.h @@ -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; diff --git a/src/swrenderer/textures/r_swtexture.h b/src/swrenderer/textures/r_swtexture.h index 3dd534624..791619e77 100644 --- a/src/swrenderer/textures/r_swtexture.h +++ b/src/swrenderer/textures/r_swtexture.h @@ -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); diff --git a/src/tarray.h b/src/tarray.h index bdbb7bb82..f580ae3e4 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -272,6 +272,18 @@ public: return i; } + template 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(); } } diff --git a/src/textures/formats/automaptexture.cpp b/src/textures/formats/automaptexture.cpp index 299727d83..81205291b 100644 --- a/src/textures/formats/automaptexture.cpp +++ b/src/textures/formats/automaptexture.cpp @@ -52,7 +52,7 @@ class FAutomapTexture : public FImageSource { public: FAutomapTexture(int lumpnum); - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; @@ -91,7 +91,7 @@ FAutomapTexture::FAutomapTexture (int lumpnum) // //========================================================================== -TArray FAutomapTexture::GetPalettedPixels(int conversion) +TArray FAutomapTexture::CreatePalettedPixels(int conversion) { int x, y; FMemLump data = Wads.ReadLump (SourceLump); diff --git a/src/textures/formats/buildtexture.cpp b/src/textures/formats/buildtexture.cpp index a76e1666e..1b5be6543 100644 --- a/src/textures/formats/buildtexture.cpp +++ b/src/textures/formats/buildtexture.cpp @@ -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 GetPalettedPixels(int conversion) override; + TArray 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 FBuildTexture::GetPalettedPixels(int conversion) +TArray FBuildTexture::CreatePalettedPixels(int conversion) { TArray Pixels(Width * Height, true); FRemapTable *Remap = translationtables[TRANSLATION_Standard][Translation]; diff --git a/src/textures/formats/ddstexture.cpp b/src/textures/formats/ddstexture.cpp index 810f91fe2..f5ae1f056 100644 --- a/src/textures/formats/ddstexture.cpp +++ b/src/textures/formats/ddstexture.cpp @@ -164,7 +164,7 @@ class FDDSTexture : public FImageSource public: FDDSTexture (FileReader &lump, int lumpnum, void *surfdesc); - TArray GetPalettedPixels(int conversion) override; + TArray 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 FDDSTexture::GetPalettedPixels(int conversion) +TArray FDDSTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); diff --git a/src/textures/formats/emptytexture.cpp b/src/textures/formats/emptytexture.cpp index 11710f226..1073de660 100644 --- a/src/textures/formats/emptytexture.cpp +++ b/src/textures/formats/emptytexture.cpp @@ -51,7 +51,7 @@ class FEmptyTexture : public FImageSource { public: FEmptyTexture (int lumpnum); - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -91,7 +91,7 @@ FEmptyTexture::FEmptyTexture (int lumpnum) // //========================================================================== -TArray FEmptyTexture::GetPalettedPixels(int conversion) +TArray FEmptyTexture::CreatePalettedPixels(int conversion) { TArray Pixel(1, true); Pixel[0] = 0; diff --git a/src/textures/formats/flattexture.cpp b/src/textures/formats/flattexture.cpp index a0982645f..7654b2b35 100644 --- a/src/textures/formats/flattexture.cpp +++ b/src/textures/formats/flattexture.cpp @@ -50,7 +50,7 @@ class FFlatTexture : public FImageSource { public: FFlatTexture (int lumpnum); - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; @@ -104,7 +104,7 @@ FFlatTexture::FFlatTexture (int lumpnum) // //========================================================================== -TArray FFlatTexture::GetPalettedPixels(int conversion) +TArray FFlatTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); TArray Pixels(Width*Height, true); diff --git a/src/textures/formats/fontchars.cpp b/src/textures/formats/fontchars.cpp index 3573ab892..93f460b3d 100644 --- a/src/textures/formats/fontchars.cpp +++ b/src/textures/formats/fontchars.cpp @@ -68,12 +68,12 @@ FFontChar1::FFontChar1 (FImageSource *sourcelump) // //========================================================================== -TArray FFontChar1::GetPalettedPixels (int) +TArray 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 FFontChar2::GetPalettedPixels(int) +TArray FFontChar2::CreatePalettedPixels(int) { auto lump = Wads.OpenLumpReader (SourceLump); int destSize = Width * Height; diff --git a/src/textures/formats/fontchars.h b/src/textures/formats/fontchars.h index 644372b77..96437f3a8 100644 --- a/src/textures/formats/fontchars.h +++ b/src/textures/formats/fontchars.h @@ -5,7 +5,7 @@ class FFontChar1 : public FImageSource { public: FFontChar1 (FImageSource *sourcelump); - TArray GetPalettedPixels(int conversion) override; + TArray 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 GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; void SetSourceRemap(const uint8_t *sourceremap); protected: diff --git a/src/textures/formats/imgztexture.cpp b/src/textures/formats/imgztexture.cpp index 681f39d97..2f466c5e2 100644 --- a/src/textures/formats/imgztexture.cpp +++ b/src/textures/formats/imgztexture.cpp @@ -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 GetPalettedPixels(int conversion) override; + TArray 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 FIMGZTexture::GetPalettedPixels(int conversion) +TArray FIMGZTexture::CreatePalettedPixels(int conversion) { FMemLump lump = Wads.ReadLump (SourceLump); const ImageHeader *imgz = (const ImageHeader *)lump.GetMem(); diff --git a/src/textures/formats/jpegtexture.cpp b/src/textures/formats/jpegtexture.cpp index 451f91f15..a441c585b 100644 --- a/src/textures/formats/jpegtexture.cpp +++ b/src/textures/formats/jpegtexture.cpp @@ -186,7 +186,7 @@ public: FJPEGTexture (int lumpnum, int width, int height); int CopyPixels(FBitmap *bmp, int conversion) override; - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -260,7 +260,7 @@ FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height) // //========================================================================== -TArray FJPEGTexture::GetPalettedPixels(int conversion) +TArray FJPEGTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); JSAMPLE *buff = NULL; diff --git a/src/textures/formats/multipatchtexture.cpp b/src/textures/formats/multipatchtexture.cpp index cd50d555c..fe960923b 100644 --- a/src/textures/formats/multipatchtexture.cpp +++ b/src/textures/formats/multipatchtexture.cpp @@ -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 FMultiPatchTexture::GetPalettedPixels(int conversion) +TArray 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); + } +} + + diff --git a/src/textures/formats/multipatchtexture.h b/src/textures/formats/multipatchtexture.h index 28ff8dcc3..bda492b84 100644 --- a/src/textures/formats/multipatchtexture.h +++ b/src/textures/formats/multipatchtexture.h @@ -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 GetPalettedPixels(int conversion) override; + TArray 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); + }; diff --git a/src/textures/formats/patchtexture.cpp b/src/textures/formats/patchtexture.cpp index 7a5de9c31..705da984a 100644 --- a/src/textures/formats/patchtexture.cpp +++ b/src/textures/formats/patchtexture.cpp @@ -64,7 +64,7 @@ class FPatchTexture : public FImageSource bool isalpha = false; public: FPatchTexture (int lumpnum, patch_t *header, bool isalphatex); - TArray GetPalettedPixels(int conversion) override; + TArray 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 FPatchTexture::GetPalettedPixels(int conversion) +TArray FPatchTexture::CreatePalettedPixels(int conversion) { uint8_t *remap, remaptable[256]; int numspans; diff --git a/src/textures/formats/pcxtexture.cpp b/src/textures/formats/pcxtexture.cpp index 708f36d81..ff37ce8aa 100644 --- a/src/textures/formats/pcxtexture.cpp +++ b/src/textures/formats/pcxtexture.cpp @@ -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 GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; @@ -358,7 +358,7 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr // //========================================================================== -TArray FPCXTexture::GetPalettedPixels(int conversion) +TArray FPCXTexture::CreatePalettedPixels(int conversion) { uint8_t PaletteMap[256]; PCXHeader header; diff --git a/src/textures/formats/pngtexture.cpp b/src/textures/formats/pngtexture.cpp index 37272125e..3cdfc3a6a 100644 --- a/src/textures/formats/pngtexture.cpp +++ b/src/textures/formats/pngtexture.cpp @@ -55,7 +55,7 @@ public: ~FPNGTexture(); int CopyPixels(FBitmap *bmp, int conversion) override; - TArray GetPalettedPixels(int conversion) override; + TArray 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 FPNGTexture::GetPalettedPixels(int conversion) +TArray FPNGTexture::CreatePalettedPixels(int conversion) { FileReader *lump; FileReader lfr; diff --git a/src/textures/formats/rawpagetexture.cpp b/src/textures/formats/rawpagetexture.cpp index 0edaa9497..3cc136dfc 100644 --- a/src/textures/formats/rawpagetexture.cpp +++ b/src/textures/formats/rawpagetexture.cpp @@ -54,7 +54,7 @@ class FRawPageTexture : public FImageSource int mPaletteLump = -1; public: FRawPageTexture (int lumpnum); - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; int CopyPixels(FBitmap *bmp, int conversion) override; }; @@ -173,7 +173,7 @@ FRawPageTexture::FRawPageTexture (int lumpnum) // //========================================================================== -TArray FRawPageTexture::GetPalettedPixels(int conversion) +TArray FRawPageTexture::CreatePalettedPixels(int conversion) { FMemLump lump = Wads.ReadLump (SourceLump); const uint8_t *source = (const uint8_t *)lump.GetMem(); diff --git a/src/textures/formats/shadertexture.cpp b/src/textures/formats/shadertexture.cpp index 0e79ad8c7..8f817d9bc 100644 --- a/src/textures/formats/shadertexture.cpp +++ b/src/textures/formats/shadertexture.cpp @@ -100,7 +100,7 @@ public: } } - TArray GetPalettedPixels(int conversion) override + TArray CreatePalettedPixels(int conversion) override { TArray Pix(512, true); if (conversion == luminance) diff --git a/src/textures/formats/tgatexture.cpp b/src/textures/formats/tgatexture.cpp index cfb0f4890..1a26f6036 100644 --- a/src/textures/formats/tgatexture.cpp +++ b/src/textures/formats/tgatexture.cpp @@ -85,7 +85,7 @@ public: protected: void ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel); - TArray GetPalettedPixels(int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -179,7 +179,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe // //========================================================================== -TArray FTGATexture::GetPalettedPixels(int conversion) +TArray FTGATexture::CreatePalettedPixels(int conversion) { uint8_t PaletteMap[256]; auto lump = Wads.OpenLumpReader (SourceLump); diff --git a/src/textures/image.cpp b/src/textures/image.cpp index c5d29ae5f..859021770 100644 --- a/src/textures/image.cpp +++ b/src/textures/image.cpp @@ -43,6 +43,24 @@ FMemArena FImageSource::ImageArena(32768); TArrayFImageSource::ImageForLump; int FImageSource::NextID; +static PrecacheInfo precacheInfo; + +struct PrecacheDataPaletted +{ + TArray 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; +TArray precacheDataRgba; //=========================================================================== // @@ -50,13 +68,97 @@ int FImageSource::NextID; // //=========================================================================== -TArray FImageSource::GetPalettedPixels(int conversion) +TArray FImageSource::CreatePalettedPixels(int conversion) { TArray 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 *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 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 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(); +} + //========================================================================== // diff --git a/src/textures/image.h b/src/textures/image.h index 7101c2816..7c976f451 100644 --- a/src/textures/image.h +++ b/src/textures/image.h @@ -5,6 +5,21 @@ #include "textures/bitmap.h" #include "memarena.h" +class FImageSource; +using PrecacheInfo = TMap>; + +struct PalettedPixels +{ + friend class FImageSource; + TArrayView Pixels; +private: + TArray 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 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 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 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); }; //========================================================================== diff --git a/src/textures/textures.h b/src/textures/textures.h index ef154a9f6..72bef46ea 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -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 FirstTextureForFile; TArray > BuildTileData; - TArray mAnimations; TArray mSwitchDefs; TArray mAnimatedDoors; public: + TArray mAnimations; + bool HasGlobalBrightmap; FRemapTable GlobalBrightmap; short sintable[2048]; // for texture warping diff --git a/src/v_video.h b/src/v_video.h index 1cba846f0..918c572e3 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -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) {}