From b612e92c81f705548f7ebd35e3dde7a588fb3924 Mon Sep 17 00:00:00 2001 From: LHoG <1476261+lhog@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:00:28 +0100 Subject: [PATCH] Big refactoring before switching from CMatrix44f to Transform --- rts/Rendering/Common/ModelDrawerData.h | 25 ++-- rts/Rendering/Common/UpdateList.cpp | 22 +++- rts/Rendering/Common/UpdateList.h | 13 +- rts/Rendering/Models/3DModel.cpp | 6 +- rts/Rendering/Models/ModelsMemStorage.cpp | 71 ++++++++++- rts/Rendering/Models/ModelsMemStorage.h | 113 ++++++++++------- rts/Rendering/ModelsDataUploader.cpp | 147 ++++++++-------------- rts/Rendering/ModelsDataUploader.h | 9 +- rts/System/Matrix44f.cpp | 2 +- rts/System/Matrix44f.h | 2 +- rts/System/Transform.cpp | 7 ++ rts/System/Transform.hpp | 3 + 12 files changed, 257 insertions(+), 163 deletions(-) diff --git a/rts/Rendering/Common/ModelDrawerData.h b/rts/Rendering/Common/ModelDrawerData.h index 8c7c886fdb..3b8bbb2f68 100644 --- a/rts/Rendering/Common/ModelDrawerData.h +++ b/rts/Rendering/Common/ModelDrawerData.h @@ -70,17 +70,17 @@ class CModelDrawerDataBase : public CModelDrawerDataConcept void ClearPreviousDrawFlags() { for (auto object : unsortedObjects) object->previousDrawFlag = 0; } const ScopedTransformMemAlloc& GetObjectTransformMemAlloc(const T* o) const { - const auto it = matricesMemAllocs.find(const_cast(o)); - return (it != matricesMemAllocs.end()) ? it->second : ScopedTransformMemAlloc::Dummy(); + const auto it = scTransMemAllocMap.find(const_cast(o)); + return (it != scTransMemAllocMap.end()) ? it->second : ScopedTransformMemAlloc::Dummy(); } - ScopedTransformMemAlloc& GetObjectTransformMemAlloc(const T* o) { return matricesMemAllocs[const_cast(o)]; } + ScopedTransformMemAlloc& GetObjectTransformMemAlloc(const T* o) { return scTransMemAllocMap[const_cast(o)]; } private: static constexpr int MMA_SIZE0 = 2 << 16; protected: std::array, MODELTYPE_CNT> modelRenderers; std::vector unsortedObjects; - std::unordered_map matricesMemAllocs; + std::unordered_map scTransMemAllocMap; bool& mtModelDrawer; }; @@ -100,7 +100,7 @@ inline CModelDrawerDataBase::CModelDrawerDataBase(const std::string& ecName, : CModelDrawerDataConcept(ecName, ecOrder) , mtModelDrawer(mtModelDrawer_) { - matricesMemAllocs.reserve(MMA_SIZE0); + scTransMemAllocMap.reserve(MMA_SIZE0); for (auto& mr : modelRenderers) { mr.Clear(); } } @@ -108,7 +108,7 @@ template inline CModelDrawerDataBase::~CModelDrawerDataBase() { unsortedObjects.clear(); - matricesMemAllocs.clear(); + scTransMemAllocMap.clear(); } template @@ -126,7 +126,7 @@ inline void CModelDrawerDataBase::AddObject(const T* co, bool add) unsortedObjects.emplace_back(o); const uint32_t numMatrices = (o->model ? o->model->numPieces : 0) + 1u; - matricesMemAllocs.emplace(o, ScopedTransformMemAlloc(numMatrices)); + scTransMemAllocMap.emplace(o, ScopedTransformMemAlloc(numMatrices)); modelUniformsStorage.GetObjOffset(co); } @@ -141,7 +141,7 @@ inline void CModelDrawerDataBase::DelObject(const T* co, bool del) } if (del && spring::VectorErase(unsortedObjects, o)) { - matricesMemAllocs.erase(o); + scTransMemAllocMap.erase(o); modelUniformsStorage.GetObjOffset(co); } } @@ -164,8 +164,7 @@ inline void CModelDrawerDataBase::UpdateObjectSMMA(const T* o) // from one point it doesn't worth the comparison, cause units usually move // but having not updated smma[0] allows for longer solid no-update areas in ModelUniformsUploader::UpdateDerived() - if (tmNew != tmOld) - smma[0] = tmNew; + smma.UpdateIfChanged(0, tmNew); for (int i = 0; i < o->localModel.pieces.size(); ++i) { const LocalModelPiece& lmp = o->localModel.pieces[i]; @@ -175,11 +174,13 @@ inline void CModelDrawerDataBase::UpdateObjectSMMA(const T* o) continue; if unlikely(!lmp.GetScriptVisible()) { - smma[i + 1] = CMatrix44f::Zero(); + //smma[i + 1] = CMatrix44f::Zero(); + smma.UpdateForced(i + 1, CMatrix44f::Zero()); continue; } - smma[i + 1] = lmp.GetModelSpaceMatrix(); + // UpdateIfChanged is not needed, wasCustomDirty takes that role + smma.UpdateForced(i + 1, lmp.GetModelSpaceMatrix()); } } diff --git a/rts/Rendering/Common/UpdateList.cpp b/rts/Rendering/Common/UpdateList.cpp index 173e047d7e..df3c72bc0e 100644 --- a/rts/Rendering/Common/UpdateList.cpp +++ b/rts/Rendering/Common/UpdateList.cpp @@ -24,6 +24,24 @@ void UpdateList::ResetNeedUpdateAll() changed = false; } +void UpdateList::Trim(size_t newLessThanOrEqualSize) +{ + RECOIL_DETAILED_TRACY_ZONE; + assert(newLessThanOrEqualSize <= updateList.size()); + updateList.resize(newLessThanOrEqualSize); + // no need to modify the update status +} + +void UpdateList::SetUpdate(size_t first, size_t count) +{ + RECOIL_DETAILED_TRACY_ZONE; + + auto beg = updateList.begin() + first; + auto end = beg + count; + + SetUpdate(UpdateList::IteratorPair(beg, end)); +} + void UpdateList::SetUpdate(const UpdateList::IteratorPair& it) { RECOIL_DETAILED_TRACY_ZONE; @@ -60,7 +78,7 @@ void UpdateList::PopBack(size_t N) changed = true; } -std::optional UpdateList::GetNext(const std::optional& prev) +std::optional UpdateList::GetNext(const std::optional& prev) const { RECOIL_DETAILED_TRACY_ZONE; auto beg = prev.has_value() ? prev.value().second : updateList.begin(); @@ -73,7 +91,7 @@ std::optional UpdateList::GetNext(const std::optional< return std::make_optional(std::make_pair(beg, end)); } -std::pair UpdateList::GetOffsetAndSize(const UpdateList::IteratorPair& it) +std::pair UpdateList::GetOffsetAndSize(const UpdateList::ConstIteratorPair& it) const { RECOIL_DETAILED_TRACY_ZONE; return std::make_pair( diff --git a/rts/Rendering/Common/UpdateList.h b/rts/Rendering/Common/UpdateList.h index ba77a1c342..6ebca33c97 100644 --- a/rts/Rendering/Common/UpdateList.h +++ b/rts/Rendering/Common/UpdateList.h @@ -8,19 +8,26 @@ class UpdateList { CR_DECLARE_STRUCT(UpdateList) public: + using ConstIteratorPair = std::pair::const_iterator, std::vector::const_iterator>; using IteratorPair = std::pair::iterator, std::vector::iterator>; public: UpdateList() : updateList() - , changed(true) + , changed(false) + {} + UpdateList(size_t initialSize) + : updateList(initialSize) + , changed(initialSize > 0) {} size_t Size() const { return updateList.size(); } size_t Capacity() const { return updateList.capacity(); } + void Trim(size_t newLessThanOrEqualSize); void Resize(size_t newSize) { updateList.resize(newSize); SetNeedUpdateAll(); } void Reserve(size_t reservedSize) { updateList.reserve(reservedSize); } + void SetUpdate(size_t first, size_t count); void SetUpdate(const IteratorPair& it); void SetUpdate(size_t offset); @@ -33,8 +40,8 @@ class UpdateList { bool NeedUpdate() const { return changed; } - std::optional GetNext(const std::optional& prev = std::nullopt); - std::pair GetOffsetAndSize(const IteratorPair& it); + std::optional GetNext(const std::optional& prev = std::nullopt) const; + std::pair GetOffsetAndSize(const ConstIteratorPair& it) const; private: std::vector updateList; bool changed; diff --git a/rts/Rendering/Models/3DModel.cpp b/rts/Rendering/Models/3DModel.cpp index a9cf6e924a..ca6499ddb2 100644 --- a/rts/Rendering/Models/3DModel.cpp +++ b/rts/Rendering/Models/3DModel.cpp @@ -763,13 +763,15 @@ void S3DModel::SetPieceMatrices() // use this occasion and copy bpose matrices for (size_t i = 0; i < pieceObjects.size(); ++i) { const auto* po = pieceObjects[i]; - traAlloc[0 + i] = po->bposeTransform.ToMatrix(); + //traAlloc[0 + i] = po->bposeTransform.ToMatrix(); + traAlloc.UpdateForced((0 + i), po->bposeTransform.ToMatrix()); } // use this occasion and copy inverse bpose matrices // store them right after all bind pose matrices for (size_t i = 0; i < pieceObjects.size(); ++i) { const auto* po = pieceObjects[i]; - traAlloc[numPieces + i] = po->bposeInvTransform.ToMatrix(); + //traAlloc[numPieces + i] = po->bposeInvTransform.ToMatrix(); + traAlloc.UpdateForced((numPieces + i), po->bposeInvTransform.ToMatrix()); } } diff --git a/rts/Rendering/Models/ModelsMemStorage.cpp b/rts/Rendering/Models/ModelsMemStorage.cpp index a98bf68445..262e597a10 100644 --- a/rts/Rendering/Models/ModelsMemStorage.cpp +++ b/rts/Rendering/Models/ModelsMemStorage.cpp @@ -9,8 +9,13 @@ ModelUniformsStorage modelUniformsStorage; ModelUniformsStorage::ModelUniformsStorage() { RECOIL_DETAILED_TRACY_ZONE; - storage[0] = dummy; - objectsMap.emplace(nullptr, 0); + storage[AddObjects(static_cast(nullptr))] = dummy; +} + +ModelUniformsStorage::~ModelUniformsStorage() +{ + // just in case + DelObjects(static_cast(nullptr)); } size_t ModelUniformsStorage::AddObjects(const CWorldObject* o) @@ -18,6 +23,17 @@ size_t ModelUniformsStorage::AddObjects(const CWorldObject* o) RECOIL_DETAILED_TRACY_ZONE; const size_t idx = storage.Add(ModelUniformData()); objectsMap[const_cast(o)] = idx; + + if (idx + 1 == storage.size()) { + //new item got added to the end of storage + updateList.EmplaceBackUpdate(); + } else { + // storage got updated somewhere in the middle, use updateList.SetUpdate() + updateList.SetUpdate(idx); + } + + assert(storage.size() == updateList.Size()); + return idx; } @@ -28,7 +44,18 @@ void ModelUniformsStorage::DelObjects(const CWorldObject* o) assert(it != objectsMap.end()); storage.Del(it->second); + + if (storage.size() < updateList.Size()) { + // storage got one element shorter, trim updateList as well + updateList.Trim(it->second); + } else { + // storage got updated somewhere in the middle, use updateList.SetUpdate() + updateList.SetUpdate(it->second); + } + objectsMap.erase(it); + + assert(storage.size() == updateList.Size()); } size_t ModelUniformsStorage::GetObjOffset(const CWorldObject* o) @@ -49,9 +76,43 @@ ModelUniformsStorage::MyType& ModelUniformsStorage::GetObjUniformsArray(const CW return storage[offset]; } -void TransformsMemStorage::SetAllDirty() +TransformsMemStorage::TransformsMemStorage() + : storage(StablePosAllocator(INIT_NUM_ELEMS)) + , updateList(INIT_NUM_ELEMS) +{} + +void TransformsMemStorage::Reset() { - RECOIL_DETAILED_TRACY_ZONE; assert(Threading::IsMainThread()); - std::fill(dirtyMap.begin(), dirtyMap.end(), BUFFERING); + storage.Reset(); + updateList.Trim(storage.GetSize()); +} + +size_t TransformsMemStorage::Allocate(size_t numElems) +{ + auto lock = CModelsLock::GetScopedLock(); + + auto res = storage.Allocate(numElems); + updateList.Resize(storage.GetSize()); + + assert(updateList.Size() == storage.GetSize()); + + return res; +} + +void TransformsMemStorage::Free(size_t firstElem, size_t numElems, const MyType* T0) +{ + auto lock = CModelsLock::GetScopedLock(); + + storage.Free(firstElem, numElems, T0); + updateList.SetUpdate(firstElem, numElems); + updateList.Trim(storage.GetSize()); + + assert(updateList.Size() == storage.GetSize()); } + +const TransformsMemStorage::MyType& TransformsMemStorage::operator[](std::size_t idx) const +{ + auto lock = CModelsLock::GetScopedLock(); + return storage[idx]; +} \ No newline at end of file diff --git a/rts/Rendering/Models/ModelsMemStorage.h b/rts/Rendering/Models/ModelsMemStorage.h index c82b47886e..8c4f726514 100644 --- a/rts/Rendering/Models/ModelsMemStorage.h +++ b/rts/Rendering/Models/ModelsMemStorage.h @@ -12,55 +12,64 @@ #include "System/Threading/SpringThreading.h" #include "Sim/Misc/GlobalConstants.h" #include "Sim/Objects/SolidObjectDef.h" +#include "Rendering/Common/UpdateList.h" -class TransformsMemStorage : public StablePosAllocator { -private: - using MyType = StablePosAllocator::Type; +class TransformsMemStorage { public: - explicit TransformsMemStorage() - : StablePosAllocator(INIT_NUM_ELEMS) - , dirtyMap(INIT_NUM_ELEMS, BUFFERING) - {} - void Reset() override { - assert(Threading::IsMainThread()); - StablePosAllocator::Reset(); - dirtyMap.resize(GetSize(), BUFFERING); - } + using MyType = CMatrix44f; + using EqualCmpFunctor = bool(*)(const MyType&, const MyType&); +public: + explicit TransformsMemStorage(); + void Reset(); - size_t Allocate(size_t numElems) override { - auto lock = CModelsLock::GetScopedLock(); - size_t res = StablePosAllocator::Allocate(numElems); - dirtyMap.resize(GetSize(), BUFFERING); + size_t Allocate(size_t numElems); - return res; - } - void Free(size_t firstElem, size_t numElems, const MyType* T0 = nullptr) override { - auto lock = CModelsLock::GetScopedLock(); - StablePosAllocator::Free(firstElem, numElems, T0); - dirtyMap.resize(GetSize(), BUFFERING); - } + void Free(size_t firstElem, size_t numElems, const MyType* T0 = nullptr); - const MyType& operator[](std::size_t idx) const override - { + const auto& GetData() const { return storage.GetData(); } + const auto GetSize() const { return storage.GetSize(); } + + template // to force universal references + bool UpdateIfChanged(std::size_t idx, MyTypeLike&& newValue, EqualCmpFunctor eqCmp) { auto lock = CModelsLock::GetScopedLock(); - return StablePosAllocator::operator[](idx); + + using DT = StablePosAllocator; + const auto& curValue = static_cast(storage)[idx]; + if (eqCmp(curValue, newValue)) + return false; + + updateList.SetUpdate(idx); + auto& mutValue = static_cast(storage)[idx]; + mutValue = newValue; + + assert(updateList.Size() == storage.GetSize()); + + return true; } - MyType& operator[](std::size_t idx) override - { + + template // to force universal references + void UpdateForced(std::size_t idx, MyTypeLike&& newValue) { auto lock = CModelsLock::GetScopedLock(); - return StablePosAllocator::operator[](idx); + + updateList.SetUpdate(idx); + auto& mutValue = storage[idx]; + mutValue = newValue; + + assert(updateList.Size() == storage.GetSize()); } + + const MyType& operator[](std::size_t idx) const; + + const auto& GetUpdateList() const { return updateList; } + void SetUpdateListUpdateAll() { updateList.SetNeedUpdateAll(); } + void SetUpdateListReset() { updateList.ResetNeedUpdateAll(); } private: - std::vector dirtyMap; -public: - const auto& GetDirtyMap() const { return dirtyMap; } - auto& GetDirtyMap() { return dirtyMap; } - void SetAllDirty(); -public: - //need to update buffer with matrices BUFFERING times, because the actual buffer is made of BUFFERING number of parts - static constexpr uint8_t BUFFERING = 3u; + StablePosAllocator storage; + UpdateList updateList; private: static constexpr int INIT_NUM_ELEMS = 1 << 16u; +public: + static constexpr auto INVALID_INDEX = StablePosAllocator::INVALID_INDEX; }; extern TransformsMemStorage transformsMemStorage; @@ -104,18 +113,31 @@ class ScopedTransformMemAlloc { return *this; } - const CMatrix44f& operator[](std::size_t offset) const { + const auto& operator[](std::size_t offset) const { assert(firstElem != TransformsMemStorage::INVALID_INDEX); assert(offset >= 0 && offset < numElems); return transformsMemStorage[firstElem + offset]; } - CMatrix44f& operator[](std::size_t offset) { + + template // to force universal references + bool UpdateIfChanged(std::size_t offset, MyTypeLike&& newValue) { + static const auto EqCmp = [](const TransformsMemStorage::MyType& lhs, const TransformsMemStorage::MyType& rhs) { + return lhs.equals(rhs); + }; + + assert(firstElem != TransformsMemStorage::INVALID_INDEX); + assert(offset >= 0 && offset < numElems); + + return transformsMemStorage.UpdateIfChanged(firstElem + offset, newValue, EqCmp); + } + + template // to force universal references + void UpdateForced(std::size_t offset, MyTypeLike&& newValue) { assert(firstElem != TransformsMemStorage::INVALID_INDEX); assert(offset >= 0 && offset < numElems); - transformsMemStorage.GetDirtyMap().at(firstElem + offset) = TransformsMemStorage::BUFFERING; - return transformsMemStorage[firstElem + offset]; + transformsMemStorage.UpdateForced(firstElem + offset, std::forward(newValue)); } public: static const ScopedTransformMemAlloc& Dummy() { @@ -136,6 +158,7 @@ class ModelUniformsStorage { using MyType = ModelUniformData; public: ModelUniformsStorage(); + ~ModelUniformsStorage(); public: size_t AddObjects(const CWorldObject* o); void DelObjects(const CWorldObject* o); @@ -152,8 +175,14 @@ class ModelUniformsStorage { size_t GetObjOffset(const S3DModel* o) { return INVALID_INDEX; } auto& GetObjUniformsArray(const S3DModel* o) { return dummy; } - size_t Size() const { return storage.GetData().size(); } + auto GetSize() const { return storage.GetData().size(); } const auto& GetData() const { return storage.GetData(); } + + const auto& GetUpdateList() const { return updateList; } + void SetUpdateListUpdateAll() { updateList.SetNeedUpdateAll(); } + void SetUpdateListReset() { updateList.ResetNeedUpdateAll(); } +private: + UpdateList updateList; public: static constexpr size_t INVALID_INDEX = 0; private: diff --git a/rts/Rendering/ModelsDataUploader.cpp b/rts/Rendering/ModelsDataUploader.cpp index 87f19431f5..d30525a76a 100644 --- a/rts/Rendering/ModelsDataUploader.cpp +++ b/rts/Rendering/ModelsDataUploader.cpp @@ -32,6 +32,56 @@ //////////////////////////////////////////////////////////////////// +namespace Impl { + template< + typename SSBO, + typename Uploader, + typename MemStorage + > + void UpdateCommon(Uploader& uploader, std::unique_ptr& ssbo, MemStorage& memStorage, const char* className, const char* funcName) + { + //resize + const uint32_t elemCount = uploader.GetElemsCount(); + const uint32_t storageElemCount = memStorage.GetSize(); + if (storageElemCount > elemCount) { + ssbo->UnbindBufferRange(uploader.GetBindingIdx()); + + const uint32_t newElemCount = AlignUp(storageElemCount, uploader.GetElemCountIncr()); + LOG_L(L_DEBUG, "[%s::%s] sizing SSBO %s. New elements count = %u, elemCount = %u, storageElemCount = %u", className, funcName, "up", newElemCount, elemCount, storageElemCount); + ssbo->Resize(newElemCount); + // ssbo->Resize() doesn't copy the data, force the update + memStorage.SetUpdateListUpdateAll(); + } + + const auto& ul = memStorage.GetUpdateList(); + if (!ul.NeedUpdate()) + return; + + // may have been already unbound above, not a big deal + ssbo->UnbindBufferRange(uploader.GetBindingIdx()); + + // get the data + const auto* clientPtr = memStorage.GetData().data(); + + // iterate over contiguous regions of values that need update on the GPU + for (auto itPair = ul.GetNext(); itPair.has_value(); itPair = ul.GetNext(itPair)) { + auto [idxOffset, idxSize] = ul.GetOffsetAndSize(itPair.value()); + + auto* mappedPtr = ssbo->Map(clientPtr, idxOffset, idxSize); + + if (!ssbo->HasClientPtr()) + memcpy(mappedPtr, clientPtr, storageElemCount * sizeof(decltype(*clientPtr))); + + ssbo->Unmap(); + } + + ssbo->BindBufferRange(uploader.GetBindingIdx()); + ssbo->SwapBuffer(); + + memStorage.SetUpdateListReset(); + } +} + template void TypedStorageBufferUploader::InitImpl(uint32_t bindingIdx_, uint32_t elemCount0_, uint32_t elemCountIncr_, uint8_t type, bool coherent, uint32_t numBuffers) { @@ -109,18 +159,7 @@ void TransformsUploader::InitDerived() if (!globalRendering->haveGL4) return; - const auto sbType = globalRendering->supportPersistentMapping - ? IStreamBufferConcept::Types::SB_PERSISTENTMAP - : IStreamBufferConcept::Types::SB_BUFFERSUBDATA; - - InitImpl(MATRIX_SSBO_BINDING_IDX, ELEM_COUNT0, ELEM_COUNTI, sbType, true, TransformsMemStorage::BUFFERING); - if (ssbo->GetBufferImplementation() == IStreamBufferConcept::Types::SB_PERSISTENTMAP && !ssbo->IsValid()) { - // some potatoe driver overestimated its support for SB_PERSISTENTMAP - // Redo with good old SB_BUFFERSUBDATA - LOG_L(L_ERROR, "[%s::%s] OpenGL reported persistent mapping to be available, but initial mapping of buffer failed. Falling back.", className, __func__); - KillImpl(); - InitImpl(MATRIX_SSBO_BINDING_IDX, ELEM_COUNT0, ELEM_COUNTI, IStreamBufferConcept::Types::SB_BUFFERSUBDATA, true, TransformsMemStorage::BUFFERING); - } + InitImpl(MATRIX_SSBO_BINDING_IDX, ELEM_COUNT0, ELEM_COUNTI, IStreamBufferConcept::Types::SB_BUFFERSUBDATA, true, 1); } void TransformsUploader::KillDerived() @@ -137,68 +176,11 @@ void TransformsUploader::UpdateDerived() return; SCOPED_TIMER("TransformsUploader::Update"); - ssbo->UnbindBufferRange(bindingIdx); + // TODO why the lock? auto lock = CModelsLock::GetScopedLock(); - //resize - const uint32_t elemCount = GetElemsCount(); - const uint32_t storageElemCount = transformsMemStorage.GetSize(); - if (storageElemCount > elemCount) { - const uint32_t newElemCount = AlignUp(storageElemCount, elemCountIncr); - LOG_L(L_DEBUG, "[%s::%s] sizing SSBO %s. New elements count = %u, elemCount = %u, storageElemCount = %u", className, __func__, "up", newElemCount, elemCount, storageElemCount); - ssbo->Resize(newElemCount); - - if (ssbo->GetBufferImplementation() == IStreamBufferConcept::Types::SB_PERSISTENTMAP && !ssbo->IsValid()) { - LOG_L(L_ERROR, "[%s::%s] OpenGL reported persistent mapping to be available, but mapping of buffer of %u size failed. Falling back.", className, __func__, uint32_t(newElemCount * sizeof(CMatrix44f))); - KillImpl(); - InitImpl(MATRIX_SSBO_BINDING_IDX, newElemCount, ELEM_COUNTI, IStreamBufferConcept::Types::SB_BUFFERSUBDATA, true, TransformsMemStorage::BUFFERING); - } - - transformsMemStorage.SetAllDirty(); //Resize doesn't copy the data - } - - //update on the GPU - const CMatrix44f* clientPtr = transformsMemStorage.GetData().data(); - - constexpr bool ENABLE_UPLOAD_OPTIMIZATION = true; - if (ssbo->GetBufferImplementation() == IStreamBufferConcept::Types::SB_PERSISTENTMAP && ENABLE_UPLOAD_OPTIMIZATION) { - const auto stt = transformsMemStorage.GetDirtyMap().begin(); - const auto fin = transformsMemStorage.GetDirtyMap().end(); - - auto beg = transformsMemStorage.GetDirtyMap().begin(); - auto end = transformsMemStorage.GetDirtyMap().begin(); - - static const auto dirtyPred = [](uint8_t m) -> bool { return m > 0u; }; - while (beg != fin) { - beg = std::find_if (beg, fin, dirtyPred); - end = std::find_if_not(beg, fin, dirtyPred); - - if (beg != fin) { - const uint32_t offs = static_cast(std::distance(stt, beg)); - const uint32_t size = static_cast(std::distance(beg, end)); - - CMatrix44f* mappedPtr = ssbo->Map(clientPtr, offs, size); - memcpy(mappedPtr, clientPtr + offs, size * sizeof(CMatrix44f)); - ssbo->Unmap(); - - std::transform(beg, end, beg, [](uint8_t v) { return (v - 1); }); //make it less dirty - } - - beg = end; //rewind - } - } - else { - const CMatrix44f* clientPtr = transformsMemStorage.GetData().data(); - CMatrix44f* mappedPtr = ssbo->Map(clientPtr, 0, storageElemCount); - - if (!ssbo->HasClientPtr()) - memcpy(mappedPtr, clientPtr, storageElemCount * sizeof(CMatrix44f)); - - ssbo->Unmap(); - } - ssbo->BindBufferRange(bindingIdx); - ssbo->SwapBuffer(); + Impl::UpdateCommon(*this, ssbo, transformsMemStorage, className, __func__); } std::size_t TransformsUploader::GetDefElemOffsetImpl(const S3DModel* model) const @@ -292,7 +274,7 @@ void ModelUniformsUploader::InitDerived() if (!globalRendering->haveGL4) return; - InitImpl(MATUNI_SSBO_BINDING_IDX, ELEM_COUNT0, ELEM_COUNTI, IStreamBufferConcept::Types::SB_BUFFERSUBDATA, true, 3); + InitImpl(MATUNI_SSBO_BINDING_IDX, ELEM_COUNT0, ELEM_COUNTI, IStreamBufferConcept::Types::SB_BUFFERSUBDATA, true, 1); } void ModelUniformsUploader::KillDerived() @@ -309,27 +291,8 @@ void ModelUniformsUploader::UpdateDerived() return; SCOPED_TIMER("ModelUniformsUploader::Update"); - ssbo->UnbindBufferRange(bindingIdx); - //resize - const uint32_t elemCount = GetElemsCount(); - const uint32_t storageElemCount = modelUniformsStorage.Size(); - if (storageElemCount > elemCount) { - const uint32_t newElemCount = AlignUp(storageElemCount, elemCountIncr); - LOG_L(L_DEBUG, "[%s::%s] sizing SSBO %s. New elements count = %u, elemCount = %u, storageElemCount = %u", className, __func__, "up", newElemCount, elemCount, storageElemCount); - ssbo->Resize(newElemCount); - } - - //update on the GPU - const ModelUniformData* clientPtr = modelUniformsStorage.GetData().data(); - ModelUniformData* mappedPtr = ssbo->Map(clientPtr, 0, storageElemCount); - - if (!ssbo->HasClientPtr()) - memcpy(mappedPtr, clientPtr, storageElemCount * sizeof(ModelUniformData)); - - ssbo->Unmap(); - ssbo->BindBufferRange(bindingIdx); - ssbo->SwapBuffer(); + Impl::UpdateCommon(*this, ssbo, modelUniformsStorage, className, __func__); } std::size_t ModelUniformsUploader::GetDefElemOffsetImpl(const S3DModel* model) const diff --git a/rts/Rendering/ModelsDataUploader.h b/rts/Rendering/ModelsDataUploader.h index 2a6fcd05c9..1808b956e9 100644 --- a/rts/Rendering/ModelsDataUploader.h +++ b/rts/Rendering/ModelsDataUploader.h @@ -33,6 +33,10 @@ class TypedStorageBufferUploader { void Init() { static_cast(this)->InitDerived(); } void Kill() { static_cast(this)->KillDerived(); } void Update() { static_cast(this)->UpdateDerived(); } + + uint32_t GetElemsCount() const; + auto GetElemCountIncr() const { return elemCountIncr; } + auto GetBindingIdx() const { return bindingIdx; } public: // Defs std::size_t GetElemOffset(const UnitDef* def) const { return GetDefElemOffsetImpl(def); } @@ -59,7 +63,6 @@ class TypedStorageBufferUploader { virtual std::size_t GetElemOffsetImpl(const CFeature* so) const = 0; virtual std::size_t GetElemOffsetImpl(const CProjectile* p) const = 0; - uint32_t GetElemsCount() const; protected: uint32_t bindingIdx = -1u; uint32_t elemCount0 = 0; @@ -83,8 +86,8 @@ class TransformsUploader : public TypedStorageBufferUploader { diff --git a/rts/System/Matrix44f.cpp b/rts/System/Matrix44f.cpp index 7da3fa9e6e..653d7dfd6a 100644 --- a/rts/System/Matrix44f.cpp +++ b/rts/System/Matrix44f.cpp @@ -377,7 +377,7 @@ static inline void MatrixMatrixMultiplySSE(const CMatrix44f& m1, const CMatrix44 _mm_store_ps(&mout->md[3][0], moutc4); } -bool CMatrix44f::equal(const CMatrix44f& rhs) const +bool CMatrix44f::equals(const CMatrix44f& rhs) const { return col[0].equals(rhs.col[0]) && diff --git a/rts/System/Matrix44f.h b/rts/System/Matrix44f.h index 349d52fea3..2e3e20875c 100644 --- a/rts/System/Matrix44f.h +++ b/rts/System/Matrix44f.h @@ -98,7 +98,7 @@ class CMatrix44f float4 Mul(const float4 v) const { return ((*this) * v); } /// approximately equal - bool equal(const CMatrix44f& rhs) const; + bool equals(const CMatrix44f& rhs) const; bool operator == (const CMatrix44f& rhs) const; bool operator != (const CMatrix44f& rhs) const { return !(*this == rhs); } diff --git a/rts/System/Transform.cpp b/rts/System/Transform.cpp index d0582bebba..b0bfe92d15 100644 --- a/rts/System/Transform.cpp +++ b/rts/System/Transform.cpp @@ -1,5 +1,7 @@ #include "Transform.hpp" +#include + #include "System/SpringMath.h" CR_BIND(Transform, ) @@ -12,6 +14,11 @@ CR_REG_METADATA(Transform, ( static_assert(sizeof (Transform) == 2 * 4 * sizeof(float)); static_assert(alignof(Transform) == alignof(decltype(Transform::r))); +void Transform::SetScaleSign(float signSrc) +{ + s = std::copysignf(s, signSrc); +} + bool Transform::IsIdentity() const { static constexpr Transform Identity; diff --git a/rts/System/Transform.hpp b/rts/System/Transform.hpp index f997a45ddf..955fdbb430 100644 --- a/rts/System/Transform.hpp +++ b/rts/System/Transform.hpp @@ -31,6 +31,9 @@ struct Transform { s = 1.0f; } + // can be used to enable/disable rendering + void SetScaleSign(float signSrc); + bool IsIdentity() const; static Transform FromMatrix(const CMatrix44f& mat);