Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
91c5e7e626 | ||
|
7c851cdb2d | ||
|
08a175b7f1 | ||
|
9f029da2f9 |
21
FAQ.md
21
FAQ.md
@ -134,18 +134,27 @@ that's all. See [#37].
|
|||||||
|
|
||||||
### The quality is low
|
### The quality is low
|
||||||
|
|
||||||
On Windows, you may need to configure the [scaling behavior].
|
If the definition of your client window is smaller than that of your device
|
||||||
|
screen, then you might get poor quality, especially visible on text (see [#40]).
|
||||||
|
|
||||||
|
[#40]: https://github.com/Genymobile/scrcpy/issues/40
|
||||||
|
|
||||||
|
To improve downscaling quality, trilinear filtering is enabled automatically
|
||||||
|
if the renderer is OpenGL and if it supports mipmapping.
|
||||||
|
|
||||||
|
On Windows or macOS, you might need to force OpenGL:
|
||||||
|
|
||||||
|
```
|
||||||
|
scrcpy --render-driver=opengl
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, you may also need to configure the [scaling behavior].
|
||||||
|
|
||||||
> `scrcpy.exe` > Properties > Compatibility > Change high DPI settings >
|
> `scrcpy.exe` > Properties > Compatibility > Change high DPI settings >
|
||||||
> Override high DPI scaling behavior > Scaling performed by: _Application_.
|
> Override high DPI scaling behavior > Scaling performed by: _Application_.
|
||||||
|
|
||||||
[scaling behavior]: https://github.com/Genymobile/scrcpy/issues/40#issuecomment-424466723
|
[scaling behavior]: https://github.com/Genymobile/scrcpy/issues/40#issuecomment-424466723
|
||||||
|
|
||||||
If the definition of your client window is far smaller than that of your device
|
|
||||||
screen, then you'll get poor quality. This is especially visible on text. See
|
|
||||||
[#40].
|
|
||||||
|
|
||||||
[#40]: https://github.com/Genymobile/scrcpy/issues/40
|
|
||||||
|
|
||||||
|
|
||||||
### KWin compositor crashes
|
### KWin compositor crashes
|
||||||
|
@ -11,6 +11,7 @@ src = [
|
|||||||
'src/file_handler.c',
|
'src/file_handler.c',
|
||||||
'src/fps_counter.c',
|
'src/fps_counter.c',
|
||||||
'src/input_manager.c',
|
'src/input_manager.c',
|
||||||
|
'src/opengl.c',
|
||||||
'src/receiver.c',
|
'src/receiver.c',
|
||||||
'src/recorder.c',
|
'src/recorder.c',
|
||||||
'src/scrcpy.c',
|
'src/scrcpy.c',
|
||||||
|
12
app/scrcpy.1
12
app/scrcpy.1
@ -74,6 +74,10 @@ Disable device control (mirror the device in read\-only).
|
|||||||
.B \-N, \-\-no\-display
|
.B \-N, \-\-no\-display
|
||||||
Do not display device (only when screen recording is enabled).
|
Do not display device (only when screen recording is enabled).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-mipmaps
|
||||||
|
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-p, \-\-port " port[:port]
|
.BI "\-p, \-\-port " port[:port]
|
||||||
Set the TCP port (range) used by the client to listen.
|
Set the TCP port (range) used by the client to listen.
|
||||||
@ -106,6 +110,14 @@ option if set, or by the file extension (.mp4 or .mkv).
|
|||||||
.BI "\-\-record\-format " format
|
.BI "\-\-record\-format " format
|
||||||
Force recording format (either mp4 or mkv).
|
Force recording format (either mp4 or mkv).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "\-\-render\-driver " name
|
||||||
|
Request SDL to use the given render driver (this is just a hint).
|
||||||
|
|
||||||
|
Supported names are currently "direct3d", "opengl", "opengles2", "opengles", "metal" and "software".
|
||||||
|
.UR https://wiki.libsdl.org/SDL_HINT_RENDER_DRIVER
|
||||||
|
.UE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-\-render\-expired\-frames
|
.B \-\-render\-expired\-frames
|
||||||
By default, to minimize latency, scrcpy always renders the last available decoded frame, and drops any previous ones. This flag forces to render all frames, at a cost of a possible increased latency.
|
By default, to minimize latency, scrcpy always renders the last available decoded frame, and drops any previous ones. This flag forces to render all frames, at a cost of a possible increased latency.
|
||||||
|
@ -75,6 +75,11 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
" Do not display device (only when screen recording is\n"
|
" Do not display device (only when screen recording is\n"
|
||||||
" enabled).\n"
|
" enabled).\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" --no-mipmaps\n"
|
||||||
|
" If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then\n"
|
||||||
|
" mipmaps are automatically generated to improve downscaling\n"
|
||||||
|
" quality. This option disables the generation of mipmaps.\n"
|
||||||
|
"\n"
|
||||||
" -p, --port port[:port]\n"
|
" -p, --port port[:port]\n"
|
||||||
" Set the TCP port (range) used by the client to listen.\n"
|
" Set the TCP port (range) used by the client to listen.\n"
|
||||||
" Default is %d:%d.\n"
|
" Default is %d:%d.\n"
|
||||||
@ -99,6 +104,13 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
" --record-format format\n"
|
" --record-format format\n"
|
||||||
" Force recording format (either mp4 or mkv).\n"
|
" Force recording format (either mp4 or mkv).\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" --render-driver name\n"
|
||||||
|
" Request SDL to use the given render driver (this is just a\n"
|
||||||
|
" hint).\n"
|
||||||
|
" Supported names are currently \"direct3d\", \"opengl\",\n"
|
||||||
|
" \"opengles2\", \"opengles\", \"metal\" and \"software\".\n"
|
||||||
|
" <https://wiki.libsdl.org/SDL_HINT_RENDER_DRIVER>\n"
|
||||||
|
"\n"
|
||||||
" --render-expired-frames\n"
|
" --render-expired-frames\n"
|
||||||
" By default, to minimize latency, scrcpy always renders the\n"
|
" By default, to minimize latency, scrcpy always renders the\n"
|
||||||
" last available decoded frame, and drops any previous ones.\n"
|
" last available decoded frame, and drops any previous ones.\n"
|
||||||
@ -454,6 +466,8 @@ guess_record_format(const char *filename) {
|
|||||||
#define OPT_LOCK_VIDEO_ORIENTATION 1013
|
#define OPT_LOCK_VIDEO_ORIENTATION 1013
|
||||||
#define OPT_DISPLAY_ID 1014
|
#define OPT_DISPLAY_ID 1014
|
||||||
#define OPT_ROTATION 1015
|
#define OPT_ROTATION 1015
|
||||||
|
#define OPT_RENDER_DRIVER 1016
|
||||||
|
#define OPT_NO_MIPMAPS 1017
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
@ -470,10 +484,12 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
{"max-size", required_argument, NULL, 'm'},
|
{"max-size", required_argument, NULL, 'm'},
|
||||||
{"no-control", no_argument, NULL, 'n'},
|
{"no-control", no_argument, NULL, 'n'},
|
||||||
{"no-display", no_argument, NULL, 'N'},
|
{"no-display", no_argument, NULL, 'N'},
|
||||||
|
{"no-mipmaps", no_argument, NULL, OPT_NO_MIPMAPS},
|
||||||
{"port", required_argument, NULL, 'p'},
|
{"port", required_argument, NULL, 'p'},
|
||||||
{"push-target", required_argument, NULL, OPT_PUSH_TARGET},
|
{"push-target", required_argument, NULL, OPT_PUSH_TARGET},
|
||||||
{"record", required_argument, NULL, 'r'},
|
{"record", required_argument, NULL, 'r'},
|
||||||
{"record-format", required_argument, NULL, OPT_RECORD_FORMAT},
|
{"record-format", required_argument, NULL, OPT_RECORD_FORMAT},
|
||||||
|
{"render-driver", required_argument, NULL, OPT_RENDER_DRIVER},
|
||||||
{"render-expired-frames", no_argument, NULL,
|
{"render-expired-frames", no_argument, NULL,
|
||||||
OPT_RENDER_EXPIRED_FRAMES},
|
OPT_RENDER_EXPIRED_FRAMES},
|
||||||
{"rotation", required_argument, NULL, OPT_ROTATION},
|
{"rotation", required_argument, NULL, OPT_ROTATION},
|
||||||
@ -617,6 +633,12 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OPT_RENDER_DRIVER:
|
||||||
|
opts->render_driver = optarg;
|
||||||
|
break;
|
||||||
|
case OPT_NO_MIPMAPS:
|
||||||
|
opts->mipmaps = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// getopt prints the error message on stderr
|
// getopt prints the error message on stderr
|
||||||
return false;
|
return false;
|
||||||
|
56
app/src/opengl.c
Normal file
56
app/src/opengl.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "opengl.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "SDL2/SDL.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_opengl_init(struct sc_opengl *gl) {
|
||||||
|
gl->GetString = SDL_GL_GetProcAddress("glGetString");
|
||||||
|
assert(gl->GetString);
|
||||||
|
|
||||||
|
gl->TexParameterf = SDL_GL_GetProcAddress("glTexParameterf");
|
||||||
|
assert(gl->TexParameterf);
|
||||||
|
|
||||||
|
gl->TexParameteri = SDL_GL_GetProcAddress("glTexParameteri");
|
||||||
|
assert(gl->TexParameteri);
|
||||||
|
|
||||||
|
// optional
|
||||||
|
gl->GenerateMipmap = SDL_GL_GetProcAddress("glGenerateMipmap");
|
||||||
|
|
||||||
|
const char *version = (const char *) gl->GetString(GL_VERSION);
|
||||||
|
assert(version);
|
||||||
|
gl->version = version;
|
||||||
|
|
||||||
|
#define OPENGL_ES_PREFIX "OpenGL ES "
|
||||||
|
/* starts with "OpenGL ES " */
|
||||||
|
gl->is_opengles = !strncmp(gl->version, OPENGL_ES_PREFIX,
|
||||||
|
sizeof(OPENGL_ES_PREFIX) - 1);
|
||||||
|
if (gl->is_opengles) {
|
||||||
|
/* skip the prefix */
|
||||||
|
version += sizeof(PREFIX) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);
|
||||||
|
if (r != 2) {
|
||||||
|
// failed to parse the version
|
||||||
|
gl->version_major = 0;
|
||||||
|
gl->version_minor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_opengl_version_at_least(struct sc_opengl *gl,
|
||||||
|
int minver_major, int minver_minor,
|
||||||
|
int minver_es_major, int minver_es_minor)
|
||||||
|
{
|
||||||
|
if (gl->is_opengles) {
|
||||||
|
return gl->version_major > minver_es_major
|
||||||
|
|| (gl->version_major == minver_es_major
|
||||||
|
&& gl->version_minor >= minver_es_minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gl->version_major > minver_major
|
||||||
|
|| (gl->version_major == minver_major
|
||||||
|
&& gl->version_minor >= minver_minor);
|
||||||
|
}
|
36
app/src/opengl.h
Normal file
36
app/src/opengl.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef SC_OPENGL_H
|
||||||
|
#define SC_OPENGL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <SDL2/SDL_opengl.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
struct sc_opengl {
|
||||||
|
const char *version;
|
||||||
|
bool is_opengles;
|
||||||
|
int version_major;
|
||||||
|
int version_minor;
|
||||||
|
|
||||||
|
const GLubyte *
|
||||||
|
(*GetString)(GLenum name);
|
||||||
|
|
||||||
|
void
|
||||||
|
(*TexParameterf)(GLenum target, GLenum pname, GLfloat param);
|
||||||
|
|
||||||
|
void
|
||||||
|
(*TexParameteri)(GLenum target, GLenum pname, GLint param);
|
||||||
|
|
||||||
|
void
|
||||||
|
(*GenerateMipmap)(GLenum target);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_opengl_init(struct sc_opengl *gl);
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_opengl_version_at_least(struct sc_opengl *gl,
|
||||||
|
int minver_major, int minver_minor,
|
||||||
|
int minver_es_major, int minver_es_minor);
|
||||||
|
|
||||||
|
#endif
|
@ -47,7 +47,7 @@ static struct input_manager input_manager = {
|
|||||||
|
|
||||||
// init SDL and set appropriate hints
|
// init SDL and set appropriate hints
|
||||||
static bool
|
static bool
|
||||||
sdl_init_and_configure(bool display) {
|
sdl_init_and_configure(bool display, const char *render_driver) {
|
||||||
uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS;
|
uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS;
|
||||||
if (SDL_Init(flags)) {
|
if (SDL_Init(flags)) {
|
||||||
LOGC("Could not initialize SDL: %s", SDL_GetError());
|
LOGC("Could not initialize SDL: %s", SDL_GetError());
|
||||||
@ -60,6 +60,10 @@ sdl_init_and_configure(bool display) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (render_driver && !SDL_SetHint(SDL_HINT_RENDER_DRIVER, render_driver)) {
|
||||||
|
LOGW("Could not set render driver");
|
||||||
|
}
|
||||||
|
|
||||||
// Linear filtering
|
// Linear filtering
|
||||||
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
|
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
|
||||||
LOGW("Could not enable linear filtering");
|
LOGW("Could not enable linear filtering");
|
||||||
@ -310,7 +314,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
bool controller_initialized = false;
|
bool controller_initialized = false;
|
||||||
bool controller_started = false;
|
bool controller_started = false;
|
||||||
|
|
||||||
if (!sdl_init_and_configure(options->display)) {
|
if (!sdl_init_and_configure(options->display, options->render_driver)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +401,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
options->window_y, options->window_width,
|
options->window_y, options->window_width,
|
||||||
options->window_height,
|
options->window_height,
|
||||||
options->window_borderless,
|
options->window_borderless,
|
||||||
options->rotation)) {
|
options->rotation, options-> mipmaps)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ struct scrcpy_options {
|
|||||||
const char *record_filename;
|
const char *record_filename;
|
||||||
const char *window_title;
|
const char *window_title;
|
||||||
const char *push_target;
|
const char *push_target;
|
||||||
|
const char *render_driver;
|
||||||
enum recorder_format record_format;
|
enum recorder_format record_format;
|
||||||
struct port_range port_range;
|
struct port_range port_range;
|
||||||
uint16_t max_size;
|
uint16_t max_size;
|
||||||
@ -36,6 +37,7 @@ struct scrcpy_options {
|
|||||||
bool render_expired_frames;
|
bool render_expired_frames;
|
||||||
bool prefer_text;
|
bool prefer_text;
|
||||||
bool window_borderless;
|
bool window_borderless;
|
||||||
|
bool mipmaps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRCPY_OPTIONS_DEFAULT { \
|
#define SCRCPY_OPTIONS_DEFAULT { \
|
||||||
@ -44,6 +46,7 @@ struct scrcpy_options {
|
|||||||
.record_filename = NULL, \
|
.record_filename = NULL, \
|
||||||
.window_title = NULL, \
|
.window_title = NULL, \
|
||||||
.push_target = NULL, \
|
.push_target = NULL, \
|
||||||
|
.render_driver = NULL, \
|
||||||
.record_format = RECORDER_FORMAT_AUTO, \
|
.record_format = RECORDER_FORMAT_AUTO, \
|
||||||
.port_range = { \
|
.port_range = { \
|
||||||
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST, \
|
.first = DEFAULT_LOCAL_PORT_RANGE_FIRST, \
|
||||||
@ -68,6 +71,7 @@ struct scrcpy_options {
|
|||||||
.render_expired_frames = false, \
|
.render_expired_frames = false, \
|
||||||
.prefer_text = false, \
|
.prefer_text = false, \
|
||||||
.window_borderless = false, \
|
.window_borderless = false, \
|
||||||
|
.mipmaps = true, \
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -168,10 +168,30 @@ screen_init(struct screen *screen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline SDL_Texture *
|
static inline SDL_Texture *
|
||||||
create_texture(SDL_Renderer *renderer, struct size frame_size) {
|
create_texture(struct screen *screen) {
|
||||||
return SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
SDL_Renderer *renderer = screen->renderer;
|
||||||
|
struct size size = screen->frame_size;
|
||||||
|
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
||||||
SDL_TEXTUREACCESS_STREAMING,
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
frame_size.width, frame_size.height);
|
size.width, size.height);
|
||||||
|
if (!texture) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen->mipmaps) {
|
||||||
|
struct sc_opengl *gl = &screen->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, -.5f);
|
||||||
|
|
||||||
|
SDL_GL_UnbindTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -179,7 +199,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
struct size frame_size, bool always_on_top,
|
struct size frame_size, bool always_on_top,
|
||||||
int16_t window_x, int16_t window_y, uint16_t window_width,
|
int16_t window_x, int16_t window_y, uint16_t window_width,
|
||||||
uint16_t window_height, bool window_borderless,
|
uint16_t window_height, bool window_borderless,
|
||||||
uint8_t rotation) {
|
uint8_t rotation, bool mipmaps) {
|
||||||
screen->frame_size = frame_size;
|
screen->frame_size = frame_size;
|
||||||
screen->rotation = rotation;
|
screen->rotation = rotation;
|
||||||
if (rotation) {
|
if (rotation) {
|
||||||
@ -226,6 +246,11 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_RendererInfo renderer_info;
|
||||||
|
int r = SDL_GetRendererInfo(screen->renderer, &renderer_info);
|
||||||
|
const char *renderer_name = r ? NULL : renderer_info.name;
|
||||||
|
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
||||||
|
|
||||||
if (SDL_RenderSetLogicalSize(screen->renderer, content_size.width,
|
if (SDL_RenderSetLogicalSize(screen->renderer, content_size.width,
|
||||||
content_size.height)) {
|
content_size.height)) {
|
||||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
||||||
@ -233,6 +258,32 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stats with "opengl"
|
||||||
|
screen->use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
||||||
|
if (screen->use_opengl) {
|
||||||
|
struct sc_opengl *gl = &screen->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");
|
||||||
|
screen->mipmaps = true;
|
||||||
|
} else {
|
||||||
|
LOGW("Trilinear filtering disabled "
|
||||||
|
"(OpenGL 3.0+ or ES 2.0+ required)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGI("Trilinear filtering disabled");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGW("Trilinear filtering disabled (not an OpenGL renderer)");
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Surface *icon = read_xpm(icon_xpm);
|
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
SDL_SetWindowIcon(screen->window, icon);
|
SDL_SetWindowIcon(screen->window, icon);
|
||||||
@ -243,7 +294,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
|
|
||||||
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
||||||
frame_size.height);
|
frame_size.height);
|
||||||
screen->texture = create_texture(screen->renderer, frame_size);
|
screen->texture = create_texture(screen);
|
||||||
if (!screen->texture) {
|
if (!screen->texture) {
|
||||||
LOGC("Could not create texture: %s", SDL_GetError());
|
LOGC("Could not create texture: %s", SDL_GetError());
|
||||||
screen_destroy(screen);
|
screen_destroy(screen);
|
||||||
@ -341,7 +392,7 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
|||||||
|
|
||||||
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
||||||
screen->frame_size.width, screen->frame_size.height);
|
screen->frame_size.width, screen->frame_size.height);
|
||||||
screen->texture = create_texture(screen->renderer, new_frame_size);
|
screen->texture = create_texture(screen);
|
||||||
if (!screen->texture) {
|
if (!screen->texture) {
|
||||||
LOGC("Could not create texture: %s", SDL_GetError());
|
LOGC("Could not create texture: %s", SDL_GetError());
|
||||||
return false;
|
return false;
|
||||||
@ -358,6 +409,13 @@ update_texture(struct screen *screen, const AVFrame *frame) {
|
|||||||
frame->data[0], frame->linesize[0],
|
frame->data[0], frame->linesize[0],
|
||||||
frame->data[1], frame->linesize[1],
|
frame->data[1], frame->linesize[1],
|
||||||
frame->data[2], frame->linesize[2]);
|
frame->data[2], frame->linesize[2]);
|
||||||
|
|
||||||
|
if (screen->mipmaps) {
|
||||||
|
assert(screen->use_opengl);
|
||||||
|
SDL_GL_BindTexture(screen->texture, NULL, NULL);
|
||||||
|
screen->gl.GenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
SDL_GL_UnbindTexture(screen->texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "opengl.h"
|
||||||
|
|
||||||
#define WINDOW_POSITION_UNDEFINED (-0x8000)
|
#define WINDOW_POSITION_UNDEFINED (-0x8000)
|
||||||
|
|
||||||
@ -16,6 +17,8 @@ struct screen {
|
|||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
|
bool use_opengl;
|
||||||
|
struct sc_opengl gl;
|
||||||
struct size frame_size;
|
struct size frame_size;
|
||||||
struct size content_size; // rotated frame_size
|
struct size content_size; // rotated frame_size
|
||||||
// The window size the last time it was not maximized or fullscreen.
|
// The window size the last time it was not maximized or fullscreen.
|
||||||
@ -29,12 +32,15 @@ struct screen {
|
|||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
bool no_window;
|
bool no_window;
|
||||||
|
bool mipmaps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCREEN_INITIALIZER { \
|
#define SCREEN_INITIALIZER { \
|
||||||
.window = NULL, \
|
.window = NULL, \
|
||||||
.renderer = NULL, \
|
.renderer = NULL, \
|
||||||
.texture = NULL, \
|
.texture = NULL, \
|
||||||
|
.use_opengl = false, \
|
||||||
|
.gl = {0}, \
|
||||||
.frame_size = { \
|
.frame_size = { \
|
||||||
.width = 0, \
|
.width = 0, \
|
||||||
.height = 0, \
|
.height = 0, \
|
||||||
@ -56,6 +62,7 @@ struct screen {
|
|||||||
.fullscreen = false, \
|
.fullscreen = false, \
|
||||||
.maximized = false, \
|
.maximized = false, \
|
||||||
.no_window = false, \
|
.no_window = false, \
|
||||||
|
.mipmaps = false, \
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize default values
|
// initialize default values
|
||||||
@ -69,7 +76,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
struct size frame_size, bool always_on_top,
|
struct size frame_size, bool always_on_top,
|
||||||
int16_t window_x, int16_t window_y, uint16_t window_width,
|
int16_t window_x, int16_t window_y, uint16_t window_width,
|
||||||
uint16_t window_height, bool window_borderless,
|
uint16_t window_height, bool window_borderless,
|
||||||
uint8_t rotation);
|
uint8_t rotation, bool mipmaps);
|
||||||
|
|
||||||
// show the window
|
// show the window
|
||||||
void
|
void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user