mirror of
https://github.com/JulianGro/overte.git
synced 2025-05-28 03:51:17 +02:00
Merge pull request #8893 from jherico/texture_force_sparse
Changes to texture loading rules
This commit is contained in:
commit
863bf067b7
6 changed files with 134 additions and 13 deletions
|
@ -205,6 +205,12 @@ Item {
|
||||||
StatText {
|
StatText {
|
||||||
text: " Count: " + root.gpuTextures;
|
text: " Count: " + root.gpuTextures;
|
||||||
}
|
}
|
||||||
|
StatText {
|
||||||
|
text: " Rectified: " + root.rectifiedTextureCount;
|
||||||
|
}
|
||||||
|
StatText {
|
||||||
|
text: " Decimated: " + root.decimatedTextureCount;
|
||||||
|
}
|
||||||
StatText {
|
StatText {
|
||||||
text: " Sparse Count: " + root.gpuTexturesSparse;
|
text: " Sparse Count: " + root.gpuTexturesSparse;
|
||||||
visible: 0 != root.gpuSparseTextureEnabled;
|
visible: 0 != root.gpuSparseTextureEnabled;
|
||||||
|
@ -228,6 +234,9 @@ Item {
|
||||||
StatText {
|
StatText {
|
||||||
text: " Count: " + root.gpuTextures;
|
text: " Count: " + root.gpuTextures;
|
||||||
}
|
}
|
||||||
|
StatText {
|
||||||
|
text: " Memory: " + root.gpuBufferMemory;
|
||||||
|
}
|
||||||
StatText {
|
StatText {
|
||||||
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
|
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
void Stats::updateStats(bool force) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
|
@ -289,6 +291,7 @@ void Stats::updateStats(bool force) {
|
||||||
}
|
}
|
||||||
|
|
||||||
STAT_UPDATE(gpuBuffers, (int)gpu::Context::getBufferGPUCount());
|
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(gpuTextures, (int)gpu::Context::getTextureGPUCount());
|
||||||
STAT_UPDATE(gpuTexturesSparse, (int)gpu::Context::getTextureGPUSparseCount());
|
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(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage()));
|
||||||
STAT_UPDATE(gpuSparseTextureEnabled, gpu::Texture::getEnableSparseTextures() ? 1 : 0);
|
STAT_UPDATE(gpuSparseTextureEnabled, gpu::Texture::getEnableSparseTextures() ? 1 : 0);
|
||||||
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()));
|
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
|
// Incoming packets
|
||||||
QLocale locale(QLocale::English);
|
QLocale locale(QLocale::English);
|
||||||
|
|
|
@ -87,7 +87,10 @@ class Stats : public QQuickItem {
|
||||||
STATS_PROPERTY(int, localElements, 0)
|
STATS_PROPERTY(int, localElements, 0)
|
||||||
STATS_PROPERTY(int, localInternal, 0)
|
STATS_PROPERTY(int, localInternal, 0)
|
||||||
STATS_PROPERTY(int, localLeaves, 0)
|
STATS_PROPERTY(int, localLeaves, 0)
|
||||||
|
STATS_PROPERTY(int, rectifiedTextureCount, 0)
|
||||||
|
STATS_PROPERTY(int, decimatedTextureCount, 0)
|
||||||
STATS_PROPERTY(int, gpuBuffers, 0)
|
STATS_PROPERTY(int, gpuBuffers, 0)
|
||||||
|
STATS_PROPERTY(int, gpuBufferMemory, 0)
|
||||||
STATS_PROPERTY(int, gpuTextures, 0)
|
STATS_PROPERTY(int, gpuTextures, 0)
|
||||||
STATS_PROPERTY(int, gpuTexturesSparse, 0)
|
STATS_PROPERTY(int, gpuTexturesSparse, 0)
|
||||||
STATS_PROPERTY(int, glContextSwapchainMemory, 0)
|
STATS_PROPERTY(int, glContextSwapchainMemory, 0)
|
||||||
|
@ -186,6 +189,7 @@ signals:
|
||||||
void glContextSwapchainMemoryChanged();
|
void glContextSwapchainMemoryChanged();
|
||||||
void qmlTextureMemoryChanged();
|
void qmlTextureMemoryChanged();
|
||||||
void gpuBuffersChanged();
|
void gpuBuffersChanged();
|
||||||
|
void gpuBufferMemoryChanged();
|
||||||
void gpuTexturesChanged();
|
void gpuTexturesChanged();
|
||||||
void gpuTexturesSparseChanged();
|
void gpuTexturesSparseChanged();
|
||||||
void gpuTextureMemoryChanged();
|
void gpuTextureMemoryChanged();
|
||||||
|
@ -194,6 +198,8 @@ signals:
|
||||||
void gpuTextureSparseMemoryChanged();
|
void gpuTextureSparseMemoryChanged();
|
||||||
void gpuSparseTextureEnabledChanged();
|
void gpuSparseTextureEnabledChanged();
|
||||||
void gpuFreeMemoryChanged();
|
void gpuFreeMemoryChanged();
|
||||||
|
void rectifiedTextureCountChanged();
|
||||||
|
void decimatedTextureCountChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
|
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
|
||||||
|
|
|
@ -102,12 +102,17 @@ float GLTexture::getMemoryPressure() {
|
||||||
|
|
||||||
// If no memory limit has been set, use a percentage of the total dedicated memory
|
// If no memory limit has been set, use a percentage of the total dedicated memory
|
||||||
if (!availableTextureMemory) {
|
if (!availableTextureMemory) {
|
||||||
|
#if 0
|
||||||
auto totalMemory = getDedicatedMemory();
|
auto totalMemory = getDedicatedMemory();
|
||||||
if ((GPU_MEMORY_RESERVE_BYTES + TEXTURE_MEMORY_MIN_BYTES) > totalMemory) {
|
if ((GPU_MEMORY_RESERVE_BYTES + TEXTURE_MEMORY_MIN_BYTES) > totalMemory) {
|
||||||
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
|
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
|
||||||
} else {
|
} else {
|
||||||
availableTextureMemory = totalMemory - GPU_MEMORY_RESERVE_BYTES;
|
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.
|
// Return the consumed texture memory divided by the available texture memory.
|
||||||
|
|
|
@ -21,12 +21,59 @@ using namespace gpu;
|
||||||
|
|
||||||
// FIXME: Declare this to enable compression
|
// FIXME: Declare this to enable compression
|
||||||
//#define COMPRESS_TEXTURES
|
//#define COMPRESS_TEXTURES
|
||||||
|
static const uvec2 SPARSE_PAGE_SIZE(128);
|
||||||
|
static const uvec2 MAX_TEXTURE_SIZE(4096);
|
||||||
bool DEV_DECIMATE_TEXTURES = false;
|
bool DEV_DECIMATE_TEXTURES = false;
|
||||||
QImage processSourceImage(const QImage& srcImage) {
|
|
||||||
if (DEV_DECIMATE_TEXTURES) {
|
bool needsSparseRectification(const uvec2& size) {
|
||||||
return srcImage.scaled(srcImage.size() * 0.5f);
|
// 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;
|
return srcImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +107,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
||||||
QImage image = processSourceImage(srcImage);
|
QImage image = processSourceImage(srcImage, false);
|
||||||
validAlpha = false;
|
validAlpha = false;
|
||||||
alphaAsMask = true;
|
alphaAsMask = true;
|
||||||
const uint8 OPAQUE_ALPHA = 255;
|
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) {
|
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) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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) {
|
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) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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) {
|
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.hasAlphaChannel()) {
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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) {
|
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.hasAlphaChannel()) {
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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) {
|
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.hasAlphaChannel()) {
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||||
QImage image = processSourceImage(srcImage);
|
QImage image = processSourceImage(srcImage, true);
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(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);
|
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||||
|
|
||||||
// Find the layout of the cubemap in the 2D image
|
// 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;
|
std::vector<QImage> faces;
|
||||||
// If found, go extract the faces as separate images
|
// If found, go extract the faces as separate images
|
||||||
|
|
|
@ -164,11 +164,59 @@ class MyTestWindow : public TestWindow {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern bool needsSparseRectification(const uvec2& size);
|
||||||
|
extern uvec2 rectifyToSparseSize(const uvec2& size);
|
||||||
|
|
||||||
|
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) {
|
int main(int argc, char** argv) {
|
||||||
|
testSparseRectify();
|
||||||
|
|
||||||
|
// FIXME this test appears to be broken
|
||||||
|
#if 0
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
MyTestWindow window;
|
MyTestWindow window;
|
||||||
app.exec();
|
app.exec();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue