From bc7cd6f1a355f7ff1818ff0fa05fcb3fb87caa58 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 8 Feb 2022 22:21:23 -0600 Subject: [PATCH] ecs: temp vars --- src/common/ecs/binpack.ts | 71 ++++++++++++++++++++++++++++++--------- src/common/ecs/ecs.ts | 25 ++++++++++++++ src/test/testecs.ts | 41 ++++++++++++++++------ 3 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/common/ecs/binpack.ts b/src/common/ecs/binpack.ts index a0662cc9..d070d9e0 100644 --- a/src/common/ecs/binpack.ts +++ b/src/common/ecs/binpack.ts @@ -66,16 +66,26 @@ export class Bin { return result; } fits(b: Box) { - if (!boxesIntersect(this.binbounds, b)) return false; - if (this.getBoxes(b, 1).length > 0) return false; + if (!boxesIntersect(this.binbounds, b)) { + if (debug) console.log('out of bounds!', b.left,b.top,b.right,b.bottom); + return false; + } + if (this.getBoxes(b, 1).length > 0) { + if (debug) console.log('intersect!', b.left,b.top,b.right,b.bottom); + return false; + } return true; } - bestFit(b: Box) : Box | null { + bestFit(b: BoxConstraints) : Box | null { let bestscore = 0; let best = null; for (let f of this.free) { - let dx = (f.right - f.left) - (b.right - b.left); - let dy = (f.bottom - f.top) - (b.bottom - b.top); + if (b.left != null && b.left < f.left) continue; + if (b.left != null && b.left + b.width > f.right) continue; + if (b.top != null && b.top < f.top) continue; + if (b.top != null && b.top + b.height > f.bottom) continue; + let dx = (f.right - f.left) - b.width; + let dy = (f.bottom - f.top) - b.height; if (dx >= 0 && dy >= 0) { let score = 1 / (1 + dx + dy); if (score > bestscore) { @@ -85,8 +95,26 @@ export class Bin { } return best; } + anyFit(b: BoxConstraints) : Box | null { + let bestscore = 0; + let best = null; + for (let f of this.free) { + let box : Box = { + left: b.left != null ? b.left : f.left, + right: f.left + b.width, + top: b.top != null ? b.top : f.top, + bottom: f.top + b.height }; + if (this.fits(box)) { + let score = 1 / (1 + box.left + box.top); + if (score > bestscore) { + best = f; + } + } + } + return best; + } add(b: PlacedBox) { - if (debug) console.log('added',b.left,b.top,b.right,b.bottom); + if (debug) console.log('added', b.left,b.top,b.right,b.bottom); if (!this.fits(b)) { //console.log('collided with', this.getBoxes(b, 1)); throw new Error(`bad fit ${b.left} ${b.top} ${b.right} ${b.bottom}`) @@ -141,19 +169,29 @@ export class Packer { return true; } bestPlacement(b: BoxConstraints) : PlacedBox | null { - let left = b.left != null ? b.left : 0; - let top = b.top != null ? b.top : 0; - let right = left + b.width; - let bottom = top + b.height; for (let bin of this.bins) { let place : BoxPlacement = BoxPlacement.TopLeft; //TODO - let box = { left, top, right, bottom }; - let parent = bin.bestFit(box); + let parent = bin.bestFit(b); + if (!parent) { + parent = bin.anyFit(b); + if (debug) console.log('anyfit',parent?.left,parent?.top); + } if (parent) { - box.left = parent.left; - box.top = parent.top; - box.right = parent.left + b.width; - box.bottom = parent.top + b.height; + let box = { + left: parent.left, + top: parent.top, + right: parent.left + b.width, + bottom: parent.top + b.height + }; + if (b.left != null) { + box.left = b.left; + box.right = b.left + b.width; + } + if (b.top != null) { + box.top = b.top; + box.bottom = b.top + b.height; + } + if (debug) console.log('place',box.left,box.top,box.right,box.bottom,parent?.left,parent?.top); /* if (place == BoxPlacement.BottomLeft || place == BoxPlacement.BottomRight) { box.top = parent.bottom - (box.bottom - box.top); @@ -165,6 +203,7 @@ export class Packer { return { parent, place, bin, ...box }; } } + if (debug) console.log('cannot place!', b.left,b.top,b.width,b.height); return null; } } diff --git a/src/common/ecs/ecs.ts b/src/common/ecs/ecs.ts index a810d2b6..77441c5d 100644 --- a/src/common/ecs/ecs.ts +++ b/src/common/ecs/ecs.ts @@ -60,6 +60,7 @@ how to avoid cycle crossing for critical code and data? */ import { SourceLocated, SourceLocation } from "../workertypes"; +import { Bin, Packer } from "./binpack"; export class ECSError extends Error { $loc: SourceLocation; @@ -1150,6 +1151,29 @@ export class EntityScope implements SourceLocated { this.resources.add(symbol); return symbol; } + allocateTempVars() { + let pack = new Packer(); + let maxTempBytes = 128; // TODO + pack.bins.push(new Bin({ left:0, top:0, bottom: this.eventSeq+1, right: maxTempBytes })); + for (let sys of this.systems) { + let stats = this.getSystemStats(sys); + if (sys.tempbytes && stats.tempstartseq && stats.tempendseq) { + let v = { + sys, + top: stats.tempstartseq, + bottom: stats.tempendseq+1, + width: sys.tempbytes, + height: stats.tempendseq - stats.tempstartseq + 1, + }; + pack.boxes.push(v); + } + } + if (!pack.pack()) console.log('cannot pack temporary local vars'); // TODO + console.log('tempvars', pack); + for (let b of pack.boxes) { + console.log((b as any).sys.name, b.box); + } + } analyzeEntities() { this.buildSegments(); this.allocateSegment(this.bss, false); @@ -1173,6 +1197,7 @@ export class EntityScope implements SourceLocated { this.code.addCodeFragment(code); } //this.showStats(); + this.allocateTempVars(); } showStats() { for (let sys of this.systems) { diff --git a/src/test/testecs.ts b/src/test/testecs.ts index fcc31534..62feb4b3 100644 --- a/src/test/testecs.ts +++ b/src/test/testecs.ts @@ -2,7 +2,7 @@ import assert from "assert"; import { execFileSync, spawnSync } from "child_process"; import { readdirSync, readFileSync, writeFileSync } from "fs"; import { describe } from "mocha"; -import { Bin, Packer } from "../common/ecs/binpack"; +import { Bin, BoxConstraints, Packer } from "../common/ecs/binpack"; import { ECSCompiler } from "../common/ecs/compiler"; import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs"; @@ -396,18 +396,37 @@ describe('Compiler', function() { }); }); +function testPack(bins: Bin[], boxes: BoxConstraints[]) { + let packer = new Packer(); + for (let bin of bins) packer.bins.push(bin); + for (let bc of boxes) packer.boxes.push(bc); + if (!packer.pack()) throw new Error('cannot pack') + console.log(packer.boxes); + console.log(packer.bins[0].free) +} + describe('Box Packer', function() { it('Should pack boxes', function() { - let packer = new Packer(); - let bin1 = new Bin({ left:0, top:0, right:10, bottom:10 }); - packer.bins.push(bin1); - packer.boxes.push({ width: 5, height: 5 }); - packer.boxes.push({ width: 5, height: 5 }); - packer.boxes.push({ width: 5, height: 5 }); - packer.boxes.push({ width: 5, height: 5 }); - if (!packer.pack()) throw new Error('cannot pack') - console.log(packer.boxes); - console.log(packer.bins[0].free) + testPack( + [ + new Bin({ left:0, top:0, right:10, bottom:10 }) + ], [ + { width: 5, height: 5 }, + { width: 5, height: 5 }, + { width: 5, height: 5 }, + { width: 5, height: 5 }, + ] + ); + }); + it('Should pack temp vars', function() { + testPack( + [ + new Bin({ left:0, top:0, right:10, bottom:10 }) + ], [ + { width: 3, height: 7, top: 0 }, + { width: 3, height: 7, top: 1 }, + ] + ); }); });