Compare commits

..

4 Commits

Author SHA1 Message Date
Romain Vimont
91c5e7e626 Mention mipmapping in FAQ 2020-04-13 16:33:28 +02:00
Romain Vimont
7c851cdb2d Add option --no-mipmaps
Add an option to disable trilinear filtering even if mipmapping is
available.
2020-04-13 16:33:28 +02:00
Romain Vimont
08a175b7f1 Enable trilinear filtering for OpenGL
Improve downscaling quality if mipmapping is available.

Suggested-by: Giumo Clanjor (哆啦比猫/兰威举) <cjxgm2@gmail.com>

Fixes #40 <https://github.com/Genymobile/scrcpy/issues/40>
Ref: <https://github.com/Genymobile/scrcpy/issues/40#issuecomment-591917787>
2020-04-13 16:33:28 +02:00
Romain Vimont
9f029da2f9 Add --render-driver command-line option
Add an option to set a render driver hint (SDL_HINT_RENDER_DRIVER).
2020-04-13 16:33:28 +02:00
11 changed files with 27 additions and 24 deletions

4
FAQ.md
View File

@@ -142,13 +142,13 @@ screen, then you might get poor quality, especially visible on text (see [#40]).
To improve downscaling quality, trilinear filtering is enabled automatically To improve downscaling quality, trilinear filtering is enabled automatically
if the renderer is OpenGL and if it supports mipmapping. if the renderer is OpenGL and if it supports mipmapping.
On Windows, you might want to force OpenGL: On Windows or macOS, you might need to force OpenGL:
``` ```
scrcpy --render-driver=opengl scrcpy --render-driver=opengl
``` ```
You may also need to configure the [scaling behavior]: 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_.

View File

@@ -363,7 +363,7 @@ Note that _scrcpy_ manages 3 different rotations:
current running app may refuse, if it does support the requested current running app may refuse, if it does support the requested
orientation). orientation).
- `--lock-video-orientation` changes the mirroring orientation (the orientation - `--lock-video-orientation` changes the mirroring orientation (the orientation
of the video sent from the device to the computer). This affects the of the video sent from the device to the computer. This affects the
recording. recording.
- `--rotation` (or `Ctrl`+`←`/`Ctrl`+`→`) rotates only the window content. This - `--rotation` (or `Ctrl`+`←`/`Ctrl`+`→`) rotates only the window content. This
affects only the display, not the recording. affects only the display, not the recording.

View File

@@ -45,9 +45,8 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
buffer_write32be(&buf[6], msg->inject_keycode.metastate); buffer_write32be(&buf[6], msg->inject_keycode.metastate);
return 10; return 10;
case CONTROL_MSG_TYPE_INJECT_TEXT: { case CONTROL_MSG_TYPE_INJECT_TEXT: {
size_t len = size_t len = write_string(msg->inject_text.text,
write_string(msg->inject_text.text, CONTROL_MSG_TEXT_MAX_LENGTH, &buf[1]);
CONTROL_MSG_INJECT_TEXT_MAX_LENGTH, &buf[1]);
return 1 + len; return 1 + len;
} }
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:

View File

@@ -10,7 +10,7 @@
#include "android/keycodes.h" #include "android/keycodes.h"
#include "common.h" #include "common.h"
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300 #define CONTROL_MSG_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4093 #define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4093
#define CONTROL_MSG_SERIALIZED_MAX_SIZE \ #define CONTROL_MSG_SERIALIZED_MAX_SIZE \
(3 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH) (3 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH)

View File

@@ -49,20 +49,20 @@ static void test_serialize_inject_text(void) {
static void test_serialize_inject_text_long(void) { static void test_serialize_inject_text_long(void) {
struct control_msg msg; struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT; msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1]; char text[CONTROL_MSG_TEXT_MAX_LENGTH + 1];
memset(text, 'a', sizeof(text)); memset(text, 'a', sizeof(text));
text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0'; text[CONTROL_MSG_TEXT_MAX_LENGTH] = '\0';
msg.inject_text.text = text; msg.inject_text.text = text;
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE]; unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
int size = control_msg_serialize(&msg, buf); int size = control_msg_serialize(&msg, buf);
assert(size == 3 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH); assert(size == 3 + CONTROL_MSG_TEXT_MAX_LENGTH);
unsigned char expected[3 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH]; unsigned char expected[3 + CONTROL_MSG_TEXT_MAX_LENGTH];
expected[0] = CONTROL_MSG_TYPE_INJECT_TEXT; expected[0] = CONTROL_MSG_TYPE_INJECT_TEXT;
expected[1] = 0x01; expected[1] = 0x01;
expected[2] = 0x2c; // text length (16 bits) expected[2] = 0x2c; // text length (16 bits)
memset(&expected[3], 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH); memset(&expected[3], 'a', CONTROL_MSG_TEXT_MAX_LENGTH);
assert(!memcmp(buf, expected, sizeof(expected))); assert(!memcmp(buf, expected, sizeof(expected)));
} }

View File

@@ -1,6 +1,6 @@
project('scrcpy', 'c', project('scrcpy', 'c',
version: '1.12.1', version: '1.12.1',
meson_version: '>= 0.48', meson_version: '>= 0.37',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',
'warning_level=2', 'warning_level=2',

View File

@@ -3,9 +3,7 @@
prebuilt_server = get_option('prebuilt_server') prebuilt_server = get_option('prebuilt_server')
if prebuilt_server == '' if prebuilt_server == ''
custom_target('scrcpy-server', custom_target('scrcpy-server',
# gradle is responsible for tracking source changes build_always: true, # gradle is responsible for tracking source changes
build_by_default: true,
build_always_stale: true,
output: 'scrcpy-server', output: 'scrcpy-server',
command: [find_program('./scripts/build-wrapper.sh'), meson.current_source_dir(), '@OUTPUT@', get_option('buildtype')], command: [find_program('./scripts/build-wrapper.sh'), meson.current_source_dir(), '@OUTPUT@', get_option('buildtype')],
console: true, console: true,

View File

@@ -13,8 +13,8 @@ public class ControlMessageReader {
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20; static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1; static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
public static final int TEXT_MAX_LENGTH = 300;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093; public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
public static final int INJECT_TEXT_MAX_LENGTH = 300;
private static final int RAW_BUFFER_SIZE = 1024; private static final int RAW_BUFFER_SIZE = 1024;
private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE]; private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE];

View File

@@ -36,7 +36,10 @@ public final class Device {
*/ */
private final int layerStack; private final int layerStack;
private final boolean supportsInputEvents; /**
* The FLAG_PRESENTATION from the DisplayInfo
*/
private final boolean isPresentationDisplay;
public Device(Options options) { public Device(Options options) {
displayId = options.getDisplayId(); displayId = options.getDisplayId();
@@ -50,6 +53,7 @@ public final class Device {
screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation()); screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation());
layerStack = displayInfo.getLayerStack(); layerStack = displayInfo.getLayerStack();
isPresentationDisplay = (displayInfoFlags & DisplayInfo.FLAG_PRESENTATION) != 0;
registerRotationWatcher(new IRotationWatcher.Stub() { registerRotationWatcher(new IRotationWatcher.Stub() {
@Override @Override
@@ -69,10 +73,8 @@ public final class Device {
Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted"); Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted");
} }
// main display or any display on Android >= Q if (!supportsInputEvents()) {
supportsInputEvents = displayId == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; Ln.w("Input events are not supported for displays with FLAG_PRESENTATION enabled for devices with API lower than 29");
if (!supportsInputEvents) {
Ln.w("Input events are not supported for secondary displays before Android 10");
} }
} }
@@ -114,7 +116,10 @@ public final class Device {
} }
public boolean supportsInputEvents() { public boolean supportsInputEvents() {
return supportsInputEvents; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return true;
}
return !isPresentationDisplay;
} }
public boolean injectInputEvent(InputEvent inputEvent, int mode) { public boolean injectInputEvent(InputEvent inputEvent, int mode) {

View File

@@ -8,6 +8,7 @@ public final class DisplayInfo {
private final int flags; private final int flags;
public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001; public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001;
public static final int FLAG_PRESENTATION = 0x00000008;
public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) { public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) {
this.displayId = displayId; this.displayId = displayId;

View File

@@ -66,7 +66,7 @@ public class ControlMessageReaderTest {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT); dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
byte[] text = new byte[ControlMessageReader.INJECT_TEXT_MAX_LENGTH]; byte[] text = new byte[ControlMessageReader.TEXT_MAX_LENGTH];
Arrays.fill(text, (byte) 'a'); Arrays.fill(text, (byte) 'a');
dos.writeShort(text.length); dos.writeShort(text.length);
dos.write(text); dos.write(text);