- major refactor of texture upscaling control.

All decisions were done deep inside the texture creation code, leaving zero options to the higher level code for controlling the feature.
Changed this so that the option to upscale must be passed as a parameter to FRenderState::SetMaterial and extended all needed variables to manage the added texture variants.
Still not solved: Material layers need explicit control, not only for scaling but also for filtering.
This commit is contained in:
Christoph Oelckers 2020-04-16 23:37:22 +02:00
parent 0b990f0dcb
commit 8505c7ee7d
27 changed files with 144 additions and 129 deletions

View file

@ -409,22 +409,10 @@ void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasA
{
// [BB] Make sure that inWidth and inHeight denote the size of
// the returned buffer even if we don't upsample the input buffer.
int inWidth = texbuffer.mWidth;
int inHeight = texbuffer.mHeight;
// [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared.
const int maxInputSize = gl_texture_hqresize_maxinputsize;
if (inWidth * inHeight > maxInputSize * maxInputSize)
return;
// [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!)
if (bHasCanvas)
return;
// already scaled?
if (Scale.X >= 2 && Scale.Y >= 2)
return;
int type = gl_texture_hqresizemode;
int mult = gl_texture_hqresizemult;
#ifdef HAVE_MMX
@ -493,3 +481,33 @@ void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasA
contentId.scalefactor = mult;
texbuffer.mContentId = contentId.id;
}
bool shouldUpscale(FGameTexture *tex, ETextureType UseType)
{
// [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared.
const int maxInputSize = gl_texture_hqresize_maxinputsize;
if (tex->GetTexelWidth() * tex->GetTexelHeight() > maxInputSize * maxInputSize)
return false;
// [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!)
if (tex->isHardwareCanvas())
return false;
// already scaled?
if (tex->GetDisplayWidth() >= 2* tex->GetTexelWidth() || tex->GetDisplayHeight() >= 2*tex->GetTexelHeight())
return false;
switch (UseType)
{
case ETextureType::Sprite:
case ETextureType::SkinSprite:
return !!(gl_texture_hqresize_targets & 2);
case ETextureType::FontChar:
return !!(gl_texture_hqresize_targets & 4);
default:
return !!(gl_texture_hqresize_targets & 1);
}
}

View file

