-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
render: Initial attempt at adding SDL_GenerateTextureMipmap(). #10254
base: main
Are you sure you want to change the base?
Conversation
Some notes:
|
We could easily add mipmaps as a texture creation property, and trilinear filtering to the blend mode (that’s where it would go, right?) |
For mipmap filtering, it's pretty much a So there could be a |
Maybe we make the creation flag/property that says "this texture wants mipmapping" and we create the texture appropriately, and then automatically (re)generate mipmaps when the app changes a texture (SDL_UpdateTexture, SDL_UnlockTexture, or unbinds it as a render target), and remove the SDL_GenerateTextureMipmap function call entirely. |
if (glmajorver >= 3) { | ||
data->glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)SDL_GL_GetProcAddress("glGenerateMipmap"); | ||
renderer->GenMipmaps = (data->glGenerateMipmap != NULL) ? GL_GenMipmaps : NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For OpenGL < 3, glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE) can be used as a fallback.
renderdata->drawstate.texture = texture; | ||
} | ||
|
||
renderdata->glGenerateMipmap(renderdata->textype); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mipmaps need one of GL_*_MIPMAP_*
modes (e.g GL_LINEAR_MIPMAP_LINEAR
) for GL_TEXTURE_MIN_FILTER
to have effect. See https://www.khronos.org/opengl/wiki/Common_Mistakes#Automatic_mipmap_generation
renderdata->glGenerateMipmap(renderdata->textype); | ||
return 0; // GL does not report failure here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, glGenerateMipmap does report errors (in particular, for NPOT textures):
https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGenerateMipmap.xml
In terms of OpenGL, trillinerar filtering is |
This seems like a good idea to me. |
Thoughts on filter modes: That said, I've always just ended up using trilinear. For my use cases the quality is usually the best and the performance hit has never mattered for me (the performance bottleneck is always somewhere else).
Yes, I also agree that this is a good way to do it. |
In practice, But this case is irrelevant for 2D drawing, so |
This is only implemented for the OpenGL and OpenGL ES 2 backends currently, and is completely untested, beyond it compiles on my laptop. Fixes libsdl-org#4156.
b83aab8
to
d227640
Compare
(Just force-pushed to resolve conflicts, no changes to this yet.) |
Mipmaps can be generated in software to have better control over all backends and how mipmaps are looking when rendered to the screen (regardless of chosen backend). For example, I do manually generate mipmaps because I have a fallback renderer of SDL2 software which does not support mipmaps (and probably will never support with your current approach in this pull request). However, with some clever tricks it can by choosing underlying texture to render depending on the scaled rectangle (mipmap level). In my case when I want to draw something using software renderer in SDL I do the following: Rect mipMapSrc = src;
if(texture->hasMipmaps()) {
int level = mipmap(src.width(), dst.width());
texture->setMipMap(level);
mipMapSrc >>= level; // just divide the rectangle by power of 2 depending on the mipmap level since the source texture is now smaller
}
draw(texture, dst, mipMapSrc);
/*
.......
.......
.......
*/
#if defined(__clang__) || defined(__GNUC__)
inline int log2_fast(float d) { return 8 * sizeof(unsigned long long) - __builtin_clzll(d) - 1; }
#else
inline int log2_fast(float d) { int r; std::frexp(d, &r); return r - 1; }
#endif
inline int mipmap(float src, float dst) { return std::max<int>(log2_fast(src / dst), 0); }
Perhaps it would be worth to consider such approach. It purely depends on your goals. Of course this is simplified idea when drawing 2D quads (width equals height). |
This is only implemented for the OpenGL and OpenGL ES 2 backends currently, and is completely untested, beyond it compiles on my laptop.
This is a draft until it gets comments and more backends. Metal is easy to implement, Vulkan and D3D11+ probably are (...?), and Direct3D 9 will need us to roll our own, to which I say we should probably just leave it unimplemented there.
Fixes #4156.