Revert of 971f2a08e2 - Fix mipmap of compressed textures on AMD Radeon graphics cards by forcing the use of squared power of two textures

Changed nanosvg library from https://github.com/memononen/nanosvg to https://github.com/fltk/nanosvg which contains the definition of the new function nsvgRasterizeXY()
This commit is contained in:
enricoturri1966 2023-01-19 09:26:47 +01:00
parent ecc3211c18
commit eee4453993
4 changed files with 61 additions and 40 deletions

View File

@ -1,4 +1,9 @@
# In PrusaSlicer 2.6.0 we switched from https://github.com/memononen/nanosvg to its fork https://github.com/fltk/nanosvg
# because this last implements the new function nsvgRasterizeXY() which we now use in GLTexture::load_from_svg()
# for rasterizing svg files from their original size to a squared power of two texture on Windows systems using
# AMD Radeon graphics cards
prusaslicer_add_cmake_project(NanoSVG prusaslicer_add_cmake_project(NanoSVG
URL https://github.com/memononen/nanosvg/archive/4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148.zip URL https://github.com/fltk/nanosvg/archive/abcd277ea45e9098bed752cf9c6875b533c0892f.zip
URL_HASH SHA256=584e084af1a75bf633f79753ce2f6f6ec8686002ca27f35f1037c25675fecfb6 URL_HASH SHA256=e859938fbaee4b351bd8a8b3d3c7a75b40c36885ce00b73faa1ce0b98aa0ad34
) )

View File

