Merge pull request #8893 from jherico/texture_force_sparse

Changes to texture loading rules
This commit is contained in:
Brad Hefta-Gaub 2016-10-25 18:22:42 -07:00 committed by GitHub
commit 863bf067b7
6 changed files with 134 additions and 13 deletions

View file

@ -205,6 +205,12 @@ Item {
StatText {
text: " Count: " + root.gpuTextures;
}
StatText {
text: " Rectified: " + root.rectifiedTextureCount;
}
StatText {
text: " Decimated: " + root.decimatedTextureCount;
}
StatText {
text: " Sparse Count: " + root.gpuTexturesSparse;
visible: 0 != root.gpuSparseTextureEnabled;
@ -228,6 +234,9 @@ Item {
StatText {
text: " Count: " + root.gpuTextures;
}
StatText {
text: " Memory: " + root.gpuBufferMemory;
}
StatText {
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
}

View file

@ -96,6 +96,8 @@ bool Stats::includeTimingRecord(const QString& name) {
} \
}
extern std::atomic<size_t> DECIMATED_TEXTURE_COUNT;
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
void Stats::updateStats(bool force) {
if (!force) {
@ -289,6 +291,7 @@ void Stats::updateStats(bool force) {
}
STAT_UPDATE(gpuBuffers, (int)gpu::Context::getBufferGPUCount());
STAT_UPDATE(gpuBufferMemory, (int)BYTES_TO_MB(gpu::Context::getBufferGPUMemoryUsage()));
STAT_UPDATE(gpuTextures, (int)gpu::Context::getTextureGPUCount());
STAT_UPDATE(gpuTexturesSparse, (int)gpu::Context::getTextureGPUSparseCount());
@ -301,6 +304,8 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage()));
STAT_UPDATE(gpuSparseTextureEnabled, gpu::Texture::getEnableSparseTextures() ? 1 : 0);
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()));
STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
// Incoming packets
QLocale locale(QLocale::English);

View file

@ -87,7 +87,10 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, localElements, 0)
STATS_PROPERTY(int, localInternal, 0)
STATS_PROPERTY(int, localLeaves, 0)
STATS_PROPERTY(int, rectifiedTextureCount, 0)
STATS_PROPERTY(int, decimatedTextureCount, 0)
STATS_PROPERTY(int, gpuBuffers, 0)
STATS_PROPERTY(int, gpuBufferMemory, 0)
STATS_PROPERTY(int, gpuTextures, 0)
STATS_PROPERTY(int, gpuTexturesSparse, 0)
STATS_PROPERTY(int, glContextSwapchainMemory, 0)
@ -186,6 +189,7 @@ signals:
void glContextSwapchainMemoryChanged();
void qmlTextureMemoryChanged();
void gpuBuffersChanged();
void gpuBufferMemoryChanged();
void gpuTexturesChanged();
void gpuTexturesSparseChanged();
void gpuTextureMemoryChanged();
@ -194,6 +198,8 @@ signals:
void gpuTextureSparseMemoryChanged();
void gpuSparseTextureEnabledChanged();
void gpuFreeMemoryChanged();
void rectifiedTextureCountChanged();
void decimatedTextureCountChanged();
private:
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process

View file

