Re-enable downsampling for non-sparse textures

This commit is contained in:
Bradley Austin Davis 2016-11-04 18:00:07 -07:00 committed by Brad Davis
parent 666d2dd2fc
commit 9e929ca629
6 changed files with 91 additions and 48 deletions

View file

@ -116,7 +116,7 @@ float GLTexture::getMemoryPressure() {
}
// Return the consumed texture memory divided by the available texture memory.
auto consumedGpuMemory = Context::getTextureGPUSparseMemoryUsage();
auto consumedGpuMemory = Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage();
float memoryPressure = (float)consumedGpuMemory / (float)availableTextureMemory;
static Context::Size lastConsumedGpuMemory = 0;
if (memoryPressure > 1.0f && lastConsumedGpuMemory != consumedGpuMemory) {

View file

@ -94,6 +94,7 @@ public:
TransferState _transferState;
uint32_t _allocatedPages { 0 };
uint32_t _lastMipAllocatedPages { 0 };
uint16_t _mipOffset { 0 };
friend class GL45Backend;
};

View file

@ -282,20 +282,22 @@ GL45Texture::~GL45Texture() {
if (!_gpuObject.getUsage().isExternal()) {
qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str();
}
if (_sparseInfo.sparse) {
Backend::decrementTextureGPUSparseCount();
// Remove this texture from the candidate list of derezzable textures
{
auto mipLevels = usedMipLevels();
Lock lock(texturesByMipCountsMutex);
if (texturesByMipCounts.count(mipLevels)) {
auto& textures = texturesByMipCounts[mipLevels];
textures.erase(this);
if (textures.empty()) {
texturesByMipCounts.erase(mipLevels);
}
// Remove this texture from the candidate list of derezzable textures
if (_transferrable) {
auto mipLevels = usedMipLevels();
Lock lock(texturesByMipCountsMutex);
if (texturesByMipCounts.count(mipLevels)) {
auto& textures = texturesByMipCounts[mipLevels];
textures.erase(this);
if (textures.empty()) {
texturesByMipCounts.erase(mipLevels);
}
}
}
if (_sparseInfo.sparse) {
Backend::decrementTextureGPUSparseCount();
// Experimenation suggests that allocating sparse textures on one context/thread and deallocating
// them on another is buggy. So for sparse textures we need to queue a lambda with the deallocation
@ -355,7 +357,7 @@ void GL45Texture::allocateStorage() const {
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
// Get the dimensions, accounting for the downgrade level
Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip);
Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip + _mipOffset);
glTextureStorage2D(_id, usedMipLevels(), _internalFormat, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR();
}
@ -370,7 +372,7 @@ void GL45Texture::updateSize() const {
Backend::updateTextureGPUSparseMemoryUsage(_size, size);
setSize(_allocatedPages * _sparseInfo.pageBytes);
} else {
setSize(_virtualSize);
setSize(_gpuObject.evalTotalSize(_mipOffset));
}
}
@ -481,35 +483,30 @@ void GL45Texture::syncSampler() const {
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
// FIXME account for mip offsets here
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), _minMip);
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip);
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip() - _mipOffset));
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
}
void GL45Texture::postTransfer() {
Parent::postTransfer();
if (_sparseInfo.sparse) {
auto mipLevels = usedMipLevels();
if (mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) {
Lock lock(texturesByMipCountsMutex);
texturesByMipCounts[mipLevels].insert(this);
}
auto mipLevels = usedMipLevels();
if (_transferrable && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) {
Lock lock(texturesByMipCountsMutex);
texturesByMipCounts[mipLevels].insert(this);
}
}
void GL45Texture::stripToMip(uint16_t newMinMip) {
if (!_sparseInfo.sparse) {
return;
}
if (newMinMip < _minMip) {
qCWarning(gpugl45logging) << "Cannot decrease the min mip";
return;
}
if (newMinMip > _sparseInfo.maxSparseLevel) {
if (_sparseInfo.sparse && newMinMip > _sparseInfo.maxSparseLevel) {
qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail";
return;
}
@ -533,19 +530,53 @@ void GL45Texture::stripToMip(uint16_t newMinMip) {
uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
for (uint16_t mip = _minMip; mip < newMinMip; ++mip) {
auto id = _id;
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
_textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] {
glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE);
});
if (_sparseInfo.sparse) {
for (uint16_t mip = _minMip; mip < newMinMip; ++mip) {
auto id = _id;
auto mipDimensions = _gpuObject.evalMipDimensions(mip);
_textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] {
glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE);
});
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
assert(deallocatedPages < _allocatedPages);
_allocatedPages -= deallocatedPages;
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
assert(deallocatedPages < _allocatedPages);
_allocatedPages -= deallocatedPages;
}
_minMip = newMinMip;
} else {
GLuint oldId = _id;
// Find the distance between the old min mip and the new one
uint16 mipDelta = newMinMip - _minMip;
_mipOffset += mipDelta;
const_cast<uint16&>(_maxMip) -= mipDelta;
auto newLevels = usedMipLevels();
// Create and setup the new texture (allocate)
glCreateTextures(_target, 1, &const_cast<GLuint&>(_id));
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
Vec3u newDimensions = _gpuObject.evalMipDimensions(_mipOffset);
glTextureStorage2D(_id, newLevels, _internalFormat, newDimensions.x, newDimensions.y);
// Copy the contents of the old texture to the new
GLuint fbo { 0 };
glCreateFramebuffers(1, &fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) {
uint16 sourceMip = targetMip + mipDelta;
Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset);
for (GLenum target : getFaceTargets(_target)) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip);
(void)CHECK_GL_ERROR();
glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y);
(void)CHECK_GL_ERROR();
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &oldId);
}
_minMip = newMinMip;
// Re-sync the sampler to force access to the new mip level
syncSampler();
updateSize();
@ -553,7 +584,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) {
// Re-insert into the texture-by-mips map if appropriate
mipLevels = usedMipLevels();
if (_sparseInfo.sparse && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) {
if (mipLevels > 1 && (!_sparseInfo.sparse || _minMip < _sparseInfo.maxSparseLevel)) {
Lock lock(texturesByMipCountsMutex);
texturesByMipCounts[mipLevels].insert(this);
}
@ -570,8 +601,9 @@ void GL45Texture::updateMips() {
}
void GL45Texture::derez() {
assert(_sparseInfo.sparse);
assert(_minMip < _sparseInfo.maxSparseLevel);
if (_sparseInfo.sparse) {
assert(_minMip < _sparseInfo.maxSparseLevel);
}
assert(_minMip < _maxMip);
assert(_transferrable);
stripToMip(_minMip + 1);
@ -595,7 +627,7 @@ void GL45Backend::derezTextures() const {
}
qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage();
qCDebug(gpugl45logging) << "Used texture memory " << Context::getTextureGPUMemoryUsage();
qCDebug(gpugl45logging) << "Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage());
GL45Texture* targetTexture = nullptr;
{
@ -605,5 +637,5 @@ void GL45Backend::derezTextures() const {
}
lock.unlock();
targetTexture->derez();
qCDebug(gpugl45logging) << "New Used texture memory " << Context::getTextureGPUMemoryUsage();
qCDebug(gpugl45logging) << "New Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage());
}

View file

@ -15,6 +15,7 @@
#include "Texture.h"
#include <glm/gtc/constants.hpp>
#include <glm/gtx/component_wise.hpp>
#include <NumericalConstants.h>
@ -418,12 +419,18 @@ uint16 Texture::evalDimNumMips(uint16 size) {
return 1 + (uint16) val;
}
static const double LOG_2 = log(2.0);
uint16 Texture::evalNumMips(const Vec3u& dimensions) {
double largerDim = glm::compMax(dimensions);
double val = log(largerDim) / LOG_2;
return 1 + (uint16)val;
}
// The number mips that the texture could have if all existed
// = log2(max(width, height, depth))
uint16 Texture::evalNumMips() const {
double largerDim = std::max(std::max(_width, _height), _depth);
double val = log(largerDim)/log(2.0);
return 1 + (uint16) val;
return evalNumMips({ _width, _height, _depth });
}
bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) {

View file

@ -369,9 +369,12 @@ public:
// = 1 + log2(max(width, height, depth))
uint16 evalNumMips() const;
static uint16 evalNumMips(const Vec3u& dimnsions);
// Eval the size that the mips level SHOULD have
// not the one stored in the Texture
static const uint MIN_DIMENSION = 1;
Vec3u evalMipDimensions(uint16 level) const;
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
@ -388,9 +391,9 @@ public:
uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
uint32 evalTotalSize() const {
uint32 evalTotalSize(uint16 startingMip = 0) const {
uint32 size = 0;
uint16 minMipLevel = minMip();
uint16 minMipLevel = std::max(minMip(), startingMip);
uint16 maxMipLevel = maxMip();
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
size += evalMipSize(l);

View file

@ -599,7 +599,7 @@ protected:
return;
case Qt::Key_End:
gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(256));
gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(64));
return;