@ -36,7 +36,7 @@ IHardwareTexture* CreateHardwareTexture();
//
//===========================================================================
FMaterial::FMaterial(FGameTexture * tx, bool expanded)
FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
{
mShaderIndex = SHADER_Default;
sourcetex = tx;
@ -122,10 +122,10 @@ FMaterial::FMaterial(FGameTexture * tx, bool expanded)
}
}
}
mExpanded = expanded;
mScaleFlags = scaleflags;
mTextureLayers.ShrinkToFit();
imgtex->Material[expanded] = this;
imgtex->Material[scaleflags] = this;
if (tx->isHardwareCanvas()) tx->SetTranslucent(false);
}
@ -151,7 +151,7 @@ IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer)
FTexture *layer = i == 0 ? imgtex : mTextureLayers[i - 1];
if (pLayer) *pLayer = layer;
if (layer) return layer->GetHardwareTexture(translation, mExpanded);
if (layer) return layer->GetHardwareTexture(translation, mScaleFlags);
return nullptr;
}
@ -162,17 +162,17 @@ IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer)
//
//==========================================================================
FMaterial * FMaterial::ValidateTexture(FGameTexture * gtex, bool expand, bool create)
FMaterial * FMaterial::ValidateTexture(FGameTexture * gtex, int scaleflags, bool create)
{
if (gtex && gtex->isValid())
{
auto tex = gtex->GetTexture();
if (!tex->ShouldExpandSprite()) expand = false;
if (!tex->ShouldExpandSprite()) scaleflags &= ~CTF_Expand;
FMaterial *hwtex = tex->Material[expand];
FMaterial *hwtex = tex->Material[scaleflags];
if (hwtex == NULL && create)
{
hwtex = new FMaterial(gtex, expand);
hwtex = new FMaterial(gtex, scaleflags);
}
return hwtex;
}

View file

@ -20,16 +20,17 @@ class FMaterial
TArray<FTexture*> mTextureLayers;
int mShaderIndex;
int mLayerFlags = 0;
bool mExpanded;
int mScaleFlags;
public:
FGameTexture *sourcetex; // the owning texture.
FTexture* imgtex; // the first layer's texture image - should be moved into the array
FMaterial(FGameTexture *tex, bool forceexpand);
FMaterial(FGameTexture *tex, int scaleflags);
~FMaterial();
int GetLayerFlags() const { return mLayerFlags; }
int GetShaderIndex() const { return mShaderIndex; }
int GetScaleFlags() const { return mScaleFlags; }
FGameTexture* Source() const
{
@ -45,10 +46,6 @@ public:
//ValidateTexture(tex, false);
mTextureLayers.Push(tex);
}
bool isExpanded() const
{
return mExpanded;
}
int GetLayers() const
{
@ -58,7 +55,7 @@ public:
IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr) const;
static FMaterial *ValidateTexture(FGameTexture * tex, bool expand, bool create = true);
static FMaterial *ValidateTexture(FGameTexture * tex, int scaleflags, bool create = true);
const TArray<FTexture*> &GetLayerArray() const
{
return mTextureLayers;

View file

@ -7,6 +7,15 @@
struct FTextureBuffer;
class IHardwareTexture;
enum ECreateTexBufferFlags
{
CTF_Expand = 1, // create buffer with a one-pixel wide border
CTF_Upscale = 2, // Upscale the texture
CTF_CreateMask = 3, // Flags that are relevant for hardware texture creation.
CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture.
CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures.
};
class FHardwareTextureContainer
{
public:
@ -40,20 +49,20 @@ private:
private:
TranslatedTexture hwDefTex[2];
TranslatedTexture hwDefTex[4];
TArray<TranslatedTexture> hwTex_Translated;
TranslatedTexture * GetTexID(int translation, bool expanded)
TranslatedTexture * GetTexID(int translation, int scaleflags)
{
auto remap = GPalette.TranslationToTable(translation);
translation = remap == nullptr ? 0 : remap->Index;
if (translation == 0)
if (translation == 0 && !(scaleflags & CTF_Upscale))
{
return &hwDefTex[expanded];
return &hwDefTex[scaleflags];
}
if (expanded) translation = -translation;
translation |= (scaleflags << 24);
// normally there aren't more than very few different
// translations here so this isn't performance critical.
unsigned index = hwTex_Translated.FindEx([=](auto &element)
@ -73,31 +82,28 @@ private:
public:
void Clean(bool cleannormal, bool cleanexpanded)
void Clean(bool reallyclean)
{
if (cleannormal) hwDefTex[0].Delete();
if (cleanexpanded) hwDefTex[1].Delete();
hwDefTex[0].DeleteDescriptors();
hwDefTex[1].DeleteDescriptors();
for (int i = hwTex_Translated.Size() - 1; i >= 0; i--)
{
if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i);
else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i);
for (unsigned int j = 0; j < hwTex_Translated.Size(); j++)
hwTex_Translated[j].DeleteDescriptors();
for (unsigned int j = 0; j < hwTex_Translated.Size(); j++)
hwTex_Translated[j].DeleteDescriptors();
}
if (!reallyclean) return;
hwDefTex[0].Delete();
hwDefTex[1].Delete();
hwTex_Translated.Clear();
}
IHardwareTexture * GetHardwareTexture(int translation, bool expanded)
IHardwareTexture * GetHardwareTexture(int translation, int scaleflags)
{
auto tt = GetTexID(translation, expanded);
auto tt = GetTexID(translation, scaleflags);
return tt->hwTexture;
}
void AddHardwareTexture(int translation, bool expanded, IHardwareTexture *tex)
void AddHardwareTexture(int translation, int scaleflags, IHardwareTexture *tex)
{
auto tt = GetTexID(translation, expanded);
auto tt = GetTexID(translation, scaleflags);
tt->Delete();
tt->hwTexture =tex;
}
@ -109,16 +115,15 @@ public:
//
//===========================================================================
void CleanUnused(SpriteHits &usedtranslations, bool expanded)
void CleanUnused(SpriteHits &usedtranslations, int scaleflags)
{
if (usedtranslations.CheckKey(0) == nullptr)
{
hwDefTex[expanded].Delete();
hwDefTex[scaleflags].Delete();
}
int fac = expanded ? -1 : 1;
for (int i = hwTex_Translated.Size()-1; i>= 0; i--)
{
if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr)
if (usedtranslations.CheckKey(hwTex_Translated[i].translation & 0xffffff) == nullptr)
{
hwTex_Translated.Delete(i);
}

View file

@ -688,27 +688,10 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
result.mWidth = W;
result.mHeight = H;
bool upscale = true;
switch (UseType)
{
case ETextureType::Sprite:
case ETextureType::SkinSprite:
if (!(gl_texture_hqresize_targets & 2)) upscale = false;
break;
case ETextureType::FontChar:
if (!(gl_texture_hqresize_targets & 4)) upscale = false;
break;
default:
if (!(gl_texture_hqresize_targets & 1)) upscale = false;
break;
}
// Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.)
if (GetImage() && flags & CTF_ProcessData)
{
if (upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false);
}
@ -738,7 +721,7 @@ bool FTexture::DetermineTranslucency()
void FTexture::CleanHardwareTextures(bool reallyclean)
{
SystemTextures.Clean(reallyclean, reallyclean);
SystemTextures.Clean(reallyclean);
}
//===========================================================================
@ -964,15 +947,15 @@ void FTexture::SetSpriteRect()
//
//===========================================================================
IHardwareTexture* FTexture::GetHardwareTexture(int translation, bool expanded)
IHardwareTexture* FTexture::GetHardwareTexture(int translation, int scaleflags)
{
if (UseType != ETextureType::Null)
{
IHardwareTexture* hwtex = SystemTextures.GetHardwareTexture(translation, expanded);
IHardwareTexture* hwtex = SystemTextures.GetHardwareTexture(translation, scaleflags);
if (hwtex == nullptr)
{
hwtex = CreateHardwareTexture();
SystemTextures.AddHardwareTexture(translation, expanded, hwtex);
SystemTextures.AddHardwareTexture(translation, scaleflags, hwtex);
}
return hwtex;
}

View file

@ -120,15 +120,6 @@ struct FloatRect
}
};
enum ECreateTexBufferFlags
{
CTF_Expand = 2, // create buffer with a one-pixel wide border
CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture.
CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures.
};
class FBitmap;
struct FRemapTable;
struct FCopyInfo;
@ -258,7 +249,7 @@ public:
SpritePositioningInfo *spi = nullptr;
IHardwareTexture* GetHardwareTexture(int translation, bool expanded);
IHardwareTexture* GetHardwareTexture(int translation, int scaleflags);
static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype);
virtual ~FTexture ();
virtual FImageSource *GetImage() const { return nullptr; }
@ -369,7 +360,7 @@ protected:
int SourceLump;
FTextureID id;
FMaterial *Material[2] = { nullptr, nullptr };
FMaterial *Material[4] = { };
public:
FHardwareTextureContainer SystemTextures;
protected:
@ -534,7 +525,7 @@ public:
FWrapperTexture(int w, int h, int bits = 1);
IHardwareTexture *GetSystemTexture()
{
return SystemTextures.GetHardwareTexture(0, false);
return SystemTextures.GetHardwareTexture(0, 0);
}
int GetColorFormat() const
@ -764,6 +755,7 @@ inline FGameTexture* MakeGameTexture(FTexture* tex)
return new FGameTexture(tex);
}
bool shouldUpscale(FGameTexture* tex, ETextureType UseType);
#endif