@ -102,12 +102,17 @@ float GLTexture::getMemoryPressure() {
// If no memory limit has been set, use a percentage of the total dedicated memory
if (!availableTextureMemory) {
#if 0
auto totalMemory = getDedicatedMemory();
if ((GPU_MEMORY_RESERVE_BYTES + TEXTURE_MEMORY_MIN_BYTES) > totalMemory) {
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
} else {
availableTextureMemory = totalMemory - GPU_MEMORY_RESERVE_BYTES;
}
#else
// Hardcode texture limit for sparse textures at 1 GB for now
availableTextureMemory = GPU_MEMORY_RESERVE_BYTES;
#endif
}
// Return the consumed texture memory divided by the available texture memory.

View file

@ -21,12 +21,59 @@ using namespace gpu;
// FIXME: Declare this to enable compression
//#define COMPRESS_TEXTURES
static const uvec2 SPARSE_PAGE_SIZE(128);
static const uvec2 MAX_TEXTURE_SIZE(4096);
bool DEV_DECIMATE_TEXTURES = false;
QImage processSourceImage(const QImage& srcImage) {
if (DEV_DECIMATE_TEXTURES) {
return srcImage.scaled(srcImage.size() * 0.5f);
bool needsSparseRectification(const uvec2& size) {
// Don't attempt to rectify small textures (textures less than the sparse page size in any dimension)
if (glm::any(glm::lessThan(size, SPARSE_PAGE_SIZE))) {
return false;
}
// Don't rectify textures that are already an exact multiple of sparse page size
if (uvec2(0) == (size % SPARSE_PAGE_SIZE)) {
return false;
}
// Texture is not sparse compatible, but is bigger than the sparse page size in both dimensions, rectify!
return true;
}
uvec2 rectifyToSparseSize(const uvec2& size) {
uvec2 pages = ((size / SPARSE_PAGE_SIZE) + glm::clamp(size % SPARSE_PAGE_SIZE, uvec2(0), uvec2(1)));
uvec2 result = pages * SPARSE_PAGE_SIZE;
return result;
}
std::atomic<size_t> DECIMATED_TEXTURE_COUNT { 0 };
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT { 0 };
QImage processSourceImage(const QImage& srcImage, bool cubemap) {
const uvec2 srcImageSize = toGlm(srcImage.size());
uvec2 targetSize = srcImageSize;
while (glm::any(glm::greaterThan(targetSize, MAX_TEXTURE_SIZE))) {
targetSize /= 2;
}
if (targetSize != srcImageSize) {
++DECIMATED_TEXTURE_COUNT;
}
if (!cubemap && needsSparseRectification(targetSize)) {
++RECTIFIED_TEXTURE_COUNT;
targetSize = rectifyToSparseSize(targetSize);
}
if (DEV_DECIMATE_TEXTURES && glm::all(glm::greaterThanEqual(targetSize / SPARSE_PAGE_SIZE, uvec2(2)))) {
targetSize /= 2;
}
if (targetSize != srcImageSize) {
qDebug() << "Resizing texture from " << srcImageSize.x << "x" << srcImageSize.y << " to " << targetSize.x << "x" << targetSize.y;
return srcImage.scaled(fromGlm(targetSize));
}
return srcImage;
}
@ -60,7 +107,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
}
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
validAlpha = false;
alphaAsMask = true;
const uint8 OPAQUE_ALPHA = 255;
@ -228,7 +275,7 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
@ -262,7 +309,7 @@ double mapComponent(double sobelValue) {
}
gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
@ -334,7 +381,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
}
gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
@ -368,7 +415,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
}
gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
@ -406,7 +453,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
}
gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
@ -699,7 +746,7 @@ const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS)
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
gpu::Texture* theTexture = nullptr;
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
QImage image = processSourceImage(srcImage);
QImage image = processSourceImage(srcImage, true);
if (image.format() != QImage::Format_RGB888) {
image = image.convertToFormat(QImage::Format_RGB888);
}
@ -709,7 +756,8 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
// Find the layout of the cubemap in the 2D image
int foundLayout = CubeLayout::findLayout(image.width(), image.height());
// Use the original image size since processSourceImage may have altered the size / aspect ratio
int foundLayout = CubeLayout::findLayout(srcImage.width(), srcImage.height());
std::vector<QImage> faces;
// If found, go extract the faces as separate images

View file

@ -164,11 +164,59 @@ class MyTestWindow : public TestWindow {
}
};
extern bool needsSparseRectification(const uvec2& size);
extern uvec2 rectifyToSparseSize(const uvec2& size);
int main(int argc, char** argv) {
void testSparseRectify() {
std::vector<std::pair<uvec2, bool>> NEEDS_SPARSE_TESTS {{
// Already sparse
{ {1024, 1024 }, false },
{ { 128, 128 }, false },
// Too small in one dimension
{ { 127, 127 }, false },
{ { 1, 1 }, false },
{ { 1000, 1 }, false },
{ { 1024, 1 }, false },
{ { 100, 100 }, false },
// needs rectification
{ { 1000, 1000 }, true },
{ { 1024, 1000 }, true },
} };
for (const auto& test : NEEDS_SPARSE_TESTS) {
const auto& size = test.first;
const auto& expected = test.second;
auto result = needsSparseRectification(size);
Q_ASSERT(expected == result);
result = needsSparseRectification(uvec2(size.y, size.x));
Q_ASSERT(expected == result);
}
std::vector<std::pair<uvec2, uvec2>> SPARSE_SIZE_TESTS { {
// needs rectification
{ { 1000, 1000 }, { 1024, 1024 } },
{ { 1024, 1000 }, { 1024, 1024 } },
} };
for (const auto& test : SPARSE_SIZE_TESTS) {
const auto& size = test.first;
const auto& expected = test.second;
auto result = rectifyToSparseSize(size);
Q_ASSERT(expected == result);
result = rectifyToSparseSize(uvec2(size.y, size.x));
Q_ASSERT(expected == uvec2(result.y, result.x));
}
}
int main(int argc, char** argv) {
testSparseRectify();
// FIXME this test appears to be broken
#if 0
QGuiApplication app(argc, argv);
MyTestWindow window;
app.exec();
#endif
return 0;
}