Skip to content
This repository has been archived by the owner on Jul 3, 2020. It is now read-only.

Add graphics subsystem #130

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions js/core/graphics/graphics-renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2016-present runtime.js project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const nameSymbol = Symbol('name');

class GraphicsRenderer {
constructor(name = '') {
this[nameSymbol] = name;
this.ongetbuffer = null;
this.onenablegraphics = null;
this.constants = {};
}
get name() {
return this[nameSymbol];
}
get displayBuffer() {
if (!this.ongetbuffer) {
throw new Error('renderer not initialized');
}
return this.ongetbuffer();
}
enableGraphics(width, height, bitDepth) {
if (!this.onenablegraphics) {
throw new Error('renderer not initialized');
}
this.onenablegraphics(width, height, bitDepth);
}
}

module.exports = GraphicsRenderer;
29 changes: 29 additions & 0 deletions js/core/graphics/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const GraphicsRenderer = require('./graphics-renderer');
const { Screen, symbols: screenSymbols } = require('./screen');
const renderers = require('./renderers');
const screen = new Screen();

module.exports = {
graphicsAvailable() {
return renderers.renderersAvailable();
},
enableGraphics(width, height, bitDepth) {
const renderer = renderers.getDefaultRenderer();
renderer.enableGraphics(width, height, bitDepth);
screen[screenSymbols.reset]();
screen[screenSymbols.init](width, height, bitDepth, renderer);
},
GraphicsRenderer,
get screen() {
return screen;
},
get displayBuffer() {
return renderers.getDefaultRenderer().displayBuffer;
},
addRenderer: renderers.addRenderer,
get constants() {
return renderers.getConstants();
},
};
41 changes: 41 additions & 0 deletions js/core/graphics/renderers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2016-present runtime.js project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

let defaultRenderer = null;
const availableRenderers = new Map();

module.exports = {
addRenderer(renderer) {
availableRenderers.set(renderer.name, renderer);

console.log(`[graphics] using renderer ${renderer.name}`);

defaultRenderer = renderer;
},
renderersAvailable() {
return availableRenderers.size !== 0;
},
getDefaultRenderer() {
return defaultRenderer;
},
getConstants() {
const consts = {};
for (const renderer of availableRenderers.values()) {
Object.assign(consts, renderer.constants);
}
return consts;
},
};
64 changes: 64 additions & 0 deletions js/core/graphics/screen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2016-present runtime.js project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

// The properties `width`, `height`, and `bitDepth` are
// Symbols because they shouldn't be set.
const symbols = {
width: Symbol('width'),
height: Symbol('height'),
bitDepth: Symbol('bitDepth'),
init: Symbol('init'),
reset: Symbol('reset'),
initialized: Symbol('initialized'),
renderer: Symbol('renderer'),
};

class Screen {
constructor() {
this[symbols.reset]();
}
[symbols.init](width, height, bitDepth, renderer) {
this[symbols.width] = width;
this[symbols.height] = height;
this[symbols.bitDepth] = bitDepth;
this[symbols.renderer] = renderer;
this[symbols.initialized] = true;
}
[symbols.reset]() {
this[symbols.width] = 0;
this[symbols.height] = 0;
this[symbols.bitDepth] = 0;
this[symbols.renderer] = null;
this[symbols.initialized] = false;
}
get width() {
return this[symbols.width];
}
get height() {
return this[symbols.height];
}
get bitDepth() {
return this[symbols.bitDepth];
}
get bufferFormat() {
return this[symbols.renderer].name;
}
}

module.exports = {
Screen,
symbols,
};
2 changes: 2 additions & 0 deletions js/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ps2 = require('./ps2');
const pci = require('./pci');
const net = require('./net');
const stdio = require('./stdio');
const graphics = require('./graphics');

