diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 26a3608fd3..ad4cfdf865 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1058,6 +1058,7 @@ set (PCH_SOURCES hwrenderer/data/flatvertices.cpp hwrenderer/dynlights/hw_aabbtree.cpp hwrenderer/textures/hw_material.cpp + hwrenderer/textures/hw_precache.cpp menu/joystickmenu.cpp menu/loadsavemenu.cpp diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index ec77414e7f..857b6fa480 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -38,6 +38,7 @@ #include "gl/textures/gl_samplers.h" #include "gl/utility/gl_clock.h" #include "gl/data/gl_vertexbuffer.h" +#include "gl/models/gl_models.h" #include "gl_debug.h" #include "r_videoscale.h" @@ -393,6 +394,12 @@ IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(FTexture *tex) return new FHardwareTexture(tex->bNoCompress); } +FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) +{ + return new FGLModelRenderer(mli); +} + + void OpenGLFrameBuffer::UnbindTexUnit(int no) { FHardwareTexture::Unbind(no); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 3061d7598e..26dbf1635b 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -44,6 +44,7 @@ public: void RenderView(player_t *player) override; void SetTextureFilterMode() override; IHardwareTexture *CreateHardwareTexture(FTexture *tex) override; + FModelRenderer *CreateModelRenderer(int mli) override; void UnbindTexUnit(int no) override; // Retrieves a buffer containing image data for a screenshot. diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index ee74d74b0c..e7d6096425 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -105,189 +105,3 @@ int TexFormat[]={ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, }; - -//========================================================================== -// -// DFrameBuffer :: PrecacheTexture -// -//========================================================================== - -static void PrecacheTexture(FTexture *tex, int cache) -{ - if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, false); - if (gltex) gltex->Precache(); - } - else - { - // make sure that software pixel buffers do not stick around for unneeded textures. - tex->Unload(); - } -} - -//========================================================================== -// -// DFrameBuffer :: PrecacheSprite -// -//========================================================================== - -static void PrecacheSprite(FTexture *tex, SpriteHits &hits) -{ - FMaterial * gltex = FMaterial::ValidateTexture(tex, true); - if (gltex) gltex->PrecacheList(hits); -} - -//========================================================================== -// -// DFrameBuffer :: Precache -// -//========================================================================== - -void gl_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist) -{ - SpriteHits *spritelist = new SpriteHits[sprites.Size()]; - SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; - TMap::Iterator it(actorhitlist); - TMap::Pair *pair; - uint8_t *modellist = new uint8_t[Models.Size()]; - memset(modellist, 0, Models.Size()); - memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); - - // this isn't done by the main code so it needs to be done here first: - // check skybox textures and mark the separate faces as used - for (int i = 0; ibSkybox) - { - FSkyBox *sb = static_cast(tex); - for (int i = 0; i<6; i++) - { - if (sb->faces[i]) - { - int index = sb->faces[i]->id.GetIndex(); - texhitlist[index] |= FTextureManager::HIT_Flat; - } - } - } - } - } - - // Check all used actors. - // 1. mark all sprites associated with its states - // 2. mark all model data and skins associated with its states - while (it.NextPair(pair)) - { - PClassActor *cls = pair->Key; - auto remap = TranslationToTable(GetDefaultByType(cls)->Translation); - int gltrans = remap == nullptr ? 0 : remap->GetUniqueIndex(); - - for (unsigned i = 0; i < cls->GetStateCount(); i++) - { - auto &state = cls->GetStates()[i]; - spritelist[state.sprite].Insert(gltrans, true); - FSpriteModelFrame * smf = gl_FindModelFrame(cls, state.sprite, state.Frame, false); - if (smf != NULL) - { - for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) - { - if (smf->skinIDs[i].isValid()) - { - texhitlist[smf->skinIDs[i].GetIndex()] |= FTextureManager::HIT_Flat; - } - else if (smf->modelIDs[i] != -1) - { - Models[smf->modelIDs[i]]->PushSpriteMDLFrame(smf, i); - Models[smf->modelIDs[i]]->AddSkins(texhitlist); - } - if (smf->modelIDs[i] != -1) - { - modellist[smf->modelIDs[i]] = 1; - } - } - } - } - } - - // mark all sprite textures belonging to the marked sprites. - for (int i = (int)(sprites.Size() - 1); i >= 0; i--) - { - if (spritelist[i].CountUsed()) - { - int j, k; - for (j = 0; j < sprites[i].numframes; j++) - { - const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; - - for (k = 0; k < 16; k++) - { - FTextureID pic = frame->Texture[k]; - if (pic.isValid()) - { - spritehitlist[pic.GetIndex()] = &spritelist[i]; - } - } - } - } - } - - // delete everything unused before creating any new resources to avoid memory usage peaks. - - // delete unused models - for (unsigned i = 0; i < Models.Size(); i++) - { - if (!modellist[i]) Models[i]->DestroyVertexBuffer(); - } - - // delete unused textures - int cnt = TexMan.NumTextures(); - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr) - { - if (!texhitlist[i]) - { - if (tex->Material[0]) tex->Material[0]->Clean(true); - } - if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) - { - if (tex->Material[1]) tex->Material[1]->Clean(true); - } - } - } - - if (gl_precache) - { - // cache all used textures - for (int i = cnt - 1; i >= 0; i--) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex != nullptr) - { - PrecacheTexture(tex, texhitlist[i]); - if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) - { - PrecacheSprite(tex, *spritehitlist[i]); - } - } - } - - // cache all used models - FGLModelRenderer renderer(-1); - for (unsigned i = 0; i < Models.Size(); i++) - { - if (modellist[i]) - Models[i]->BuildVertexBuffer(&renderer); - } - } - - delete[] spritehitlist; - delete[] spritelist; - delete[] modellist; -} - diff --git a/src/hwrenderer/textures/hw_precache.cpp b/src/hwrenderer/textures/hw_precache.cpp new file mode 100644 index 0000000000..a40a8a821c --- /dev/null +++ b/src/hwrenderer/textures/hw_precache.cpp @@ -0,0 +1,223 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2004-2016 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** Texture precaching +** +*/ + +#include "c_cvars.h" +#include "w_wad.h" +#include "r_data/r_translate.h" +#include "c_dispatch.h" +#include "r_state.h" +#include "actor.h" +#include "r_data/models/models.h" +#include "textures/skyboxtexture.h" +#include "hwrenderer/textures/hw_material.h" + + +//========================================================================== +// +// DFrameBuffer :: PrecacheTexture +// +//========================================================================== + +static void PrecacheTexture(FTexture *tex, int cache) +{ + if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) + { + FMaterial * gltex = FMaterial::ValidateTexture(tex, false); + if (gltex) gltex->Precache(); + } + else + { + // make sure that software pixel buffers do not stick around for unneeded textures. + tex->Unload(); + } +} + +//========================================================================== +// +// DFrameBuffer :: PrecacheSprite +// +//========================================================================== + +static void PrecacheSprite(FTexture *tex, SpriteHits &hits) +{ + FMaterial * gltex = FMaterial::ValidateTexture(tex, true); + if (gltex) gltex->PrecacheList(hits); +} + +//========================================================================== +// +// DFrameBuffer :: Precache +// +//========================================================================== + +void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist) +{ + SpriteHits *spritelist = new SpriteHits[sprites.Size()]; + SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; + TMap::Iterator it(actorhitlist); + TMap::Pair *pair; + uint8_t *modellist = new uint8_t[Models.Size()]; + memset(modellist, 0, Models.Size()); + memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); + + // this isn't done by the main code so it needs to be done here first: + // check skybox textures and mark the separate faces as used + for (int i = 0; ibSkybox) + { + FSkyBox *sb = static_cast(tex); + for (int i = 0; i<6; i++) + { + if (sb->faces[i]) + { + int index = sb->faces[i]->id.GetIndex(); + texhitlist[index] |= FTextureManager::HIT_Flat; + } + } + } + } + } + + // Check all used actors. + // 1. mark all sprites associated with its states + // 2. mark all model data and skins associated with its states + while (it.NextPair(pair)) + { + PClassActor *cls = pair->Key; + auto remap = TranslationToTable(GetDefaultByType(cls)->Translation); + int gltrans = remap == nullptr ? 0 : remap->GetUniqueIndex(); + + for (unsigned i = 0; i < cls->GetStateCount(); i++) + { + auto &state = cls->GetStates()[i]; + spritelist[state.sprite].Insert(gltrans, true); + FSpriteModelFrame * smf = gl_FindModelFrame(cls, state.sprite, state.Frame, false); + if (smf != NULL) + { + for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) + { + if (smf->skinIDs[i].isValid()) + { + texhitlist[smf->skinIDs[i].GetIndex()] |= FTextureManager::HIT_Flat; + } + else if (smf->modelIDs[i] != -1) + { + Models[smf->modelIDs[i]]->PushSpriteMDLFrame(smf, i); + Models[smf->modelIDs[i]]->AddSkins(texhitlist); + } + if (smf->modelIDs[i] != -1) + { + modellist[smf->modelIDs[i]] = 1; + } + } + } + } + } + + // mark all sprite textures belonging to the marked sprites. + for (int i = (int)(sprites.Size() - 1); i >= 0; i--) + { + if (spritelist[i].CountUsed()) + { + int j, k; + for (j = 0; j < sprites[i].numframes; j++) + { + const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; + + for (k = 0; k < 16; k++) + { + FTextureID pic = frame->Texture[k]; + if (pic.isValid()) + { + spritehitlist[pic.GetIndex()] = &spritelist[i]; + } + } + } + } + } + + // delete everything unused before creating any new resources to avoid memory usage peaks. + + // delete unused models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (!modellist[i]) Models[i]->DestroyVertexBuffer(); + } + + // delete unused textures + int cnt = TexMan.NumTextures(); + for (int i = cnt - 1; i >= 0; i--) + { + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + if (!texhitlist[i]) + { + if (tex->Material[0]) tex->Material[0]->Clean(true); + } + if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) + { + if (tex->Material[1]) tex->Material[1]->Clean(true); + } + } + } + + if (gl_precache) + { + // cache all used textures + for (int i = cnt - 1; i >= 0; i--) + { + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + PrecacheTexture(tex, texhitlist[i]); + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) + { + PrecacheSprite(tex, *spritehitlist[i]); + } + } + } + + // cache all used models + FModelRenderer *renderer = screen->CreateModelRenderer(-1); + for (unsigned i = 0; i < Models.Size(); i++) + { + if (modellist[i]) + Models[i]->BuildVertexBuffer(renderer); + } + delete renderer; + } + + delete[] spritehitlist; + delete[] spritelist; + delete[] modellist; +} + diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 621343decc..c718bdeaba 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3412,7 +3412,7 @@ void P_GetPolySpots (MapData * map, TArray &spots, TAr // Preloads all relevant graphics for the level. // //=========================================================================== -void gl_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist); +void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist); static void P_PrecacheLevel() { @@ -3491,7 +3491,7 @@ static void P_PrecacheLevel() if (!V_IsHardwareRenderer()) SWRenderer->Precache(hitlist, actorhitlist); else - gl_PrecacheTexture(hitlist, actorhitlist); + hw_PrecacheTexture(hitlist, actorhitlist); delete[] hitlist; } diff --git a/src/v_video.h b/src/v_video.h index 468a03784f..49869a6058 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -80,6 +80,7 @@ class FTexture; struct FColormap; class FileWriter; enum FTextureFormat : uint32_t; +class FModelRenderer; // TagItem definitions for DrawTexture. As far as I know, tag lists // originated on the Amiga. @@ -354,6 +355,7 @@ public: virtual void CleanForRestart() {} virtual void SetTextureFilterMode() {} virtual IHardwareTexture *CreateHardwareTexture(FTexture *tex) { return nullptr; } + virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; } virtual void UnbindTexUnit(int no) {} // Begin 2D drawing operations.