Move texture management out of screen.c, which already handles the window and the rendering. This paves the way to implement optional software filtering (swscale) properly, as an alternative to mipmaps (which are not available everywhere).
121 lines
3.8 KiB
C
121 lines
3.8 KiB
C
#include "frame_texture.h"
|
|
|
|
#include "util/log.h"
|
|
|
|
static SDL_Texture *
|
|
create_texture(struct sc_frame_texture *ftex, struct size size) {
|
|
SDL_Renderer *renderer = ftex->renderer;
|
|
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
|
SDL_TEXTUREACCESS_STREAMING,
|
|
size.width, size.height);
|
|
if (!texture) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ftex->mipmaps) {
|
|
struct sc_opengl *gl = &ftex->gl;
|
|
|
|
SDL_GL_BindTexture(texture, NULL, NULL);
|
|
|
|
// Enable trilinear filtering for downscaling
|
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
GL_LINEAR_MIPMAP_LINEAR);
|
|
gl->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.f);
|
|
|
|
SDL_GL_UnbindTexture(texture);
|
|
}
|
|
|
|
return texture;
|
|
}
|
|
|
|
bool
|
|
sc_frame_texture_init(struct sc_frame_texture *ftex, SDL_Renderer *renderer,
|
|
bool mipmaps, struct size initial_size) {
|
|
SDL_RendererInfo renderer_info;
|
|
int r = SDL_GetRendererInfo(renderer, &renderer_info);
|
|
const char *renderer_name = r ? NULL : renderer_info.name;
|
|
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
|
|
|
ftex->mipmaps = false;
|
|
|
|
// starts with "opengl"
|
|
bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
|
if (use_opengl) {
|
|
struct sc_opengl *gl = &ftex->gl;
|
|
sc_opengl_init(gl);
|
|
|
|
LOGI("OpenGL version: %s", gl->version);
|
|
|
|
if (mipmaps) {
|
|
bool supports_mipmaps =
|
|
sc_opengl_version_at_least(gl, 3, 0, /* OpenGL 3.0+ */
|
|
2, 0 /* OpenGL ES 2.0+ */);
|
|
if (supports_mipmaps) {
|
|
LOGI("Trilinear filtering enabled");
|
|
ftex->mipmaps = true;
|
|
} else {
|
|
LOGW("Trilinear filtering disabled "
|
|
"(OpenGL 3.0+ or ES 2.0+ required)");
|
|
}
|
|
} else {
|
|
LOGI("Trilinear filtering disabled");
|
|
}
|
|
} else {
|
|
LOGD("Trilinear filtering disabled (not an OpenGL renderer)");
|
|
}
|
|
|
|
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, initial_size.width,
|
|
initial_size.height);
|
|
ftex->renderer = renderer;
|
|
ftex->texture = create_texture(ftex, initial_size);
|
|
if (!ftex->texture) {
|
|
LOGC("Could not create texture: %s", SDL_GetError());
|
|
SDL_DestroyRenderer(ftex->renderer);
|
|
return false;
|
|
}
|
|
|
|
ftex->texture_size = initial_size;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
sc_frame_texture_destroy(struct sc_frame_texture *ftex) {
|
|
if (ftex->texture) {
|
|
SDL_DestroyTexture(ftex->texture);
|
|
}
|
|
}
|
|
|
|
bool
|
|
sc_frame_texture_update(struct sc_frame_texture *ftex, const AVFrame *frame) {
|
|
struct size frame_size = {frame->width, frame->height};
|
|
if (ftex->texture_size.width != frame_size.width
|
|
|| ftex->texture_size.height != frame_size.height) {
|
|
// Frame dimensions changed, destroy texture
|
|
SDL_DestroyTexture(ftex->texture);
|
|
|
|
LOGI("New texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
|
frame_size.height);
|
|
ftex->texture = create_texture(ftex, frame_size);
|
|
if (!ftex->texture) {
|
|
LOGC("Could not create texture: %s", SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
ftex->texture_size = frame_size;
|
|
}
|
|
|
|
SDL_UpdateYUVTexture(ftex->texture, NULL,
|
|
frame->data[0], frame->linesize[0],
|
|
frame->data[1], frame->linesize[1],
|
|
frame->data[2], frame->linesize[2]);
|
|
|
|
if (ftex->mipmaps) {
|
|
SDL_GL_BindTexture(ftex->texture, NULL, NULL);
|
|
ftex->gl.GenerateMipmap(GL_TEXTURE_2D);
|
|
SDL_GL_UnbindTexture(ftex->texture);
|
|
}
|
|
|
|
return true;
|
|
}
|