GPU speed up: Writing to the gpu buffer outside the viewport is free. no budget cost, no power cost, (also, writes are already direct calls)

We've discussed a large variety of options for the gpu
I've reviewed our options and suggestions. Ultimately - users want faster graphics. Most of the ideas are relating to what api is meaningful to the user. The core issue we have in making graphics faster is an increase load on the server.
For example
  Tier 3 GPU and Tier 3 Screen has a max resolution of 160x50
  If you set the viewport (via gpu.setViewport) to 160x25 the bottom half of the buffer will no longer be shown. All gpu.set, gpu.copy, and gpu.fill calls into that space have no cost
  Overlaps are calculated for partial cost. Half in and half out will have half the power cost.

closes #779
This commit is contained in:
payonel 2020-05-15 21:01:41 -07:00
parent a13792aef3
commit 15d34a8660

View File

@ -71,16 +71,40 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
DeviceAttribute.Clock -> clockInfo
)
def capacityInfo = (maxResolution._1 * maxResolution._2).toString
def capacityInfo: String = (maxResolution._1 * maxResolution._2).toString
def widthInfo = Array("1", "4", "8").apply(maxDepth.ordinal())
def widthInfo: String = Array("1", "4", "8").apply(maxDepth.ordinal())
def clockInfo = ((2000 / setBackgroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setForegroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setPaletteColorCosts(tier)).toInt / 100).toString + "/" + ((2000 / setCosts(tier)).toInt / 100).toString + "/" + ((2000 / copyCosts(tier)).toInt / 100).toString + "/" + ((2000 / fillCosts(tier)).toInt / 100).toString
def clockInfo: String = ((2000 / setBackgroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setForegroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setPaletteColorCosts(tier)).toInt / 100).toString + "/" + ((2000 / setCosts(tier)).toInt / 100).toString + "/" + ((2000 / copyCosts(tier)).toInt / 100).toString + "/" + ((2000 / fillCosts(tier)).toInt / 100).toString
override def getDeviceInfo: util.Map[String, String] = deviceInfo
// ----------------------------------------------------------------------- //
private def getViewportOverlapSize(s: api.internal.TextBuffer, x1: Int, y1: Int, x2: Int, y2: Int): Int = {
val width = s.getViewportWidth
val height = s.getViewportHeight
val left = math.min(x1, x2);
val right = math.max(x1, x2);
val top = math.min(y1, y2);
val bottom = math.max(y1, y2);
if (right < 0 || left >= width || top >= height || bottom < 0)
return 0
val box_left = math.max(0, left)
val box_right = math.min(width - 1, right)
val box_top = math.max(0, top)
val box_bottom = math.min(height - 1, bottom)
(box_right - box_left + 1) * (box_bottom - box_top + 1)
}
private def consumeViewportPower(overlap: Int, context: Context, budgetCost: Double, callFactor: Double): Boolean = {
if (overlap == 0) true
else {
context.consumeCallBudget(budgetCost)
consumePower(overlap, callFactor)
}
}
@Callback(doc = """function(address:string[, reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""")
def bind(context: Context, args: Arguments): Array[AnyRef] = {
val address = args.checkString(0)
@ -275,14 +299,16 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
@Callback(direct = true, doc = """function(x:number, y:number, value:string[, vertical:boolean]):boolean -- Plots a string value to the screen at the specified position. Optionally writes the string vertically.""")
def set(context: Context, args: Arguments): Array[AnyRef] = {
context.consumeCallBudget(setCosts(tier))
val x = args.checkInteger(0) - 1
val y = args.checkInteger(1) - 1
val value = args.checkString(2)
val vertical = args.optBoolean(3, false)
screen(s => {
if (consumePower(value.length, Settings.get.gpuSetCost)) {
val x2 = if (vertical) x else x + value.length - 1
val y2 = if (!vertical) y else y + value.length - 1
val overlap: Int = getViewportOverlapSize(s, x, y, x2, y2)
if (consumeViewportPower(overlap, context, setCosts(tier), Settings.get.gpuSetCost)) {
s.set(x, y, value, vertical)
result(true)
}
@ -292,7 +318,6 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
@Callback(direct = true, doc = """function(x:number, y:number, width:number, height:number, tx:number, ty:number):boolean -- Copies a portion of the screen from the specified location with the specified size by the specified translation.""")
def copy(context: Context, args: Arguments): Array[AnyRef] = {
context.consumeCallBudget(copyCosts(tier))
val x = args.checkInteger(0) - 1
val y = args.checkInteger(1) - 1
val w = math.max(0, args.checkInteger(2))
@ -300,7 +325,8 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
val tx = args.checkInteger(4)
val ty = args.checkInteger(5)
screen(s => {
if (consumePower(w * h, Settings.get.gpuCopyCost)) {
val overlap: Int = getViewportOverlapSize(s, x + tx, y + ty, x + tx + w - 1, y + ty + h - 1)
if (consumeViewportPower(overlap, context, copyCosts(tier), Settings.get.gpuCopyCost)) {
s.copy(x, y, w, h, tx, ty)
result(true)
}
@ -319,7 +345,8 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
if (value.length == 1) screen(s => {
val c = value.charAt(0)
val cost = if (c == ' ') Settings.get.gpuClearCost else Settings.get.gpuFillCost
if (consumePower(w * h, cost)) {
val overlap: Int = getViewportOverlapSize(s, x, y, x + w - 1, y + h - 1)
if (consumeViewportPower(overlap, context, fillCosts(tier), cost)) {
s.fill(x, y, w, h, value.charAt(0))
result(true)
}