From f619657e097e41110109f26acd1ab7db54227898 Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 19 May 2023 16:00:09 +0800 Subject: [PATCH] Support 16 bit Hextile --- core/decoders/hextile.js | 85 ++++++++++++++++++++++++++++++++-------- core/rfb.js | 18 ++++++++- 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/core/decoders/hextile.js b/core/decoders/hextile.js index ac21eff03..67248e5dd 100644 --- a/core/decoders/hextile.js +++ b/core/decoders/hextile.js @@ -34,6 +34,11 @@ export default class HextileDecoder { let rQ = sock.rQ; let rQi = sock.rQi; + let bpp = 4; // Bytes per pixel + if (depth == 16) { + bpp = 2; + } + let subencoding = rQ[rQi]; // Peek if (subencoding > 30) { // Raw throw new Error("Illegal hextile subencoding (subencoding: " + @@ -50,13 +55,13 @@ export default class HextileDecoder { // Figure out how much we are expecting if (subencoding & 0x01) { // Raw - bytes += tw * th * 4; + bytes += tw * th * bpp; } else { if (subencoding & 0x02) { // Background - bytes += 4; + bytes += bpp; } if (subencoding & 0x04) { // Foreground - bytes += 4; + bytes += bpp; } if (subencoding & 0x08) { // AnySubrects bytes++; // Since we aren't shifting it off @@ -67,7 +72,7 @@ export default class HextileDecoder { let subrects = rQ[rQi + bytes - 1]; // Peek if (subencoding & 0x10) { // SubrectsColoured - bytes += subrects * (4 + 2); + bytes += subrects * (bpp + 2); } else { bytes += subrects * 2; } @@ -88,21 +93,26 @@ export default class HextileDecoder { display.fillRect(tx, ty, tw, th, this._background); } } else if (subencoding & 0x01) { // Raw - let pixels = tw * th; - // Max sure the image is fully opaque - for (let i = 0;i < pixels;i++) { - rQ[rQi + i * 4 + 3] = 255; - } - display.blitImage(tx, ty, tw, th, rQ, rQi); + this._blitImage(tx, ty, tw, th, rQ, rQi, display, depth); rQi += bytes - 1; } else { if (subencoding & 0x02) { // Background - this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; - rQi += 4; + if (depth == 16) { + this._background = this._extractRgb565([rQ[rQi], rQ[rQi + 1]]); + } else { + this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + } + + rQi += bpp; } if (subencoding & 0x04) { // Foreground - this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; - rQi += 4; + if (depth == 16) { + this._foreground = this._extractRgb565([rQ[rQi], rQ[rQi + 1]]); + } else { + this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + } + + rQi += bpp; } this._startTile(tx, ty, tw, th, this._background); @@ -113,8 +123,13 @@ export default class HextileDecoder { for (let s = 0; s < subrects; s++) { let color; if (subencoding & 0x10) { // SubrectsColoured - color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; - rQi += 4; + if (depth == 16) { + color = this._extractRgb565([rQ[rQi], rQ[rQi + 1]]); + } else { + color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + } + + rQi += bpp; } else { color = this._foreground; } @@ -188,4 +203,42 @@ export default class HextileDecoder { this._tileW, this._tileH, this._tileBuffer, 0); } + + _blitImage(x, y, width, height, arr, offset, display, depth) { + let pixels = width * height; + + if (depth == 16) { + const newArr = new Uint8Array(pixels * 4); + + for (let i = 0, j = offset; i < pixels * 4; i += 4, j += 2) { + let color = this._extractRgb565([arr[j], arr[j + 1]]); + + newArr[i] = color[0]; // Red + newArr[i + 1] = color[1]; // Green + newArr[i + 2] = color[2]; // Blue + newArr[i + 3] = 255; // Alpha + } + + display.blitImage(x, y, width, height, newArr, 0); + } else { + // Make sure the image is fully opaque + for (let i = 0; i < pixels; i++) { + arr[offset + i * 4 + 3] = 255; + } + + display.blitImage(x, y, width, height, arr, offset); + } + } + + // extract color components of rgb565 + _extractRgb565(color) { + let rgb565 = color[0] + (color[1] << 8); + let red, green, blue; + + red = (rgb565 & 0xf800) >> 8; + green = (rgb565 & 0x07e0) >> 3; + blue = (rgb565 & 0x001f) << 3; + + return [red, green, blue]; + } } diff --git a/core/rfb.js b/core/rfb.js index 6afd7c659..dc846e77a 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -2127,6 +2127,11 @@ export default class RFB extends EventTargetMixin { this._fbDepth = 8; } + if (this._fbName === "OpenBMC IKVM" || this._fbName === "obmc iKVM") { + Log.Warn("NPCM Hextile supports 16 bit depths. Using low color mode."); + this._fbDepth = 16; + } + RFB.messages.pixelFormat(this._sock, this._fbDepth, true); this._sendEncodings(); RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight); @@ -2146,9 +2151,13 @@ export default class RFB extends EventTargetMixin { encs.push(encodings.encodingTightPNG); encs.push(encodings.encodingZRLE); encs.push(encodings.encodingJPEG); - encs.push(encodings.encodingHextile); encs.push(encodings.encodingRRE); } + + if (this._fbDepth >= 16) { + encs.push(encodings.encodingHextile); + } + encs.push(encodings.encodingRaw); // Psuedo-encoding settings @@ -3282,6 +3291,13 @@ RFB.messages = { buff[offset + 18] = 0; // padding buff[offset + 19] = 0; // padding + // adjust green-max, red-shift and blue-shift for rgb565 + if (depth == 16) { + buff[offset + 11] = (1 << 6) - 1; // green-max + buff[offset + 14] = 11; // red-shift + buff[offset + 16] = 0; // blue-shift + } + sock._sQlen += 20; sock.flush(); },