Screen fixes, improved update method

Fixed updates stopping, but not the cursor
NotifyUpdate handling is in a separate thread to avoid slowing the machine and it will only perform one update at a time that reflects the current state
This commit is contained in:
Norbi Peti 2020-08-03 22:49:25 +02:00
parent 32cea5c384
commit 586ab05033
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
3 changed files with 86 additions and 38 deletions

View file

@ -67,9 +67,16 @@ public class Commands implements CommandExecutor, TabCompleter {
case "restart": case "restart":
Computer.getInstance().Reset(sender); Computer.getInstance().Reset(sender);
break; break;
case "save":
case "savestate":
Computer.getInstance().SaveState(sender);
break;
case "fix": case "fix":
case "fixscreen": case "fixscreen":
Computer.getInstance().FixScreen(sender); Boolean seamless;
if (args.length < 2) seamless = null;
else seamless = args[1].equalsIgnoreCase("true");
Computer.getInstance().FixScreen(sender, seamless);
break; break;
case "key": case "key":
case "press": case "press":

View file

@ -100,6 +100,7 @@ public final class Computer {
handler.setProgress(progress); handler.setProgress(progress);
handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way? handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way?
val fb = new MCFrameBuffer(console.getDisplay()); val fb = new MCFrameBuffer(console.getDisplay());
fb.start();
String fbid = console.getDisplay().attachFramebuffer(0L, String fbid = console.getDisplay().attachFramebuffer(0L,
COMUtils.gimmeAFramebuffer(fb)); COMUtils.gimmeAFramebuffer(fb));
fb.setId(fbid); fb.setId(fbid);
@ -153,7 +154,16 @@ public final class Computer {
sendMessage(sender, "§eComputer reset."); sendMessage(sender, "§eComputer reset.");
} }
public void FixScreen(CommandSender sender) { public void SaveState(CommandSender sender) {
if (checkMachineNotRunning(sender))
return;
sendMessage(sender, "§eSaving computer state...");
synchronized (session) {
session.getMachine().saveState();
}
}
public void FixScreen(CommandSender sender, Boolean seamless) {
if (checkMachineNotRunning(sender)) if (checkMachineNotRunning(sender))
return; return;
if (framebuffer == null) { if (framebuffer == null) {
@ -166,15 +176,20 @@ public final class Computer {
sendMessage(sender, "§eFixing screen..."); sendMessage(sender, "§eFixing screen...");
try { try {
synchronized (session) { synchronized (session) {
session.getConsole().getDisplay().setSeamlessMode(false); if (seamless == null)
session.getConsole().getDisplay().detachFramebuffer(0L, framebuffer.getId()); session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L, false);
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L, true); } //Last param: notify - send PnP notification - stops updates but not changes for some reason
framebuffer.setId(session.getConsole().getDisplay().attachFramebuffer(0L, COMUtils.gimmeAFramebuffer(framebuffer))); Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, () -> {
synchronized (session) {
sendMessage(sender, "Needs host cursor: " + session.getConsole().getMouse().getNeedsHostCursor());
session.getConsole().getMouse().putMouseEventAbsolute(-1, -1, 0, 0, 0);
session.getConsole().getMouse().putMouseEvent(0, 0, 0, 0, 0); //Switch to relative mode
sendMessage(sender, "§eScreen fixed.");
} }
}, 20);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
sendMessage(sender, "§eScreen fixed.");
status = session.getConsole().getGuest().getFacilityStatus(AdditionsFacilityType.Seamless, lastUpdated); status = session.getConsole().getGuest().getFacilityStatus(AdditionsFacilityType.Seamless, lastUpdated);
sendMessage(sender, "Seamless status: " + status); sendMessage(sender, "Seamless status: " + status);
} }
@ -258,6 +273,7 @@ public final class Computer {
GPURenderer.update(new byte[1], 0, 0, 0, 0, 640, 480); //Black screen GPURenderer.update(new byte[1], 0, 0, 0, 0, 640, 480); //Black screen
stopEvents(); stopEvents();
MouseLockerPlayerListener.computerStop(); MouseLockerPlayerListener.computerStop();
framebuffer.stop();
} }
public void stopEvents() { public void stopEvents() {
@ -270,6 +286,7 @@ public final class Computer {
public void pluginDisable(CommandSender ccs) { public void pluginDisable(CommandSender ccs) {
stopEvents(); stopEvents();
framebuffer.stop();
if (session.getState() == SessionState.Locked) { if (session.getState() == SessionState.Locked) {
if (session.getMachine().getState().equals(MachineState.Running)) { if (session.getMachine().getState().equals(MachineState.Running)) {
ccs.sendMessage("§aSaving machine state..."); ccs.sendMessage("§aSaving machine state...");

View file

@ -15,6 +15,8 @@ import sznp.virtualcomputer.util.COMUtils;
import sznp.virtualcomputer.util.IMCFrameBuffer; import sznp.virtualcomputer.util.IMCFrameBuffer;
import sznp.virtualcomputer.util.Timing; import sznp.virtualcomputer.util.Timing;
import java.util.concurrent.atomic.AtomicBoolean;
@RequiredArgsConstructor @RequiredArgsConstructor
public class MCFrameBuffer implements IMCFrameBuffer { public class MCFrameBuffer implements IMCFrameBuffer {
private final IDisplay display; private final IDisplay display;
@ -23,10 +25,11 @@ public class MCFrameBuffer implements IMCFrameBuffer {
private Pointer pointer; private Pointer pointer;
private int width; private int width;
private int height; private int height;
private boolean updating = false;
@Getter @Getter
@Setter @Setter
private String id; private String id;
private final AtomicBoolean shouldUpdate = new AtomicBoolean();
private boolean running;
@Override @Override
public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) { public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) {
@ -35,7 +38,7 @@ public class MCFrameBuffer implements IMCFrameBuffer {
tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
synchronized (this) { //If a change occurs twice, then wait for it synchronized (this) { //If a change occurs twice, then wait for it
try { try {
System.out.println("Change: " + xOrigin + " " + yOrigin + " - " + width + " " + height); //System.out.println("Change: " + xOrigin + " " + yOrigin + " - " + width + " " + height);
display.querySourceBitmap(0L, holder); display.querySourceBitmap(0L, holder);
long[] ptr = new long[1], w = new long[1], h = new long[1], bpp = new long[1], bpl = new long[1], pf = new long[1]; long[] ptr = new long[1], w = new long[1], h = new long[1], bpp = new long[1], bpl = new long[1], pf = new long[1];
COMUtils.queryBitmapInfo(holder.value, ptr, w, h, bpp, bpl, pf); COMUtils.queryBitmapInfo(holder.value, ptr, w, h, bpp, bpl, pf);
@ -43,8 +46,9 @@ public class MCFrameBuffer implements IMCFrameBuffer {
pointer = new Pointer(ptr[0]); pointer = new Pointer(ptr[0]);
this.width = (int) w[0]; this.width = (int) w[0];
this.height = (int) h[0]; this.height = (int) h[0];
if (this.width > 1024 || this.height > 768) //System.out.println("Actual sizes: " + this.width + " " + this.height);
return; /*if (this.width > 1024 || this.height > 768)
return;*/
GPURenderer.update(pointer.getByteArray(0L, (int) (w[0] * h[0] * 4)), (int) w[0], (int) h[0], 0, 0, this.width, this.height); GPURenderer.update(pointer.getByteArray(0L, (int) (w[0] * h[0] * 4)), (int) w[0], (int) h[0], 0, 0, this.width, this.height);
} else { } else {
PluginMain.allpixels = new Pointer(ptr[0]).getByteBuffer(0L, width * height * 4); PluginMain.allpixels = new Pointer(ptr[0]).getByteBuffer(0L, width * height * 4);
@ -61,43 +65,63 @@ public class MCFrameBuffer implements IMCFrameBuffer {
e.printStackTrace(); e.printStackTrace();
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} finally { } /*finally {
System.out.println("Change finished"); System.out.println("Change finished");
} }*/
} }
}); });
} }
@Override @Override
public void notifyUpdate(long x, long y, long width, long height) { public void notifyUpdate(long x, long y, long width, long height) {
if (this.width > 1024 || this.height > 768) /*if (this.width > 1024 || this.height > 768)
return; return;*/
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { if(shouldUpdate.get())
return; //Don't wait for lock, ignore update since we're updating everything anyway - TODO: Not always
synchronized (this) { synchronized (this) {
if (updating) { shouldUpdate.set(true);
System.out.println("Ignoring update"); notifyAll();
return;
} }
updating = true;
if (pointer == null) {
System.out.println("Screen pointer is null");
updating = false;
return;
}
System.out.println("Update: " + x + " " + y + " - " + width + " " + height);
Timing t = new Timing();
GPURenderer.update(pointer.getByteArray(0L, this.width * this.height * 4), this.width, this.height, (int) x, (int) y, (int) width, (int) height);
if (t.elapsedMS() > 60) //Typically 1ms max
System.out.println("Update took " + t.elapsedMS() + "ms");
else
System.out.println("Update finished");
updating = false;
}
});
} }
@Override @Override
public void notifyUpdateImage(long x, long y, long width, long height, byte[] image) { public void notifyUpdateImage(long x, long y, long width, long height, byte[] image) {
System.out.println("Update image!"); System.out.println("Update image!");
} }
public void start() {
running = true;
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
try {
while (running) {
synchronized (this) {
while (!shouldUpdate.get())
wait(1000);
if (pointer == null) {
System.out.println("Screen pointer is null");
shouldUpdate.set(false);
continue;
}
if (!running) return;
//System.out.println("Update: " + x + " " + y + " - " + width + " " + height);
Timing t = new Timing(); //TODO: Add support for only sending changed fragments
GPURenderer.update(pointer.getByteArray(0L, this.width * this.height * 4), this.width, this.height, (int) 0, (int) 0, (int) width, (int) height);
if (t.elapsedMS() > 60) //Typically 1ms max
System.out.println("Update took " + t.elapsedMS() + "ms");
shouldUpdate.set(false);
/*else
System.out.println("Update finished");*/
}
}
} catch (InterruptedException ignored) {
}
});
}
public void stop() {
synchronized (this) {
running = false;
notifyAll();
}
}
} }