class Runtime {
constructor() {
Expand All @@ -34,6 +35,7 @@ class Runtime {
allocator,
net,
stdio,
graphics,
machine: {
reboot: __SYSCALL.reboot,
shutdown: () => __SYSCALL.acpiEnterSleepState(5),
Expand Down
35 changes: 35 additions & 0 deletions js/driver/bga/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

module.exports = {
VBE_DISPI_IOPORT_INDEX: 0x01CE,
VBE_DISPI_IOPORT_DATA: 0x01CF,
VBE_DISPI_INDEX_ID: 0x0,
VBE_DISPI_INDEX_XRES: 0x1,
VBE_DISPI_INDEX_YRES: 0x2,
VBE_DISPI_INDEX_BPP: 0x3,
VBE_DISPI_INDEX_ENABLE: 0x4,
VBE_DISPI_INDEX_BANK: 0x5,
VBE_DISPI_INDEX_VIRT_WIDTH: 0x6,
VBE_DISPI_INDEX_VIRT_HEIGHT: 0x7,
VBE_DISPI_INDEX_X_OFFSET: 0x8,
VBE_DISPI_INDEX_Y_OFFSET: 0x9,
VBE_DISPI_INDEX_VIDEO_MEMORY_64K: 0xa,
VBE_DISPI_BPP_4: 0x04,
VBE_DISPI_BPP_8: 0x08,
VBE_DISPI_BPP_15: 0x0F,
VBE_DISPI_BPP_16: 0x10,
VBE_DISPI_BPP_24: 0x18,
VBE_DISPI_BPP_32: 0x20,
VBE_DISPI_NOCLEARMEM: 0x80,
VBE_DISPI_DISABLED: 0x00,
VBE_DISPI_ENABLED: 0x01,
VBE_DISPI_LFB_ENABLED: 0x40,
VBE_DISPI_ID0: 0xB0C0,
VBE_DISPI_ID1: 0xB0C1,
VBE_DISPI_ID2: 0xB0C2,
VBE_DISPI_ID3: 0xB0C3,
VBE_DISPI_ID4: 0xB0C4,
VBE_DISPI_ID5: 0xB0C5,
VBE_DISPI_GETCAP: 0x02,
VBE_DISPI_8BIT_DAC: 0x20,
};
46 changes: 46 additions & 0 deletions js/driver/bga/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

const { ioPort } = require('../../core/driver-utils');
const constants = require('./constants');
const vbeDispiIoportIndex = ioPort(constants.VBE_DISPI_IOPORT_INDEX);
const vbeDispiIoportData = ioPort(constants.VBE_DISPI_IOPORT_DATA);

function writeBgaRegister(index, data) {
vbeDispiIoportIndex.write16(index >>> 0);
vbeDispiIoportData.write16(data >>> 0);
}
function readBgaRegister(index) {
vbeDispiIoportIndex.write16(index >>> 0);
return vbeDispiIoportData.read16();
}
function bgaAvailable() {
const bgaVersion = readBgaRegister(constants.VBE_DISPI_INDEX_ID);
for (const i of [0, 1, 2, 3, 4, 5]) {
if (bgaVersion === constants[`VBE_DISPI_ID${i}`]) {
return true;
}
}
return false;
}

if (bgaAvailable()) {
const driver = {
init(device) {
const buf = new Uint8Array(device.bars[0].resource.buffer());
const renderer = new runtime.graphics.GraphicsRenderer('bga');
renderer.onenablegraphics = (width, height, bitDepth) => {
writeBgaRegister(constants.VBE_DISPI_INDEX_ENABLE, constants.VBE_DISPI_DISABLED);
writeBgaRegister(constants.VBE_DISPI_INDEX_XRES, width);
writeBgaRegister(constants.VBE_DISPI_INDEX_YRES, height);
writeBgaRegister(constants.VBE_DISPI_INDEX_BPP, bitDepth);
writeBgaRegister(constants.VBE_DISPI_INDEX_ENABLE, constants.VBE_DISPI_ENABLED | constants.VBE_DISPI_LFB_ENABLED);
};
renderer.ongetbuffer = () => buf;
renderer.constants = constants;
runtime.graphics.addRenderer(renderer);
},
reset() {},
};

runtime.pci.addDriver(0x1234, 0x1111, driver);
}
1 change: 1 addition & 0 deletions js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ runtime.shell.setCommand('reboot', (args, env, cb) => {
// Start device drivers
require('./driver/ps2');
require('./driver/virtio');
require('./driver/bga');

// Set time
require('./core/cmos-time'); // load cmos
Expand Down