Remove duplicate code, polish

This commit is contained in:
Brad Davis 2017-02-09 18:29:20 -08:00
parent 0d89b3a922
commit 283ff01038
4 changed files with 82 additions and 162 deletions

View file

@ -69,7 +69,7 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) {
GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) { : GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) {
incrementTextureGPUCount();
withPreservedTexture([&] { withPreservedTexture([&] {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
const Sampler& sampler = _gpuObject.getSampler(); const Sampler& sampler = _gpuObject.getSampler();

View file

@ -94,15 +94,27 @@ public:
Undersubscribed, 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: protected:
static std::atomic<bool> _memoryPressureStateStale; static std::atomic<bool> _memoryPressureStateStale;
static MemoryPressureState _memoryPressureState; static MemoryPressureState _memoryPressureState;
static std::list<TextureWeakPointer> _memoryManagedTextures; static std::list<TextureWeakPointer> _memoryManagedTextures;
static WorkQueue _workQueue;
static const uvec3 INITIAL_MIP_TRANSFER_DIMENSIONS; static const uvec3 INITIAL_MIP_TRANSFER_DIMENSIONS;
static void updateMemoryPressure(); static void updateMemoryPressure();
static void processWorkQueues(); static void processWorkQueues();
static void addMemoryManagedTexture(const TexturePointer& texturePointer); static void addMemoryManagedTexture(const TexturePointer& texturePointer);
static void addToWorkQueue(const TexturePointer& texture);
static void manageMemory(); static void manageMemory();

View file

@ -107,6 +107,7 @@ using GL45Texture = GL45Backend::GL45Texture;
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate(texture)) { : GLTexture(backend, texture, allocate(texture)) {
incrementTextureGPUCount();
} }
GLuint GL45Texture::allocate(const Texture& texture) { GLuint GL45Texture::allocate(const Texture& texture) {

View file

@ -30,11 +30,13 @@ using namespace gpu::gl45;
// Variable sized textures // Variable sized textures
using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture; using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture;
using MemoryPressureState = GL45VariableAllocationTexture::MemoryPressureState; using MemoryPressureState = GL45VariableAllocationTexture::MemoryPressureState;
using WorkQueue = GL45VariableAllocationTexture::WorkQueue;
std::list<TextureWeakPointer> GL45VariableAllocationTexture::_memoryManagedTextures; std::list<TextureWeakPointer> GL45VariableAllocationTexture::_memoryManagedTextures;
MemoryPressureState GL45VariableAllocationTexture::_memoryPressureState = MemoryPressureState::Idle; MemoryPressureState GL45VariableAllocationTexture::_memoryPressureState = MemoryPressureState::Idle;
std::atomic<bool> GL45VariableAllocationTexture::_memoryPressureStateStale { false }; std::atomic<bool> GL45VariableAllocationTexture::_memoryPressureStateStale { false };
const uvec3 GL45VariableAllocationTexture::INITIAL_MIP_TRANSFER_DIMENSIONS { 64, 64, 1 }; const uvec3 GL45VariableAllocationTexture::INITIAL_MIP_TRANSFER_DIMENSIONS { 64, 64, 1 };
WorkQueue GL45VariableAllocationTexture::_workQueue;
#define OVERSUBSCRIBED_PRESSURE_VALUE 0.95f #define OVERSUBSCRIBED_PRESSURE_VALUE 0.95f
#define UNDERSUBSCRIBED_PRESSURE_VALUE 0.85f #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); 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) { void GL45VariableAllocationTexture::addMemoryManagedTexture(const TexturePointer& texturePointer) {
_memoryManagedTextures.push_back(texturePointer); _memoryManagedTextures.push_back(texturePointer);
addToWorkQueue(texturePointer);
}
void GL45VariableAllocationTexture::addToWorkQueue(const TexturePointer& texturePointer) {
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texturePointer); GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texturePointer);
switch (_memoryPressureState) { switch (_memoryPressureState) {
case MemoryPressureState::Oversubscribed: case MemoryPressureState::Oversubscribed:
if (object->canDemote()) { if (object->canDemote()) {
demoteQueue.push({ texturePointer, object->size() }); _workQueue.push({ texturePointer, (float) object->size() });
} }
break; break;
case MemoryPressureState::Undersubscribed: case MemoryPressureState::Undersubscribed:
if (object->canPromote()) { if (object->canPromote()) {
promoteQueue.push({ texturePointer, object->size() }); _workQueue.push({ texturePointer, 1.0f / (float)object->size() });
} }
break; break;
case MemoryPressureState::Transfer: case MemoryPressureState::Transfer:
if (object->hasPendingTransfers()) { if (object->hasPendingTransfers()) {
transferQueue.push( texturePointer ); _workQueue.push({ texturePointer, 1.0f / (float)object->_gpuObject.evalMipSize(object->_populatedMip) });
} }
break; break;
@ -94,23 +80,32 @@ void GL45VariableAllocationTexture::addMemoryManagedTexture(const TexturePointer
void GL45VariableAllocationTexture::updateMemoryPressure() { void GL45VariableAllocationTexture::updateMemoryPressure() {
static size_t lastAllowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage(); static size_t lastAllowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage();
size_t allowedMemoryAllocation = 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) { if (allowedMemoryAllocation != lastAllowedMemoryAllocation) {
_memoryPressureStateStale = true; _memoryPressureStateStale = true;
lastAllowedMemoryAllocation = allowedMemoryAllocation; lastAllowedMemoryAllocation = allowedMemoryAllocation;
} }
if (!_memoryPressureStateStale) { if (!_memoryPressureStateStale.exchange(false)) {
return; 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) { _memoryManagedTextures.remove_if([&](const TextureWeakPointer& weakPointer) {
return weakPointer.expired(); return weakPointer.expired();
}); });
// Convert weak pointers to strong // Convert weak pointers to strong. This new list may still contain nulls if a texture was
std::list<TexturePointer> strongTextures; { // deleted on another thread between the previous line and this one
std::vector<TexturePointer> strongTextures; {
strongTextures.reserve(_memoryManagedTextures.size());
std::transform( std::transform(
_memoryManagedTextures.begin(), _memoryManagedTextures.end(), _memoryManagedTextures.begin(), _memoryManagedTextures.end(),
std::back_inserter(strongTextures), std::back_inserter(strongTextures),
@ -127,8 +122,10 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
if (!texture) { if (!texture) {
continue; continue;
} }
idealMemoryAllocation += texture->evalTotalSize();
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture); 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(); totalVariableMemoryAllocation += object->size();
canDemote |= object->canDemote(); canDemote |= object->canDemote();
canPromote |= object->canPromote(); canPromote |= object->canPromote();
@ -136,11 +133,6 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
} }
size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation; size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation;
if (0 == allowedMemoryAllocation) {
allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY;
}
float pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation; float pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation;
auto newState = MemoryPressureState::Idle; auto newState = MemoryPressureState::Idle;
@ -154,142 +146,59 @@ void GL45VariableAllocationTexture::updateMemoryPressure() {
if (newState != _memoryPressureState) { if (newState != _memoryPressureState) {
_memoryPressureState = newState; _memoryPressureState = newState;
// Clear the existing queue
demoteQueue = DemoteQueue(); _workQueue = WorkQueue();
promoteQueue = PromoteQueue(); // Populate the existing textures into the queue
transferQueue = TransferQueue(); for (const auto& texture : strongTextures) {
addToWorkQueue(texture);
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;
} }
} }
} }
void GL45VariableAllocationTexture::processWorkQueues() { void GL45VariableAllocationTexture::processWorkQueues() {
switch (_memoryPressureState) { if (MemoryPressureState::Idle == _memoryPressureState) {
case MemoryPressureState::Idle: return;
break; }
case MemoryPressureState::Oversubscribed: while (!_workQueue.empty()) {
// Grab the first item off the demote queue auto workTarget = _workQueue.top();
while (!demoteQueue.empty()) { _workQueue.pop();
auto demoteTarget = demoteQueue.top(); auto texture = workTarget.first.lock();
demoteQueue.pop(); if (!texture) {
auto texture = demoteTarget.first.lock(); continue;
if (!texture) { }
continue;
}
GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture); // Grab the first item off the demote queue
if (!object->canDemote()) { GL45VariableAllocationTexture* object = Backend::getGPUObject<GL45VariableAllocationTexture>(*texture);
continue; if (MemoryPressureState::Oversubscribed == _memoryPressureState) {
} 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;
} }
if (demoteQueue.empty()) { //qDebug() << "QQQ executing demote for " << texture->source().c_str();
_memoryPressureState = MemoryPressureState::Idle; object->demote();
} else if (MemoryPressureState::Undersubscribed == _memoryPressureState) {
if (!object->canPromote()) {
continue;
} }
break; //qDebug() << "QQQ executing promote for " << texture->source().c_str();
object->promote();
case MemoryPressureState::Undersubscribed: } else if (MemoryPressureState::Transfer == _memoryPressureState) {
while (!promoteQueue.empty()) { if (!object->hasPendingTransfers()) {
auto promoteTarget = promoteQueue.top(); continue;
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;
} }
if (promoteQueue.empty()) { //qDebug() << "QQQ executing transfer for " << texture->source().c_str();
_memoryPressureState = MemoryPressureState::Idle; object->executeNextTransfer();
} } else {
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:
Q_UNREACHABLE(); 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; uint32_t oldSize = _size;
// create new texture // create new texture
const_cast<GLuint&>(_id) = allocate(_gpuObject); const_cast<GLuint&>(_id) = allocate(_gpuObject);
incrementTextureGPUCount();
uint16_t oldAllocatedMip = _allocatedMip; uint16_t oldAllocatedMip = _allocatedMip;
// allocate storage for new level // allocate storage for new level
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2)); allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
@ -413,7 +321,6 @@ void GL45ResourceTexture::demote() {
auto oldId = _id; auto oldId = _id;
auto oldSize = _size; auto oldSize = _size;
const_cast<GLuint&>(_id) = allocate(_gpuObject); const_cast<GLuint&>(_id) = allocate(_gpuObject);
incrementTextureGPUCount();
allocateStorage(_allocatedMip + 1); allocateStorage(_allocatedMip + 1);
_populatedMip = std::max(_populatedMip, _allocatedMip); _populatedMip = std::max(_populatedMip, _allocatedMip);
uint16_t mips = _gpuObject.evalNumMips(); uint16_t mips = _gpuObject.evalNumMips();