Skip to content

Commit

Permalink
render: Initial attempt at adding SDL_GenerateTextureMipmap().
Browse files Browse the repository at this point in the history
This is only implemented for the OpenGL and OpenGL ES 2 backends currently,
and is completely untested, beyond it compiles on my laptop.

Fixes #4156.
  • Loading branch information
icculus committed Jul 16, 2024
1 parent 1592452 commit d227640
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 15 deletions.
19 changes: 19 additions & 0 deletions include/SDL3/SDL_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,25 @@ extern SDL_DECLSPEC int SDLCALL SDL_LockTextureToSurface(SDL_Texture *texture,
*/
extern SDL_DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture *texture);

/**
* Generate mipmaps for a texture.
*
* This may make this texture render better when downscaling for future
* draw calls. When updating a texture, call this function to regenerate
* mipmaps.
*
* This might not be a cheap operation, use it sparingly!
*
* Not every renderer supports this, but when unsupported, downscaled textures
* will just perhaps scale a little less well.
*
* \param texture a texture locked by SDL_LockTexture().
* \returns 0 on success, or -1 on error.
*
* \since This function is available since SDL 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL SDL_GenerateTextureMipmap(SDL_Texture *texture);

/**
* Set a texture as the current rendering target.
*
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ SDL3_0.0.0 {
SDL_GamepadHasButton;
SDL_GamepadHasSensor;
SDL_GamepadSensorEnabled;
SDL_GenerateTextureMipmap;
SDL_GetAndroidActivity;
SDL_GetAndroidCachePath;
SDL_GetAndroidExternalStoragePath;
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
#define SDL_GamepadHasButton SDL_GamepadHasButton_REAL
#define SDL_GamepadHasSensor SDL_GamepadHasSensor_REAL
#define SDL_GamepadSensorEnabled SDL_GamepadSensorEnabled_REAL
#define SDL_GenerateTextureMipmap SDL_GenerateTextureMipmap_REAL
#define SDL_GetAndroidActivity SDL_GetAndroidActivity_REAL
#define SDL_GetAndroidCachePath SDL_GetAndroidCachePath_REAL
#define SDL_GetAndroidExternalStoragePath SDL_GetAndroidExternalStoragePath_REAL
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GamepadHasAxis,(SDL_Gamepad *a, SDL_GamepadAxis b),
SDL_DYNAPI_PROC(SDL_bool,SDL_GamepadHasButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GamepadHasSensor,(SDL_Gamepad *a, SDL_SensorType b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GamepadSensorEnabled,(SDL_Gamepad *a, SDL_SensorType b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GenerateTextureMipmap,(SDL_Texture *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_GetAndroidActivity,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetAndroidCachePath,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetAndroidExternalStoragePath,(void),(),return)
Expand Down
15 changes: 15 additions & 0 deletions src/render/SDL_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,21 @@ static int SDL_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *text
return 0;
}

int SDL_GenerateTextureMipmap(SDL_Texture *texture)
{
CHECK_TEXTURE_MAGIC(texture, -1);

SDL_Renderer *renderer = texture->renderer;

if (!renderer->GenMipmaps) {
return SDL_Unsupported();
} else if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
return -1;
}

return renderer->GenMipmaps(renderer, texture);
}

int SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
{
if (!texture && renderer->logical_target) {
Expand Down
1 change: 1 addition & 0 deletions src/render/SDL_sysrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ struct SDL_Renderer
const SDL_Rect *rect, void **pixels, int *pitch);
void (*UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture);
void (*SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode);
int (*GenMipmaps)(SDL_Renderer *renderer, SDL_Texture *texture);
int (*SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture);
SDL_Surface *(*RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect);
int (*RenderPresent)(SDL_Renderer *renderer);
Expand Down
54 changes: 39 additions & 15 deletions src/render/opengl/SDL_render_gl.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ typedef struct
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;

/* glGenerateMipmap support */
PFNGLGENERATEMIPMAPPROC glGenerateMipmap;

/* Shader support */
GL_ShaderContext *shaders;

Expand Down Expand Up @@ -843,6 +846,24 @@ static void GL_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
}