@ -375,10 +375,29 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right,
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
static bool to_squared_power_of_two(const std::string& filename, int max_size_px, int& w, int& h)
{
auto is_power_of_two = [](int v) { return v != 0 && (v & (v - 1)) == 0; };
auto upper_power_of_two = [](int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; };
int new_w = std::max(w, h);
if (!is_power_of_two(new_w))
new_w = upper_power_of_two(new_w);
while (new_w > max_size_px) {
new_w /= 2;
}
const int new_h = new_w;
const bool ret = (new_w != w || new_h != h);
w = new_w;
h = new_h;
return ret;
}
bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy) bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECompressionType compression_type, bool apply_anisotropy)
{ {
const bool compression_enabled = (compression_type != None) && OpenGLManager::are_compressed_textures_supported(); const bool compression_enabled = (compression_type != None) && OpenGLManager::are_compressed_textures_supported();
const bool use_compressor = compression_enabled && OpenGLManager::use_manually_generated_mipmaps();
// Load a PNG with an alpha channel. // Load a PNG with an alpha channel.
wxImage image; wxImage image;
@ -392,6 +411,11 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
bool requires_rescale = false; bool requires_rescale = false;
if (use_mipmaps && compression_enabled && OpenGLManager::force_power_of_two_textures()) {
if (to_squared_power_of_two(boost::filesystem::path(filename).filename().string(), OpenGLManager::get_gl_info().get_max_tex_size(), m_width, m_height))
requires_rescale = true;
}
if (compression_enabled && compression_type == MultiThreaded) { if (compression_enabled && compression_type == MultiThreaded) {
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 4 // the stb_dxt compression library seems to like only texture sizes which are a multiple of 4
int width_rem = m_width % 4; int width_rem = m_width % 4;
@ -448,7 +472,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
} }
if (compression_enabled) { if (compression_enabled) {
if (compression_type == SingleThreaded || !use_compressor) if (compression_type == SingleThreaded)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
else { else {
// initializes the texture on GPU // initializes the texture on GPU
@ -460,7 +484,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
else else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
if (use_mipmaps && OpenGLManager::use_manually_generated_mipmaps()) { if (use_mipmaps) {
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
int lod_w = m_width; int lod_w = m_width;
int lod_h = m_height; int lod_h = m_height;
@ -507,10 +531,6 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
} }
} }
else if (use_mipmaps && !OpenGLManager::use_manually_generated_mipmaps()) {
glsafe(::glGenerateMipmap(GL_TEXTURE_2D));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
}
else { else {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
@ -522,7 +542,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
m_source = filename; m_source = filename;
if (use_compressor && compression_type == MultiThreaded) if (compression_type == MultiThreaded)
// start asynchronous compression // start asynchronous compression
m_compressor.start_compressing(); m_compressor.start_compressing();
@ -532,7 +552,6 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px) bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px)
{ {
const bool compression_enabled = compress && OpenGLManager::are_compressed_textures_supported(); const bool compression_enabled = compress && OpenGLManager::are_compressed_textures_supported();
const bool use_compressor = compression_enabled && OpenGLManager::use_manually_generated_mipmaps();
NSVGimage* image = BitmapCache::nsvgParseFromFileWithReplace(filename.c_str(), "px", 96.0f, {}); NSVGimage* image = BitmapCache::nsvgParseFromFileWithReplace(filename.c_str(), "px", 96.0f, {});
if (image == nullptr) { if (image == nullptr) {
@ -540,11 +559,17 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
return false; return false;
} }
float scale = (float)max_size_px / std::max(image->width, image->height); const float scale = (float)max_size_px / std::max(image->width, image->height);
m_width = (int)(scale * image->width); m_width = (int)(scale * image->width);
m_height = (int)(scale * image->height); m_height = (int)(scale * image->height);
if (use_mipmaps && compression_enabled && OpenGLManager::force_power_of_two_textures())
to_squared_power_of_two(boost::filesystem::path(filename).filename().string(), max_size_px, m_width, m_height);
float scale_w = (float)m_width / image->width;
float scale_h = (float)m_height / image->height;
if (compression_enabled) { if (compression_enabled) {
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 4 // the stb_dxt compression library seems to like only texture sizes which are a multiple of 4
int width_rem = m_width % 4; int width_rem = m_width % 4;
@ -574,7 +599,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
// creates the temporary buffer only once, with max size, and reuse it for all the levels, if generating mipmaps // creates the temporary buffer only once, with max size, and reuse it for all the levels, if generating mipmaps
std::vector<unsigned char> data(n_pixels * 4, 0); std::vector<unsigned char> data(n_pixels * 4, 0);
nsvgRasterize(rast, image, 0, 0, scale, data.data(), m_width, m_height, m_width * 4); nsvgRasterizeXY(rast, image, 0, 0, scale_w, scale_h, data.data(), m_width, m_height, m_width * 4);
// sends data to gpu // sends data to gpu
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
@ -588,19 +613,15 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
} }
if (compression_enabled) { if (compression_enabled) {
if (use_compressor) { // initializes the texture on GPU
// initializes the texture on GPU glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); // and send the uncompressed data to the compressor
// and send the uncompressed data to the compressor m_compressor.add_level((unsigned int)m_width, (unsigned int)m_height, data);
m_compressor.add_level((unsigned int)m_width, (unsigned int)m_height, data);
}
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
} }
else else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()));
if (use_mipmaps && OpenGLManager::use_manually_generated_mipmaps()) { if (use_mipmaps) {
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
int lod_w = m_width; int lod_w = m_width;
int lod_h = m_height; int lod_h = m_height;
@ -610,11 +631,12 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
lod_w = std::max(lod_w / 2, 1); lod_w = std::max(lod_w / 2, 1);
lod_h = std::max(lod_h / 2, 1); lod_h = std::max(lod_h / 2, 1);
scale /= 2.0f; scale_w /= 2.0f;
scale_h /= 2.0f;
data.resize(lod_w * lod_h * 4); data.resize(lod_w * lod_h * 4);
nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); nsvgRasterizeXY(rast, image, 0, 0, scale_w, scale_h, data.data(), lod_w, lod_h, lod_w * 4);
if (compression_enabled) { if (compression_enabled) {
// initializes the texture on GPU // initializes the texture on GPU
glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
@ -630,10 +652,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
} }
} }
else if (use_mipmaps && !OpenGLManager::use_manually_generated_mipmaps()) {
glsafe(::glGenerateMipmap(GL_TEXTURE_2D));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
}
else { else {
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
@ -645,7 +663,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
m_source = filename; m_source = filename;
if (use_compressor) if (compression_enabled)
// start asynchronous compression // start asynchronous compression
m_compressor.start_compressing(); m_compressor.start_compressing();

View File

@ -200,7 +200,6 @@ std::string OpenGLManager::GLInfo::to_string(bool for_github) const
out << b_start << "Renderer: " << b_end << m_renderer << line_end; out << b_start << "Renderer: " << b_end << m_renderer << line_end;
out << b_start << "GLSL version: " << b_end << m_glsl_version << line_end; out << b_start << "GLSL version: " << b_end << m_glsl_version << line_end;
out << b_start << "Textures compression: " << b_end << (are_compressed_textures_supported() ? "Enabled" : "Disabled") << line_end; out << b_start << "Textures compression: " << b_end << (are_compressed_textures_supported() ? "Enabled" : "Disabled") << line_end;
out << b_start << "Textures mipmap generation: " << b_end << (use_manually_generated_mipmaps() ? "Manual" : "Automatic") << line_end;
{ {
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
@ -257,7 +256,7 @@ std::vector<std::string> OpenGLManager::GLInfo::get_extensions_list() const
OpenGLManager::GLInfo OpenGLManager::s_gl_info; OpenGLManager::GLInfo OpenGLManager::s_gl_info;
bool OpenGLManager::s_compressed_textures_supported = false; bool OpenGLManager::s_compressed_textures_supported = false;
bool OpenGLManager::s_use_manually_generated_mipmaps = true; bool OpenGLManager::s_force_power_of_two_textures = false;
OpenGLManager::EMultisampleState OpenGLManager::s_multisample = OpenGLManager::EMultisampleState::Unknown; OpenGLManager::EMultisampleState OpenGLManager::s_multisample = OpenGLManager::EMultisampleState::Unknown;
OpenGLManager::EFramebufferType OpenGLManager::s_framebuffers_type = OpenGLManager::EFramebufferType::Unknown; OpenGLManager::EFramebufferType OpenGLManager::s_framebuffers_type = OpenGLManager::EFramebufferType::Unknown;
@ -415,17 +414,16 @@ bool OpenGLManager::init_gl()
// texture of the bed (see: https://github.com/prusa3d/PrusaSlicer/issues/8417). // texture of the bed (see: https://github.com/prusa3d/PrusaSlicer/issues/8417).
// It seems that this issue only triggers when mipmaps are generated manually // It seems that this issue only triggers when mipmaps are generated manually
// (combined with a texture compression) with texture size not being power of two. // (combined with a texture compression) with texture size not being power of two.
// When mipmaps are generated through OpenGL function glGenerateMipmap() the driver works fine. // When mipmaps are generated through OpenGL function glGenerateMipmap() the driver works fine,
// but the mipmap generation is quite slow on some machines.
// There is no an easy way to detect the driver version without using Win32 API because the strings returned by OpenGL // There is no an easy way to detect the driver version without using Win32 API because the strings returned by OpenGL
// have no standardized format, only some of them contain the driver version. // have no standardized format, only some of them contain the driver version.
// Until we do not know that driver will be fixed (if ever) we force the use of glGenerateMipmap() on all cards // Until we do not know that driver will be fixed (if ever) we force the use of power of two textures on all cards
// containing the string 'Radeon' in the string returned by glGetString(GL_RENDERER) // containing the string 'Radeon' in the string returned by glGetString(GL_RENDERER)
const auto& gl_info = OpenGLManager::get_gl_info(); const auto& gl_info = OpenGLManager::get_gl_info();
if (boost::contains(gl_info.get_vendor(), "ATI Technologies Inc.") && boost::contains(gl_info.get_renderer(), "Radeon")) { if (boost::contains(gl_info.get_vendor(), "ATI Technologies Inc.") && boost::contains(gl_info.get_renderer(), "Radeon"))
s_use_manually_generated_mipmaps = false; s_force_power_of_two_textures = true;
BOOST_LOG_TRIVIAL(debug) << "Mipmapping through OpenGL was enabled."; #endif // _WIN32
}
#endif
} }
return true; return true;

View File

@ -110,7 +110,7 @@ private:
static OSInfo s_os_info; static OSInfo s_os_info;
#endif //__APPLE__ #endif //__APPLE__
static bool s_compressed_textures_supported; static bool s_compressed_textures_supported;
static bool s_use_manually_generated_mipmaps; static bool s_force_power_of_two_textures;
static EMultisampleState s_multisample; static EMultisampleState s_multisample;
static EFramebufferType s_framebuffers_type; static EFramebufferType s_framebuffers_type;
@ -139,7 +139,7 @@ public:
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; } static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
static wxGLCanvas* create_wxglcanvas(wxWindow& parent); static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
static const GLInfo& get_gl_info() { return s_gl_info; } static const GLInfo& get_gl_info() { return s_gl_info; }
static bool use_manually_generated_mipmaps() { return s_use_manually_generated_mipmaps; } static bool force_power_of_two_textures() { return s_force_power_of_two_textures; }
private: private:
#if ENABLE_GL_CORE_PROFILE || ENABLE_OPENGL_ES #if ENABLE_GL_CORE_PROFILE || ENABLE_OPENGL_ES