add scale_filter output config option

master
Ronan Pigott 5 years ago committed by Simon Ser
parent 4b57953628
commit 6968fb3123

@ -276,6 +276,7 @@ sway_cmd output_cmd_max_render_time;
sway_cmd output_cmd_mode; sway_cmd output_cmd_mode;
sway_cmd output_cmd_position; sway_cmd output_cmd_position;
sway_cmd output_cmd_scale; sway_cmd output_cmd_scale;
sway_cmd output_cmd_scale_filter;
sway_cmd output_cmd_subpixel; sway_cmd output_cmd_subpixel;
sway_cmd output_cmd_toggle; sway_cmd output_cmd_toggle;
sway_cmd output_cmd_transform; sway_cmd output_cmd_transform;

@ -204,6 +204,13 @@ enum config_dpms {
DPMS_OFF DPMS_OFF
}; };
enum scale_filter_mode {
SCALE_FILTER_DEFAULT, // the default is currently smart
SCALE_FILTER_LINEAR,
SCALE_FILTER_NEAREST,
SCALE_FILTER_SMART
};
/** /**
* Size and position configuration for a particular output. * Size and position configuration for a particular output.
* *
@ -217,6 +224,7 @@ struct output_config {
int custom_mode; int custom_mode;
int x, y; int x, y;
float scale; float scale;
enum scale_filter_mode scale_filter;
int32_t transform; int32_t transform;
enum wl_output_subpixel subpixel; enum wl_output_subpixel subpixel;
int max_render_time; // In milliseconds int max_render_time; // In milliseconds
@ -655,6 +663,8 @@ int output_name_cmp(const void *item, const void *data);
void output_get_identifier(char *identifier, size_t len, void output_get_identifier(char *identifier, size_t len,
struct sway_output *output); struct sway_output *output);
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter);
struct output_config *new_output_config(const char *name); struct output_config *new_output_config(const char *name);
void merge_output_config(struct output_config *dst, struct output_config *src); void merge_output_config(struct output_config *dst, struct output_config *src);

@ -32,6 +32,7 @@ struct sway_output {
int lx, ly; // layout coords int lx, ly; // layout coords
int width, height; // transformed buffer size int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel; enum wl_output_subpixel detected_subpixel;
enum scale_filter_mode scale_filter;
// last applied mode when the output is DPMS'ed // last applied mode when the output is DPMS'ed
struct wlr_output_mode *current_mode; struct wlr_output_mode *current_mode;

@ -48,6 +48,7 @@ pango = dependency('pango')
pangocairo = dependency('pangocairo') pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
pixman = dependency('pixman-1') pixman = dependency('pixman-1')
glesv2 = dependency('glesv2')
libevdev = dependency('libevdev') libevdev = dependency('libevdev')
libinput = dependency('libinput', version: '>=1.6.0') libinput = dependency('libinput', version: '>=1.6.0')
systemd = dependency('libsystemd', version: '>=239', required: false) systemd = dependency('libsystemd', version: '>=239', required: false)

@ -19,6 +19,7 @@ static struct cmd_handler output_handlers[] = {
{ "res", output_cmd_mode }, { "res", output_cmd_mode },
{ "resolution", output_cmd_mode }, { "resolution", output_cmd_mode },
{ "scale", output_cmd_scale }, { "scale", output_cmd_scale },
{ "scale_filter", output_cmd_scale_filter },
{ "subpixel", output_cmd_subpixel }, { "subpixel", output_cmd_subpixel },
{ "toggle", output_cmd_toggle }, { "toggle", output_cmd_toggle },
{ "transform", output_cmd_transform }, { "transform", output_cmd_transform },

@ -0,0 +1,34 @@
#include <string.h>
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *output_cmd_scale_filter(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing scale_filter argument.");
}
enum scale_filter_mode scale_filter;
if (strcmp(*argv, "linear") == 0) {
scale_filter = SCALE_FILTER_LINEAR;
} else if (strcmp(*argv, "nearest") == 0) {
scale_filter = SCALE_FILTER_NEAREST;
} else if (strcmp(*argv, "smart") == 0) {
scale_filter = SCALE_FILTER_SMART;
} else {
return cmd_results_new(CMD_INVALID, "Invalid output scale_filter.");
}
struct output_config *oc = config->handler_context.output_config;
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
oc->scale_filter = scale_filter;
return NULL;
}

@ -29,6 +29,21 @@ void output_get_identifier(char *identifier, size_t len,
wlr_output->serial); wlr_output->serial);
} }
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
switch (scale_filter) {
case SCALE_FILTER_DEFAULT:
return "smart";
case SCALE_FILTER_LINEAR:
return "linear";
case SCALE_FILTER_NEAREST:
return "nearest";
case SCALE_FILTER_SMART:
return "smart";
}
sway_assert(false, "Unknown value for scale_filter.");
return NULL;
}
struct output_config *new_output_config(const char *name) { struct output_config *new_output_config(const char *name) {
struct output_config *oc = calloc(1, sizeof(struct output_config)); struct output_config *oc = calloc(1, sizeof(struct output_config));
if (oc == NULL) { if (oc == NULL) {
@ -45,6 +60,7 @@ struct output_config *new_output_config(const char *name) {
oc->custom_mode = -1; oc->custom_mode = -1;
oc->x = oc->y = -1; oc->x = oc->y = -1;
oc->scale = -1; oc->scale = -1;
oc->scale_filter = SCALE_FILTER_DEFAULT;
oc->transform = -1; oc->transform = -1;
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
oc->max_render_time = -1; oc->max_render_time = -1;
@ -70,6 +86,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->scale != -1) { if (src->scale != -1) {
dst->scale = src->scale; dst->scale = src->scale;
} }
if (src->scale_filter != SCALE_FILTER_DEFAULT) {
dst->scale_filter = src->scale_filter;
}
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
dst->subpixel = src->subpixel; dst->subpixel = src->subpixel;
} }
@ -297,6 +316,24 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
if (oc && oc->scale > 0) { if (oc && oc->scale > 0) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale); sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_output_set_scale(wlr_output, oc->scale); wlr_output_set_scale(wlr_output, oc->scale);
enum scale_filter_mode scale_filter_old = output->scale_filter;
switch (oc->scale_filter) {
case SCALE_FILTER_DEFAULT:
case SCALE_FILTER_SMART:
output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ?
SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR;
break;
case SCALE_FILTER_LINEAR:
case SCALE_FILTER_NEAREST:
output->scale_filter = oc->scale_filter;
break;
}
if (scale_filter_old != output->scale_filter) {
sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
sway_output_scale_filter_to_string(output->scale_filter));
output_damage_whole(output);
}
} }
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
@ -352,6 +389,7 @@ static void default_output_config(struct output_config *oc,
} }
oc->x = oc->y = -1; oc->x = oc->y = -1;
oc->scale = 1; oc->scale = 1;
oc->scale_filter = SCALE_FILTER_DEFAULT;
struct sway_output *output = wlr_output->data; struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel; oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;

@ -1,9 +1,11 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <GLES2/gl2.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <time.h> #include <time.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.h> #include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
@ -70,6 +72,28 @@ static void scissor_output(struct wlr_output *wlr_output,
wlr_renderer_scissor(renderer, &box); wlr_renderer_scissor(renderer, &box);
} }
static void set_scale_filter(struct wlr_output *wlr_output,
struct wlr_texture *texture, enum scale_filter_mode scale_filter) {
if (!wlr_texture_is_gles2(texture)) {
return;
}
struct wlr_gles2_texture_attribs attribs;
wlr_gles2_texture_get_attribs(texture, &attribs);
switch (scale_filter) {
case SCALE_FILTER_LINEAR:
glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case SCALE_FILTER_NEAREST:
glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case SCALE_FILTER_DEFAULT:
case SCALE_FILTER_SMART:
assert(false); // unreachable
}
}
static void render_texture(struct wlr_output *wlr_output, static void render_texture(struct wlr_output *wlr_output,
pixman_region32_t *output_damage, struct wlr_texture *texture, pixman_region32_t *output_damage, struct wlr_texture *texture,
const struct wlr_box *box, const float matrix[static 9], float alpha) { const struct wlr_box *box, const float matrix[static 9], float alpha) {
@ -119,6 +143,7 @@ static void render_surface_iterator(struct sway_output *output, struct sway_view
wlr_matrix_project_box(matrix, &box, transform, rotation, wlr_matrix_project_box(matrix, &box, transform, rotation,
wlr_output->transform_matrix); wlr_output->transform_matrix);
set_scale_filter(wlr_output, texture, output->scale_filter);
render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_presentation_surface_sampled_on_output(server.presentation, surface,
@ -268,6 +293,7 @@ static void render_saved_view(struct sway_view *view,
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix); wlr_output->transform_matrix);
set_scale_filter(wlr_output, view->saved_buffer->texture, output->scale_filter);
render_texture(wlr_output, damage, view->saved_buffer->texture, render_texture(wlr_output, damage, view->saved_buffer->texture,
&box, matrix, alpha); &box, matrix, alpha);

@ -177,6 +177,9 @@ static void ipc_json_describe_output(struct sway_output *output,
json_object_new_string(wlr_output->serial)); json_object_new_string(wlr_output->serial));
json_object_object_add(object, "scale", json_object_object_add(object, "scale",
json_object_new_double(wlr_output->scale)); json_object_new_double(wlr_output->scale));
json_object_object_add(object, "scale_filter",
json_object_new_string(
sway_output_scale_filter_to_string(output->scale_filter)));
json_object_object_add(object, "transform", json_object_object_add(object, "transform",
json_object_new_string( json_object_new_string(
ipc_json_output_transform_description(wlr_output->transform))); ipc_json_output_transform_description(wlr_output->transform)));

@ -182,6 +182,7 @@ sway_sources = files(
'commands/output/mode.c', 'commands/output/mode.c',
'commands/output/position.c', 'commands/output/position.c',
'commands/output/scale.c', 'commands/output/scale.c',
'commands/output/scale_filter.c',
'commands/output/subpixel.c', 'commands/output/subpixel.c',
'commands/output/toggle.c', 'commands/output/toggle.c',
'commands/output/transform.c', 'commands/output/transform.c',
@ -203,6 +204,7 @@ sway_deps = [
math, math,
pango, pango,
pcre, pcre,
glesv2,
pixman, pixman,
server_protos, server_protos,
wayland_server, wayland_server,

@ -70,6 +70,14 @@ must be separated by one space. For example:
applications to taste. HiDPI isn't supported with Xwayland clients (windows applications to taste. HiDPI isn't supported with Xwayland clients (windows
will blur). will blur).
*output* <name> scale_filter linear|nearest|smart
Indicates how to scale application buffers that are rendered at a scale
lower than the output's configured scale, such as lo-dpi applications on
hi-dpi screens. Linear is smoother and blurrier, nearest (also known as
nearest neighbor) is sharper and blockier. Setting "smart" will apply
nearest scaling when the output has an integer scale factor, otherwise
linear. The default is "smart".
*output* <name> subpixel rgb|bgr|vrgb|vbgr|none *output* <name> subpixel rgb|bgr|vrgb|vbgr|none
Manually sets the subpixel hinting for the specified output. This value is Manually sets the subpixel hinting for the specified output. This value is
usually auto-detected, but some displays may misreport their subpixel usually auto-detected, but some displays may misreport their subpixel

@ -93,6 +93,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
output->wlr_output = wlr_output; output->wlr_output = wlr_output;
wlr_output->data = output; wlr_output->data = output;
output->detected_subpixel = wlr_output->subpixel; output->detected_subpixel = wlr_output->subpixel;
output->scale_filter = SCALE_FILTER_NEAREST;
wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.destroy);

@ -189,11 +189,13 @@ static void pretty_print_output(json_object *o) {
json_object_object_get_ex(o, "focused", &focused); json_object_object_get_ex(o, "focused", &focused);
json_object_object_get_ex(o, "active", &active); json_object_object_get_ex(o, "active", &active);
json_object_object_get_ex(o, "current_workspace", &ws); json_object_object_get_ex(o, "current_workspace", &ws);
json_object *make, *model, *serial, *scale, *subpixel, *transform, *max_render_time; json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
*transform, *max_render_time;
json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "make", &make);
json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "model", &model);
json_object_object_get_ex(o, "serial", &serial); json_object_object_get_ex(o, "serial", &serial);
json_object_object_get_ex(o, "scale", &scale); json_object_object_get_ex(o, "scale", &scale);
json_object_object_get_ex(o, "scale_filter", &scale_filter);
json_object_object_get_ex(o, "subpixel_hinting", &subpixel); json_object_object_get_ex(o, "subpixel_hinting", &subpixel);
json_object_object_get_ex(o, "transform", &transform); json_object_object_get_ex(o, "transform", &transform);
json_object_object_get_ex(o, "max_render_time", &max_render_time); json_object_object_get_ex(o, "max_render_time", &max_render_time);
@ -214,6 +216,7 @@ static void pretty_print_output(json_object *o) {
" Current mode: %dx%d @ %f Hz\n" " Current mode: %dx%d @ %f Hz\n"
" Position: %d,%d\n" " Position: %d,%d\n"
" Scale factor: %f\n" " Scale factor: %f\n"
" Scale filter: %s\n"
" Subpixel hinting: %s\n" " Subpixel hinting: %s\n"
" Transform: %s\n" " Transform: %s\n"
" Workspace: %s\n" " Workspace: %s\n"
@ -228,6 +231,7 @@ static void pretty_print_output(json_object *o) {
(float)json_object_get_int(refresh) / 1000, (float)json_object_get_int(refresh) / 1000,
json_object_get_int(x), json_object_get_int(y), json_object_get_int(x), json_object_get_int(y),
json_object_get_double(scale), json_object_get_double(scale),
json_object_get_string(scale_filter),
json_object_get_string(subpixel), json_object_get_string(subpixel),
json_object_get_string(transform), json_object_get_string(transform),
json_object_get_string(ws) json_object_get_string(ws)

Loading…
Cancel
Save