mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 19:55:07 +02:00
Remove duplicate code, polish
This commit is contained in:
parent
0d89b3a922
commit
283ff01038
4 changed files with 82 additions and 162 deletions
|
@ -69,7 +69,7 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
|
|||
|
||||
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
|
||||
: GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) {
|
||||
|
||||
incrementTextureGPUCount();
|
||||
withPreservedTexture([&] {
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
|
||||
const Sampler& sampler = _gpuObject.getSampler();
|
||||
|
|
|
@ -94,15 +94,27 @@ public:
|
|||
Undersubscribed,
|
||||
};
|
||||
|
||||
using QueuePair = std::pair<TextureWeakPointer, float>;
|
||||
class QueuePairLess {
|
||||
public:
|
||||
bool operator()(const QueuePair& a, const QueuePair& b) {
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
using WorkQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, QueuePairLess>;
|
||||
|
||||
protected:
|
||||
static std::atomic<bool> _memoryPressureStateStale;
|
||||
static MemoryPressureState _memoryPressureState;
|
||||
static std::list<TextureWeakPointer> _memoryManagedTextures;
|
||||
static WorkQueue _workQueue;
|
||||
static const uvec3 INITIAL_MIP_TRANSFER_DIMENSIONS;
|
||||
|
||||
|
||||
static void updateMemoryPressure();
|
||||
static void processWorkQueues();
|
||||
static void addMemoryManagedTexture(const TexturePointer& texturePointer);
|
||||
static void addToWorkQueue(const TexturePointer& texture);
|
||||
|
||||
static void manageMemory();
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ using GL45Texture = GL45Backend::GL45Texture;
|
|||
|
||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
|
||||
: GLTexture(backend, texture, allocate(texture)) {
|
||||
incrementTextureGPUCount();
|
||||
}
|
||||
|
||||
GLuint GL45Texture::allocate(const Texture& texture) {
|
||||
|
|
|
@ -30,11 +30,13 @@ using namespace gpu::gl45;
|
|||
// Variable sized textures
|
||||
using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture;
|
||||
using MemoryPressureState = GL45VariableAllocationTexture::MemoryPressureState;
|
||||
using WorkQueue = GL45VariableAllocationTexture::WorkQueue;
|
||||
|
||||
std::list<TextureWeakPointer> GL45VariableAllocationTexture::_memoryManagedTextures;
|
||||
MemoryPressureState GL45VariableAllocationTexture::_memoryPressureState = MemoryPressureState::Idle;
|
||||
std::atomic<bool> GL45VariableAllocationTexture::_memoryPressureStateStale { false };
|
||||
const uvec3 GL45VariableAllocationTexture::INITIAL_MIP_TRANSFER_DIMENSIONS { 64, 64, 1 };
|
||||
WorkQueue GL45VariableAllocationTexture::_workQueue;
|
||||
|
||||
#define OVERSUBSCRIBED_PRESSURE_VALUE 0.95f
|
||||
#define UNDERSUBSCRIBED_PRESSURE_VALUE 0.85f
|
||||
|
@ -42,45 +44,29 @@ const uvec3 GL45VariableAllocationTexture::INITIAL_MIP_TRANSFER_DIMENSIONS { 64,
|
|||
|
||||
static const size_t DEFAULT_ALLOWED_TEXTURE_MEMORY = MB_TO_BYTES(DEFAULT_ALLOWED_TEXTURE_MEMORY_MB);
|
||||
|
||||
using QueuePair = std::pair<TextureWeakPointer, uint32_t>;
|
||||
class QueuePairLess {
|
||||
public:
|
||||
bool operator()(const QueuePair& a, const QueuePair& b) {
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
class QueuePairGreater {
|
||||
public:
|
||||
bool operator()(const QueuePair& a, const QueuePair& b) {
|
||||
return a.second > b.second;
|
||||
}
|
||||
};
|
||||
using DemoteQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, QueuePairLess>;
|
||||
using PromoteQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, QueuePairGreater>;
|
||||
using TransferQueue = std::queue<TextureWeakPointer>;
|
||||
static DemoteQueue demoteQueue;
|
||||
static PromoteQueue promoteQueue;
|
||||
static TransferQueue transferQueue;
|
||||
|
||||
void GL45VariableAllocationTexture::addMemoryManagedTexture(const TexturePointer& texturePointer) {
|
||||
_memoryManagedTextures.push_back(texturePointer);
|
||||
addToWorkQueue(texturePointer);
|
||||
}
|
||||
|
||||
void GL45VariableAllocationTexture::addToWorkQueue(const TexturePointer& texturePointer) {
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texturePointer);
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
if (object->canDemote()) {
|
||||
demoteQueue.push({ texturePointer, object->size() });
|
||||
_workQueue.push({ texturePointer, (float) object->size() });
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
if (object->canPromote()) {
|
||||
promoteQueue.push({ texturePointer, object->size() });
|
||||
_workQueue.push({ texturePointer, 1.0f / (float)object->size() });
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
if (object->hasPendingTransfers()) {
|
||||
transferQueue.push( texturePointer );
|
||||
_workQueue.push({ texturePointer, 1.0f / (float)object->_gpuObject.evalMipSize(object->_populatedMip) });
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -94,23 +80,32 @@ void GL45VariableAllocationTexture::addMemoryManagedTexture(const TexturePointer
|
|||
|
||||
void GL45VariableAllocationTexture::updateMemoryPressure() {
|
||||
static size_t lastAllowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
|
||||
size_t allowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
if (0 == allowedMemoryAllocation) {
|
||||
allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY;
|
||||
}
|
||||
|
||||
// If the user explicitly changed the allowed memory usage, we need to mark ourselves stale
|
||||
// so that we react
|
||||
if (allowedMemoryAllocation != lastAllowedMemoryAllocation) {
|
||||
_memoryPressureStateStale = true;
|
||||
lastAllowedMemoryAllocation = allowedMemoryAllocation;
|
||||
}
|
||||
|
||||
if (!_memoryPressureStateStale) {
|
||||
if (!_memoryPressureStateStale.exchange(false)) {
|
||||
return;
|
||||
}
|
||||
_memoryPressureStateStale = false;
|
||||
// Clear any defunct textures
|
||||
|
||||
// Clear any defunct textures (weak pointers that no longer have a valid texture)
|
||||
_memoryManagedTextures.remove_if([&](const TextureWeakPointer& weakPointer) {
|
||||
return weakPointer.expired();
|
||||
});
|
||||
|
||||
// Convert weak pointers to strong
|
||||
std::list<TexturePointer> strongTextures; {
|
||||
// Convert weak pointers to strong. This new list may still contain nulls if a texture was
|
||||
// deleted on another thread between the previous line and this one
|
||||
std::vector<TexturePointer> strongTextures; {
|
||||
strongTextures.reserve(_memoryManagedTextures.size());
|
||||
std::transform(
|
||||
_memoryManagedTextures.begin(), _memoryManagedTextures.end(),
|
||||
std::back_inserter(strongTextures),
|
||||
|
@ -127,8 +122,10 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
|
|||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
idealMemoryAllocation += texture->evalTotalSize();
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
// Track how much the texture thinks it should be using
|
||||
idealMemoryAllocation += texture->evalTotalSize();
|
||||
// Track how much we're actually using
|
||||
totalVariableMemoryAllocation += object->size();
|
||||
canDemote |= object->canDemote();
|
||||
canPromote |= object->canPromote();
|
||||
|
@ -136,11 +133,6 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
|
|||
}
|
||||
|
||||
size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation;
|
||||
if (0 == allowedMemoryAllocation) {
|
||||
allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
float pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation;
|
||||
|
||||
auto newState = MemoryPressureState::Idle;
|
||||
|
@ -154,142 +146,59 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
|
|||
|
||||
if (newState != _memoryPressureState) {
|
||||
_memoryPressureState = newState;
|
||||
|
||||
demoteQueue = DemoteQueue();
|
||||
promoteQueue = PromoteQueue();
|
||||
transferQueue = TransferQueue();
|
||||
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Idle:
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
for (const auto& texture : strongTextures) {
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (object->canDemote()) {
|
||||
demoteQueue.push({ texture, object->size() });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
for (const auto& texture : strongTextures) {
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (object->canPromote()) {
|
||||
promoteQueue.push({ texture, object->size() });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
for (const auto& texture : strongTextures) {
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (object->hasPendingTransfers()) {
|
||||
transferQueue.push(texture);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
// Clear the existing queue
|
||||
_workQueue = WorkQueue();
|
||||
// Populate the existing textures into the queue
|
||||
for (const auto& texture : strongTextures) {
|
||||
addToWorkQueue(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GL45VariableAllocationTexture::processWorkQueues() {
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Idle:
|
||||
break;
|
||||
if (MemoryPressureState::Idle == _memoryPressureState) {
|
||||
return;
|
||||
}
|
||||
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
// Grab the first item off the demote queue
|
||||
while (!demoteQueue.empty()) {
|
||||
auto demoteTarget = demoteQueue.top();
|
||||
demoteQueue.pop();
|
||||
auto texture = demoteTarget.first.lock();
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
while (!_workQueue.empty()) {
|
||||
auto workTarget = _workQueue.top();
|
||||
_workQueue.pop();
|
||||
auto texture = workTarget.first.lock();
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (!object->canDemote()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//qDebug() << "QQQ executing demote for " << texture->source().c_str();
|
||||
object->demote();
|
||||
// if the object can be further demoted, reinsert into the queue
|
||||
if (object->canDemote()) {
|
||||
demoteQueue.push({ demoteTarget.first, object->size() });
|
||||
}
|
||||
break;
|
||||
// Grab the first item off the demote queue
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (MemoryPressureState::Oversubscribed == _memoryPressureState) {
|
||||
if (!object->canDemote()) {
|
||||
continue;
|
||||
}
|
||||
if (demoteQueue.empty()) {
|
||||
_memoryPressureState = MemoryPressureState::Idle;
|
||||
//qDebug() << "QQQ executing demote for " << texture->source().c_str();
|
||||
object->demote();
|
||||
} else if (MemoryPressureState::Undersubscribed == _memoryPressureState) {
|
||||
if (!object->canPromote()) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
while (!promoteQueue.empty()) {
|
||||
auto promoteTarget = promoteQueue.top();
|
||||
promoteQueue.pop();
|
||||
auto texture = promoteTarget.first.lock();
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (!object->canPromote()) {
|
||||
continue;
|
||||
}
|
||||
//qDebug() << "QQQ executing promote for " << texture->source().c_str();
|
||||
object->promote();
|
||||
if (object->canPromote()) {
|
||||
promoteQueue.push({ promoteTarget.first, object->size() });
|
||||
}
|
||||
break;
|
||||
//qDebug() << "QQQ executing promote for " << texture->source().c_str();
|
||||
object->promote();
|
||||
} else if (MemoryPressureState::Transfer == _memoryPressureState) {
|
||||
if (!object->hasPendingTransfers()) {
|
||||
continue;
|
||||
}
|
||||
if (promoteQueue.empty()) {
|
||||
_memoryPressureState = MemoryPressureState::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
while (!transferQueue.empty()) {
|
||||
auto weakTexture = transferQueue.front();
|
||||
transferQueue.pop();
|
||||
auto texture = weakTexture.lock();
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
|
||||
if (!object->hasPendingTransfers()) {
|
||||
continue;
|
||||
}
|
||||
//qDebug() << "QQQ executing transfer for " << texture->source().c_str();
|
||||
object->executeNextTransfer();
|
||||
if (object->hasPendingTransfers()) {
|
||||
transferQueue.push(weakTexture);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (transferQueue.empty()) {
|
||||
_memoryPressureState = MemoryPressureState::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//qDebug() << "QQQ executing transfer for " << texture->source().c_str();
|
||||
object->executeNextTransfer();
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
// Reinject into the queue if more work to be done
|
||||
addToWorkQueue(texture);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_workQueue.empty()) {
|
||||
_memoryPressureState = MemoryPressureState::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +288,6 @@ void GL45ResourceTexture::promote() {
|
|||
uint32_t oldSize = _size;
|
||||
// create new texture
|
||||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||
incrementTextureGPUCount();
|
||||
uint16_t oldAllocatedMip = _allocatedMip;
|
||||
// allocate storage for new level
|
||||
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
|
||||
|
@ -413,7 +321,6 @@ void GL45ResourceTexture::demote() {
|
|||
auto oldId = _id;
|
||||
auto oldSize = _size;
|
||||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||
incrementTextureGPUCount();
|
||||
allocateStorage(_allocatedMip + 1);
|
||||
_populatedMip = std::max(_populatedMip, _allocatedMip);
|
||||
uint16_t mips = _gpuObject.evalNumMips();
|
||||
|
|
Loading…
Reference in a new issue