VNC-132 Fix image rendering logic to decrease memory usage (#141)
* VNC-132 Fix image rendering logic to decrease memory usage * Updating the recalculate primary display container size logic to ensure an even resolution is set * VNC-132 Free memory after rendering bitmap image * VNC-132 Update screen channel logic
This commit is contained in:
parent
4d5609e9c4
commit
b2a6b2a2e4
19
app/ui.js
19
app/ui.js
|
|
@ -41,6 +41,7 @@ import Keyboard from "../core/input/keyboard.js";
|
|||
import RFB from "../core/rfb.js";
|
||||
import { MouseButtonMapper, XVNC_BUTTONS } from "../core/mousebuttonmapper.js";
|
||||
import * as WebUtil from "./webutil.js";
|
||||
import { uuidv4 } from '../core/util/strings.js';
|
||||
|
||||
const PAGE_TITLE = "KasmVNC";
|
||||
|
||||
|
|
@ -70,7 +71,8 @@ const UI = {
|
|||
selectedMonitor: null,
|
||||
refreshRotation: 0,
|
||||
currentDisplay: null,
|
||||
displayWindows: ['primary'],
|
||||
displayWindows: new Map([['primary', 'primary']]),
|
||||
registeredWindows: new Map([['primary', 'primary']]),
|
||||
|
||||
supportsBroadcastChannel: (typeof BroadcastChannel !== "undefined"),
|
||||
|
||||
|
|
@ -2009,8 +2011,9 @@ const UI = {
|
|||
},
|
||||
|
||||
async addSecondaryMonitor() {
|
||||
let new_display_path = window.location.pathname.replace(/[^/]*$/, '')
|
||||
let new_display_url = `${window.location.protocol}//${window.location.host}${new_display_path}screen.html`;
|
||||
let new_display_path = window.location.pathname.replace(/[^/]*$/, '');
|
||||
const windowId = uuidv4();
|
||||
let new_display_url = `${window.location.protocol}//${window.location.host}${new_display_path}screen.html?windowId=${windowId}`;
|
||||
|
||||
const auto_placement = document.getElementById('noVNC_auto_placement').checked
|
||||
if (auto_placement && 'getScreenDetails' in window) {
|
||||
|
|
@ -2024,7 +2027,7 @@ const UI = {
|
|||
let screen = details.screens[current]
|
||||
const options = 'left='+screen.availLeft+',top='+screen.availTop+',width='+screen.availWidth+',height='+screen.availHeight+',fullscreen'
|
||||
let newdisplay = window.open(new_display_url, '_blank', options);
|
||||
UI.displayWindows.push(newdisplay);
|
||||
UI.displayWindows.set(windowId, newdisplay);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -2035,14 +2038,16 @@ const UI = {
|
|||
|
||||
Log.Debug(`Opening a secondary display ${new_display_url}`)
|
||||
let newdisplay = window.open(new_display_url, '_blank', 'toolbar=0,location=0,menubar=0');
|
||||
UI.displayWindows.push(newdisplay);
|
||||
if (newdisplay) {
|
||||
UI.displayWindows.set(windowId, newdisplay);
|
||||
}
|
||||
},
|
||||
|
||||
initMonitors(screenPlan) {
|
||||
const { scale } = UI.multiMonitorSettings()
|
||||
let monitors = []
|
||||
let showNativeResolution = false
|
||||
let num = 1
|
||||
let num = 1;
|
||||
screenPlan.screens.forEach(screen => {
|
||||
if (parseFloat(screen.pixelRatio) != 1) {
|
||||
showNativeResolution = true
|
||||
|
|
@ -2223,7 +2228,9 @@ const UI = {
|
|||
serverWidth: Math.round(width * scale),
|
||||
screens
|
||||
}
|
||||
if (UI.rfb) {
|
||||
UI.rfb.applyScreenPlan(screenPlan);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ export default class Display {
|
|||
return changes;
|
||||
}
|
||||
|
||||
addScreen(screenID, width, height, pixelRatio, containerHeight, containerWidth, scale, serverWidth, serverHeight, x, y) {
|
||||
addScreen(screenID, width, height, pixelRatio, containerHeight, containerWidth, scale, serverWidth, serverHeight, x, y, windowId) {
|
||||
if (!this._isPrimaryDisplay) {
|
||||
throw new Error("Cannot add a screen to a secondary display.");
|
||||
}
|
||||
|
|
@ -432,14 +432,18 @@ export default class Display {
|
|||
pixelRatio: pixelRatio,
|
||||
containerHeight: containerHeight,
|
||||
containerWidth: containerWidth,
|
||||
channel: UI.displayWindows[this.screens.length],
|
||||
channel: UI.displayWindows.get(windowId),
|
||||
scale: scale,
|
||||
x2: x + serverWidth,
|
||||
y2: serverHeight
|
||||
}
|
||||
|
||||
this._screens.push(new_screen);
|
||||
if (new_screen.channel) {
|
||||
UI.registeredWindows.set(screenID, windowId);
|
||||
new_screen.channel.postMessage({eventType: "registered", screenIndex: new_screen.screenIndex});
|
||||
} else
|
||||
Log.Debug(`Channel not found for screenId ${screenID}`);
|
||||
|
||||
return new_screen.screenIndex;
|
||||
}
|
||||
|
|
@ -454,7 +458,11 @@ export default class Display {
|
|||
if (this._screens[i].screenID == screenID) {
|
||||
//flush all rects on target screen
|
||||
this._flushRectsScreen(i);
|
||||
UI.displayWindows.splice(i, 1);
|
||||
const windowId = UI.registeredWindows.get(screenID);
|
||||
if (windowId) {
|
||||
UI.registeredWindows.delete(screenID);
|
||||
UI.displayWindows.delete(windowId);
|
||||
}
|
||||
this._screens.splice(i, 1);
|
||||
removed = true;
|
||||
break;
|
||||
|
|
@ -757,30 +765,22 @@ export default class Display {
|
|||
return;
|
||||
}
|
||||
|
||||
let rect = {
|
||||
'type': 'img',
|
||||
const blob = new Blob([arr], { type: mime });
|
||||
const rect = {
|
||||
'type': 'bitmap',
|
||||
'img': null,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
'frame_id': frame_id
|
||||
}
|
||||
'frame_id': frame_id,
|
||||
'mime': mime
|
||||
};
|
||||
this._processRectScreens(rect);
|
||||
|
||||
if (rect.inPrimary) {
|
||||
const img = new Image();
|
||||
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
||||
rect.img = img;
|
||||
} else {
|
||||
rect.type = "_img";
|
||||
}
|
||||
if (rect.inSecondary) {
|
||||
rect.mime = mime;
|
||||
rect.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
||||
}
|
||||
|
||||
createImageBitmap(blob).then((bitmapImg) => {
|
||||
rect.img = bitmapImg;
|
||||
this._asyncRenderQPush(rect);
|
||||
});
|
||||
}
|
||||
|
||||
transparentRect(x, y, width, height, img, frame_id, hashId) {
|
||||
|
|
@ -1027,6 +1027,10 @@ export default class Display {
|
|||
this.drawImage(a.img, pos.x, pos.y, a.width, a.height);
|
||||
a.img.close();
|
||||
break;
|
||||
case 'bitmap':
|
||||
this.drawImage(a.img, pos.x, pos.y, a.width, a.height);
|
||||
a.img.close();
|
||||
break;
|
||||
default:
|
||||
this._syncFrameQueue.shift();
|
||||
continue;
|
||||
|
|
@ -1238,11 +1242,18 @@ export default class Display {
|
|||
case 'vid':
|
||||
this.drawImage(a.img, screenLocation.x, screenLocation.y, a.width, a.height);
|
||||
break;
|
||||
case 'bitmap':
|
||||
this.drawImage(a.img, screenLocation.x, screenLocation.y, a.width, a.height);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
primaryScreenRects++;
|
||||
} else {
|
||||
if (!this._screens[screenLocation.screenIndex]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (a.type) {
|
||||
case 'dummy':
|
||||
case 'transparent':
|
||||
|
|
@ -1250,7 +1261,7 @@ export default class Display {
|
|||
break;
|
||||
case 'vid':
|
||||
secondaryScreenRects++;
|
||||
if (this._screens[screenLocation.screenIndex].channel) {
|
||||
if (this._screens[screenLocation.screenIndex]?.channel) {
|
||||
this._screens[screenLocation.screenIndex].channel.postMessage({
|
||||
eventType: 'rect',
|
||||
rect: {
|
||||
|
|
@ -1267,6 +1278,25 @@ export default class Display {
|
|||
}, [a.img]);
|
||||
}
|
||||
break;
|
||||
case 'bitmap':
|
||||
secondaryScreenRects++;
|
||||
if (this._screens[screenLocation.screenIndex].channel) {
|
||||
this._screens[screenLocation.screenIndex].channel.postMessage({
|
||||
eventType: 'rect',
|
||||
rect: {
|
||||
'type': 'bitmap',
|
||||
'img': a.img,
|
||||
'x': a.x,
|
||||
'y': a.y,
|
||||
'width': a.width,
|
||||
'height': a.height,
|
||||
'frame_id': a.frame_id,
|
||||
'screenLocations': a.screenLocations
|
||||
},
|
||||
screenLocationIndex: sI
|
||||
}, [a.img]);
|
||||
}
|
||||
break;
|
||||
case 'blit':
|
||||
secondaryScreenRects++;
|
||||
let buf = a.data.buffer;
|
||||
|
|
@ -1434,6 +1464,8 @@ export default class Display {
|
|||
this._target.style.imageRendering = 'auto'; //auto is really smooth (blurry) using trilinear of linear
|
||||
Log.Debug('Smoothing enabled');
|
||||
}
|
||||
|
||||
requestAnimationFrame( () => { this._pushAsyncFrame(); });
|
||||
}
|
||||
|
||||
_setFillColor(color) {
|
||||
|
|
|
|||
|
|
@ -1817,7 +1817,7 @@ export default class RFB extends EventTargetMixin {
|
|||
...event.data.details,
|
||||
screenID: event.data.screenID
|
||||
}
|
||||
let screenIndex = this._display.addScreen(event.data.screenID, event.data.width, event.data.height, event.data.pixelRatio, event.data.containerHeight, event.data.containerWidth, event.data.scale, event.data.serverWidth, event.data.serverHeight, event.data.x, event.data.y);
|
||||
let screenIndex = this._display.addScreen(event.data.screenID, event.data.width, event.data.height, event.data.pixelRatio, event.data.containerHeight, event.data.containerWidth, event.data.scale, event.data.serverWidth, event.data.serverHeight, event.data.x, event.data.y, event.data.windowId);
|
||||
this._proxyRFBMessage('screenRegistrationConfirmed', [ this._display.screens[screenIndex].screenID, screenIndex ]);
|
||||
this._sendEncodings();
|
||||
clearTimeout(this._resizeTimeout);
|
||||
|
|
@ -1826,7 +1826,7 @@ export default class RFB extends EventTargetMixin {
|
|||
Log.Info(`Secondary monitor (${event.data.screenID}) has been registered.`);
|
||||
break;
|
||||
case 'reattach':
|
||||
let changes = this._display.addScreen(event.data.screenID, event.data.width, event.data.height, event.data.pixelRatio, event.data.containerHeight, event.data.containerWidth, event.data.scale, event.data.serverWidth, event.data.serverHeight, event.data.x, event.data.y);
|
||||
let changes = this._display.addScreen(event.data.screenID, event.data.width, event.data.height, event.data.pixelRatio, event.data.containerHeight, event.data.containerWidth, event.data.scale, event.data.serverWidth, event.data.serverHeight, event.data.x, event.data.y, event.data.windowId);
|
||||
|
||||
clearTimeout(this._resizeTimeout);
|
||||
this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 500);
|
||||
|
|
@ -1971,10 +1971,12 @@ export default class RFB extends EventTargetMixin {
|
|||
this._display.autoscale(size.screens[0].serverWidth, size.screens[0].serverHeight, size.screens[0].scale);
|
||||
|
||||
let screen = size.screens[0];
|
||||
const windowId = new URLSearchParams(document.location.search).get('windowId');
|
||||
|
||||
let message = {
|
||||
eventType: registerType,
|
||||
screenID: screen.screenID,
|
||||
windowId,
|
||||
width: screen.width,
|
||||
height: screen.height,
|
||||
x: currentScreen.x || 0,
|
||||
|
|
|
|||
Loading…
Reference in New Issue