gpu budget cleanup - made the vram bitblt budget and energy cost far more reasonable and logical

note: dirty page bitblts to a screen are increasinly expensive for larger buffers
bitblts to vram are "free" (no budget, no energy)
note that any direct component call has a minimum .001 budget cost
This commit is contained in:
payonel 2020-05-17 23:33:01 -07:00
parent efe6cbc1e7
commit fabe7bac43

View File

@ -70,7 +70,7 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
final val setCosts = Array(1.0 / 64, 1.0 / 128, 1.0 / 256)
final val copyCosts = Array(1.0 / 16, 1.0 / 32, 1.0 / 64)
final val fillCosts = Array(1.0 / 32, 1.0 / 64, 1.0 / 128)
final val bitbltCosts = Array(2.0, 1.0, 1.0 / 2.0)
final val bitbltCosts = Array(32, 16, 8)
final val totalVRAM: Int = (maxResolution._1 * maxResolution._2) * Settings.get.vramSizes(0 max tier min Settings.get.vramSizes.length)
// ----------------------------------------------------------------------- //
@ -189,6 +189,29 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
screen(idx, s => result(s.getWidth, s.getHeight))
}
private def determineBitbltBudgetCost(dst: api.internal.TextBuffer, src: api.internal.TextBuffer): Double = {
// large dirty buffers need throttling so their budget cost is more
// clean buffers have no budget cost.
src match {
case page: GpuTextBuffer if page.dirty => dst match {
case _: GpuTextBuffer => 0.0 // no cost to write to ram
case _ => // screen target will need the new buffer
// small buffers are cheap, so increase with size of buffer source
bitbltCosts(tier) * (src.getWidth * src.getHeight) / (maxResolution._1 * maxResolution._2)
}
case _ => 0.0 // from screen or from clean buffer is free
}
}
private def determineBitbltEnergyCost(dst: api.internal.TextBuffer): Double = {
// memory to memory copies are extremely energy efficient
// rasterizing to the screen has the same cost as copy (in fact, screen-to-screen blt _is_ a copy
dst match {
case _: GpuTextBuffer => 0
case _ => Settings.get.gpuCopyCost / (maxResolution._1 * maxResolution._2)
}
}
@Callback(direct = true, doc = """function([dst: number, col: number, row: number, width: number, height: number, src: number, fromCol: number, fromRow: number]):boolean -- bitblt from buffer to screen. All parameters are optional. Writes to `dst` page in rectangle `x, y, width, height`, defaults to the bound screen and its viewport. Reads data from `src` page at `fx, fy`, default is the active page from position 1, 1""")
def bitblt(context: Context, args: Arguments): Array[AnyRef] = {
val dstIdx = args.optInteger(0, RESERVED_SCREEN_INDEX)
@ -201,13 +224,11 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI
screen(srcIdx, src => {
val fromCol = args.optInteger(6, 1)
val fromRow = args.optInteger(7, 1)
// if src is vram and dirty, bltbit cost is large
val dirtyPage = src match {
case vram: GpuTextBuffer => vram.dirty
case _ => false
}
if (consumeViewportPower(dst, context, if (dirtyPage) bitbltCosts(tier) else setCosts(tier), w * h, Settings.get.gpuCopyCost)) {
val budgetCost: Double = determineBitbltBudgetCost(dst, src)
val energyCost: Double = determineBitbltEnergyCost(dst)
if (consumeViewportPower(dst, context, budgetCost, w * h, energyCost)) {
if (dstIdx == srcIdx) {
val tx = col - fromCol
val ty = row - fromRow