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:
parent
ecc3211c18
commit
eee4453993
9
deps/NanoSVG/NanoSVG.cmake
vendored
9
deps/NanoSVG/NanoSVG.cmake
vendored
@ -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
|
||||
URL https://github.com/memononen/nanosvg/archive/4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148.zip
|
||||
URL_HASH SHA256=584e084af1a75bf633f79753ce2f6f6ec8686002ca27f35f1037c25675fecfb6
|
||||
URL https://github.com/fltk/nanosvg/archive/abcd277ea45e9098bed752cf9c6875b533c0892f.zip
|
||||
URL_HASH SHA256=e859938fbaee4b351bd8a8b3d3c7a75b40c36885ce00b73faa1ce0b98aa0ad34
|
||||
)
|
@ -375,10 +375,29 @@ void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right,
|
||||
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)
|
||||
{
|
||||
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.
|
||||
wxImage image;
|
||||
@ -392,6 +411,11 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
|
||||
|
||||
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) {
|
||||
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 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_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()));
|
||||
else {
|
||||
// initializes the texture on GPU
|
||||
@ -460,7 +484,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps, ECo
|
||||
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()));
|
||||
|
||||
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
|
||||
int lod_w = m_width;
|
||||
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));
|
||||
}
|
||||
}
|
||||
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 {
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
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;
|
||||
|
||||
if (use_compressor && compression_type == MultiThreaded)
|
||||
if (compression_type == MultiThreaded)
|
||||
// start asynchronous compression
|
||||
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)
|
||||
{
|
||||
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, {});
|
||||
if (image == nullptr) {
|
||||
@ -540,11 +559,17 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo
|
||||
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_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) {
|
||||
// the stb_dxt compression library seems to like only texture sizes which are a multiple of 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
|
||||
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
|
||||
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 (use_compressor) {
|
||||
// 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));
|
||||
// and send the uncompressed data to the compressor
|
||||
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
|
||||
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
|
||||
int lod_w = m_width;
|
||||
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_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);
|
||||
|
||||
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) {
|
||||
// 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));
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
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 {
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
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;
|
||||
|
||||
if (use_compressor)
|
||||
if (compression_enabled)
|
||||
// start asynchronous compression
|
||||
m_compressor.start_compressing();
|
||||
|
||||
|
@ -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 << "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 mipmap generation: " << b_end << (use_manually_generated_mipmaps() ? "Manual" : "Automatic") << line_end;
|
||||
|
||||
{
|
||||
#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;
|
||||
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::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).
|
||||
// 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.
|
||||
// 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
|
||||
// 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)
|
||||
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")) {
|
||||
s_use_manually_generated_mipmaps = false;
|
||||
BOOST_LOG_TRIVIAL(debug) << "Mipmapping through OpenGL was enabled.";
|
||||
}
|
||||
#endif
|
||||
if (boost::contains(gl_info.get_vendor(), "ATI Technologies Inc.") && boost::contains(gl_info.get_renderer(), "Radeon"))
|
||||
s_force_power_of_two_textures = true;
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -110,7 +110,7 @@ private:
|
||||
static OSInfo s_os_info;
|
||||
#endif //__APPLE__
|
||||
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 EFramebufferType s_framebuffers_type;
|
||||
@ -139,7 +139,7 @@ public:
|
||||
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
|
||||
static wxGLCanvas* create_wxglcanvas(wxWindow& parent);
|
||||
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:
|
||||
#if ENABLE_GL_CORE_PROFILE || ENABLE_OPENGL_ES
|
||||
|
Loading…
Reference in New Issue
Block a user