aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
authorRonan Pigott <rpigott@berkeley.edu>2019-11-13 11:23:36 -0700
committerSimon Ser <contact@emersion.fr>2019-11-29 18:13:37 +0100
commit6968fb3123e69f563cd01d472967a9e6ddca2ec1 (patch)
tree0e313d5e19da37762ab572e38c36ff33798f25fb /sway
parent4b579536288108ec09bb8523dea6799228d3d7fa (diff)
add scale_filter output config option
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/output.c1
-rw-r--r--sway/commands/output/scale_filter.c34
-rw-r--r--sway/config/output.c38
-rw-r--r--sway/desktop/render.c26
-rw-r--r--sway/ipc-json.c3
-rw-r--r--sway/meson.build2
-rw-r--r--sway/sway-output.5.scd8
-rw-r--r--sway/tree/output.c1
8 files changed, 113 insertions, 0 deletions
diff --git a/sway/commands/output.c b/sway/commands/output.c
index db2acb50..2790bd63 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -19,6 +19,7 @@ static struct cmd_handler output_handlers[] = {
{ "res", output_cmd_mode },
{ "resolution", output_cmd_mode },
{ "scale", output_cmd_scale },
+ { "scale_filter", output_cmd_scale_filter },
{ "subpixel", output_cmd_subpixel },
{ "toggle", output_cmd_toggle },
{ "transform", output_cmd_transform },
diff --git a/sway/commands/output/scale_filter.c b/sway/commands/output/scale_filter.c
new file mode 100644
index 00000000..fa1e8e0d
--- /dev/null
+++ b/sway/commands/output/scale_filter.c
@@ -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;
+}
diff --git a/sway/config/output.c b/sway/config/output.c
index 1d5f81da..21a12b8f 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -29,6 +29,21 @@ void output_get_identifier(char *identifier, size_t len,
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 *oc = calloc(1, sizeof(struct output_config));
if (oc == NULL) {
@@ -45,6 +60,7 @@ struct output_config *new_output_config(const char *name) {
oc->custom_mode = -1;
oc->x = oc->y = -1;
oc->scale = -1;
+ oc->scale_filter = SCALE_FILTER_DEFAULT;
oc->transform = -1;
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
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) {
dst->scale = src->scale;
}
+ if (src->scale_filter != SCALE_FILTER_DEFAULT) {
+ dst->scale_filter = src->scale_filter;
+ }
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
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) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, 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)) {
@@ -352,6 +389,7 @@ static void default_output_config(struct output_config *oc,
}
oc->x = oc->y = -1;
oc->scale = 1;
+ oc->scale_filter = SCALE_FILTER_DEFAULT;
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 960fe083..2e66abd4 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -1,9 +1,11 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
+#include <GLES2/gl2.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <wayland-server-core.h>
+#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.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);
}
+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,
pixman_region32_t *output_damage, struct wlr_texture *texture,
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_output->transform_matrix);
+ set_scale_filter(wlr_output, texture, output->scale_filter);
render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
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_output->transform_matrix);
+ set_scale_filter(wlr_output, view->saved_buffer->texture, output->scale_filter);
render_texture(wlr_output, damage, view->saved_buffer->texture,
&box, matrix, alpha);
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index b880eb65..6cf8504a 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -177,6 +177,9 @@ static void ipc_json_describe_output(struct sway_output *output,
json_object_new_string(wlr_output->serial));
json_object_object_add(object, "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_new_string(
ipc_json_output_transform_description(wlr_output->transform)));
diff --git a/sway/meson.build b/sway/meson.build
index 5458d3dc..3e6e4da6 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -182,6 +182,7 @@ sway_sources = files(
'commands/output/mode.c',
'commands/output/position.c',
'commands/output/scale.c',
+ 'commands/output/scale_filter.c',
'commands/output/subpixel.c',
'commands/output/toggle.c',
'commands/output/transform.c',
@@ -203,6 +204,7 @@ sway_deps = [
math,
pango,
pcre,
+ glesv2,
pixman,
server_protos,
wayland_server,
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 3824480f..2dfb2ac1 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -70,6 +70,14 @@ must be separated by one space. For example:
applications to taste. HiDPI isn't supported with Xwayland clients (windows
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
Manually sets the subpixel hinting for the specified output. This value is
usually auto-detected, but some displays may misreport their subpixel
diff --git a/sway/tree/output.c b/sway/tree/output.c
index c4ec6eec..d2ede1f2 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -93,6 +93,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
output->wlr_output = wlr_output;
wlr_output->data = output;
output->detected_subpixel = wlr_output->subpixel;
+ output->scale_filter = SCALE_FILTER_NEAREST;
wl_signal_init(&output->events.destroy);