static int GL_GenMipmaps(SDL_Renderer *renderer, SDL_Texture *texture)
{
GL_RenderData *renderdata = (GL_RenderData *)renderer->driverdata;
SDL_assert(renderdata->glGenerateMipmap != NULL); // should have been set up at CreateRenderer time and we shouldn't be here if it isn't!

if (texture != renderdata->drawstate.texture) {
if (renderdata->GL_ARB_multitexture_supported) {
renderdata->glActiveTextureARB(GL_TEXTURE0_ARB);
}
const GL_TextureData *texturedata = (GL_TextureData *)texture->driverdata;
renderdata->glBindTexture(renderdata->textype, texturedata->texture);
renderdata->drawstate.texture = texture;
}

renderdata->glGenerateMipmap(renderdata->textype);
return 0; // GL does not report failure here.
}

static void GL_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
{
GL_RenderData *renderdata = (GL_RenderData *)renderer->driverdata;
Expand Down Expand Up @@ -1719,23 +1740,21 @@ static int GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Pro
data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
}

int glmajorver = 1;
const char *glverstr = (const char *)data->glGetString(GL_VERSION);
if (glverstr) {
char verbuf[16];
SDL_strlcpy(verbuf, glverstr, sizeof(verbuf));
char *ptr = SDL_strchr(verbuf, '.');
if (ptr) {
*ptr = '\0';
glmajorver = SDL_atoi(verbuf);
}
}

hint = SDL_getenv("GL_ARB_texture_non_power_of_two");
if (!hint || *hint != '0') {
SDL_bool isGL2 = SDL_FALSE;
const char *verstr = (const char *)data->glGetString(GL_VERSION);
if (verstr) {
char verbuf[16];
char *ptr;
SDL_strlcpy(verbuf, verstr, sizeof(verbuf));
ptr = SDL_strchr(verbuf, '.');
if (ptr) {
*ptr = '\0';
if (SDL_atoi(verbuf) >= 2) {
isGL2 = SDL_TRUE;
}
}
}
if (isGL2 || SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
if ((glmajorver >= 2) || SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
non_power_of_two_supported = SDL_TRUE;
}
}
Expand Down Expand Up @@ -1765,6 +1784,11 @@ static int GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Pro
}
}

if (glmajorver >= 3) {
data->glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)SDL_GL_GetProcAddress("glGenerateMipmap");
renderer->GenMipmaps = (data->glGenerateMipmap != NULL) ? GL_GenMipmaps : NULL;
}

/* Check for shader support */
data->shaders = GL_CreateShaderContext();
SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
Expand Down
1 change: 1 addition & 0 deletions src/render/opengles2/SDL_gles2funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ SDL_PROC(void, glDeleteBuffers, (GLsizei, const GLuint *))
SDL_PROC(void, glBindBuffer, (GLenum, GLuint))
SDL_PROC(void, glBufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum))
SDL_PROC(void, glBufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *))
SDL_PROC(void, glGenerateMipmap, (GLenum))
17 changes: 17 additions & 0 deletions src/render/opengles2/SDL_render_gles2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,22 @@ static void GLES2_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *textu
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
}

static int GLES2_GenMipmaps(SDL_Renderer *renderer, SDL_Texture *texture)
{
GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->driverdata;
SDL_assert(renderdata->glGenerateMipmap != NULL); // this should have been set up at CreateRenderer time and we shouldn't be here if it isn't!

const GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
if (texture != renderdata->drawstate.texture) {
renderdata->glActiveTexture(GL_TEXTURE0);
renderdata->glBindTexture(tdata->texture_type, tdata->texture);
renderdata->drawstate.texture = texture;
}

renderdata->glGenerateMipmap(tdata->texture_type);
return 0; // GLES2 does not report failure here.
}

static int GLES2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
{
GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
Expand Down Expand Up @@ -2152,6 +2168,7 @@ static int GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_
renderer->LockTexture = GLES2_LockTexture;
renderer->UnlockTexture = GLES2_UnlockTexture;
renderer->SetTextureScaleMode = GLES2_SetTextureScaleMode;
renderer->GenMipmaps = GLES2_GenMipmaps; // always available since OpenGL ES 2.0.
renderer->SetRenderTarget = GLES2_SetRenderTarget;
renderer->QueueSetViewport = GLES2_QueueNoOp;
renderer->QueueSetDrawColor = GLES2_QueueNoOp;
Expand Down

0 comments on commit d227640

Please sign in to comment.