Skip to content

Commit

Permalink
FXAA improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Штенгауэр Никита Дмитриевич authored and husker-dev committed Dec 3, 2023
1 parent 460021b commit 6f42684
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 155 deletions.
24 changes: 12 additions & 12 deletions modules/core/src/main/kotlin/com/huskerdev/openglfx/GLExecutor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,21 @@ open class GLExecutor {
}
}

open fun blitNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile, flipY: Boolean, msaa: Int, async: Boolean) =
if(async) AsyncBlitCanvasImpl(canvas, executor, profile, flipY, msaa)
else BlitCanvasImpl(canvas, executor, profile, flipY, msaa)
open fun blitNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile) =
if(canvas.async) AsyncBlitCanvasImpl(canvas, executor, profile)
else BlitCanvasImpl(canvas, executor, profile)

open fun sharedNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile, flipY: Boolean, msaa: Int, async: Boolean) =
if(async) AsyncSharedCanvasImpl(canvas, executor, profile, flipY, msaa)
else SharedCanvasImpl(canvas, executor, profile, flipY, msaa)
open fun sharedNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile) =
if(canvas.async) AsyncSharedCanvasImpl(canvas, executor, profile)
else SharedCanvasImpl(canvas, executor, profile)

open fun interopNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile, flipY: Boolean, msaa: Int, async: Boolean) =
if(async) AsyncNVDXInteropCanvasImpl(canvas, executor, profile, flipY, msaa)
else NVDXInteropCanvasImpl(canvas, executor, profile, flipY, msaa)
open fun interopNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile) =
if(canvas.async) AsyncNVDXInteropCanvasImpl(canvas, executor, profile)
else NVDXInteropCanvasImpl(canvas, executor, profile)

open fun ioSurfaceNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile, flipY: Boolean, msaa: Int, async: Boolean) =
if(async) AsyncIOSurfaceCanvasImpl(canvas, executor, profile, flipY, msaa)
else IOSurfaceCanvasImpl(canvas, executor, profile, flipY, msaa)
open fun ioSurfaceNGCanvas(canvas: GLCanvas, executor: GLExecutor, profile: GLProfile) =
if(canvas.async) AsyncIOSurfaceCanvasImpl(canvas, executor, profile)
else IOSurfaceCanvasImpl(canvas, executor, profile)

open fun createRenderEvent(canvas: GLCanvas, currentFps: Int, delta: Double, width: Int, height: Int, fbo: Int)
= GLRenderEvent(GLRenderEvent.ANY, currentFps, delta, width, height, fbo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ enum class GLProfile {
open class GLCanvas @JvmOverloads constructor(
val executor: GLExecutor,
val profile: GLProfile = GLProfile.Compatibility,
val flipY: Boolean = false,
val msaa: Int = 0,
val fxaa: Boolean = false,
var flipY: Boolean = false,
var msaa: Int = 0,
var fxaa: Boolean = false,
val async: Boolean = false,
val interopType: GLInteropType = GLInteropType.supported
): Pane() {
Expand Down Expand Up @@ -226,7 +226,7 @@ open class GLCanvas @JvmOverloads constructor(
TextureSharing -> executor::sharedNGCanvas
NVDXInterop -> executor::interopNGCanvas
Blit -> executor::blitNGCanvas
}(this, executor, profile, flipY, msaa, async)
}(this, executor, profile)

/**
* Destroys all resources to free up memory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ package com.huskerdev.openglfx.internal
import com.huskerdev.openglfx.GLExecutor
import com.huskerdev.openglfx.canvas.GLCanvas
import com.huskerdev.openglfx.canvas.GLProfile
import com.sun.javafx.geom.BaseBounds
import com.sun.javafx.scene.DirtyBits
import com.sun.javafx.scene.NodeHelper
import com.sun.javafx.sg.prism.NGNode
import com.sun.javafx.sg.prism.NGRegion
import com.sun.prism.Graphics
import com.sun.prism.Texture
import javafx.animation.AnimationTimer
import javafx.application.Platform
import kotlin.math.max

abstract class NGGLCanvas(
val canvas: GLCanvas,
val executor: GLExecutor,
val profile: GLProfile,
val flipY: Boolean,
val msaa: Int
val profile: GLProfile
): NGRegion(
) {

@Volatile var disposed = false
private set

Expand All @@ -28,7 +28,12 @@ abstract class NGGLCanvas(
val scaledWidth by canvas::scaledWidth
val scaledHeight by canvas::scaledHeight
internal val scaledSize: Size
get() = Size(scaledWidth, scaledHeight)
get() = Size(max(1, scaledWidth), max(1, scaledHeight))

val flipY by canvas::flipY
val async by canvas::async
val msaa by canvas::msaa
val fxaa by canvas::fxaa

private val animationTimer = object : AnimationTimer() {
override fun handle(now: Long) {
Expand All @@ -37,9 +42,7 @@ abstract class NGGLCanvas(
}.apply { start() }

init {
canvas.visibleProperty().addListener { _, _, _ -> repaint() }
canvas.widthProperty().addListener { _, _, _ -> repaint() }
canvas.heightProperty().addListener { _, _, _ -> repaint() }
Platform.runLater(::repaint)
}

protected abstract fun timerTick()
Expand All @@ -51,15 +54,30 @@ abstract class NGGLCanvas(
canvas.fireSceneBoundEvent()
}

override fun setTransformedBounds(bounds: BaseBounds?, byTransformChangeOnly: Boolean) {
super.setTransformedBounds(bounds, byTransformChangeOnly)
repaint()
}

override fun setVisible(value: Boolean) {
super.setVisible(value)
repaint()
}

protected fun dirty(){
NodeHelper.markDirty(canvas, DirtyBits.NODE_BOUNDS)
NodeHelper.markDirty(canvas, DirtyBits.REGION_SHAPE)
}

protected fun drawResultTexture(g: Graphics, texture: Texture){
if(disposed) return
if(flipY) g.drawTexture(texture, 0f, 0f, width.toFloat() + 0.5f, height.toFloat() + 0.5f, 0f, 0f, scaledWidth.toFloat(), scaledHeight.toFloat())
else g.drawTexture(texture, 0f, 0f, width.toFloat() + 0.5f, height.toFloat() + 0.5f, 0f, scaledHeight.toFloat(), scaledWidth.toFloat(), 0f)
val drawWidth = (texture.physicalWidth / canvas.dpi).toFloat()
val drawHeight = (texture.physicalHeight / canvas.dpi).toFloat()
val sourceWidth = texture.physicalWidth.toFloat()
val sourceHeight = texture.physicalHeight.toFloat()

if(flipY) g.drawTexture(texture, 0f, 0f, drawWidth, drawHeight, 0f, 0f, sourceWidth, sourceHeight)
else g.drawTexture(texture, 0f, 0f, drawWidth, drawHeight, 0f, sourceHeight, sourceWidth, 0f)
}

open fun dispose(){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package com.huskerdev.openglfx.internal

import kotlin.math.max

internal data class Size(
var width: Int = Integer.MIN_VALUE,
var height: Int = Integer.MIN_VALUE,
val minWidth: Int = Integer.MIN_VALUE,
val minHeight: Int = Integer.MIN_VALUE
var height: Int = Integer.MIN_VALUE
) {

inline fun executeOnDifferenceWith(newWidth: Int, newHeight: Int, consumer: (sizeWidth: Int, sizeHeight: Int) -> Unit){
if(width != newWidth || height != newHeight){
width = max(newWidth, minWidth)
height = max(newHeight, minHeight)
width = newWidth
height = newHeight
consumer(width, height)
}
}
Expand All @@ -22,10 +19,15 @@ internal data class Size(

fun executeOnDifferenceWith(size: Size, vararg consumers: (sizeWidth: Int, sizeHeight: Int) -> Unit) {
if(width != size.width || height != size.height){
width = max(size.width, minWidth)
height = max(size.height, minHeight)
width = size.width
height = size.height
consumers.forEach { it(width, height) }
}
}

fun copyTo(target: Size){
target.width = width
target.height = height
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ import java.util.concurrent.atomic.AtomicBoolean
open class BlitCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa){
profile: GLProfile
): NGGLCanvas(canvas, executor, profile){

private var needsRepaint = AtomicBoolean(false)

private var resultSize = Size(minWidth = 1, minHeight = 1)
private var resultSize = Size()

private lateinit var fbo: Framebuffer
private lateinit var msaaFBO: MultiSampledFramebuffer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ import java.util.concurrent.atomic.AtomicBoolean
open class IOSurfaceCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa) {
profile: GLProfile
): NGGLCanvas(canvas, executor, profile) {

private lateinit var ioSurface: IOSurface
private lateinit var fxTexture: Texture

private val lastSize = Size(minWidth = 1, minHeight = 1)
private val lastSize = Size()

private lateinit var fboFX: Framebuffer
private lateinit var sharedFboFX: Framebuffer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ import java.util.concurrent.atomic.AtomicBoolean
open class NVDXInteropCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa){
profile: GLProfile
): NGGLCanvas(canvas, executor, profile){

private var lastSize = Size(minWidth = 1, minHeight = 1)
private var lastSize = Size()

private var needsRepaint = AtomicBoolean(false)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ import java.util.concurrent.atomic.AtomicBoolean
open class SharedCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa){
profile: GLProfile
): NGGLCanvas(canvas, executor, profile){

private var lastSize = Size(minWidth = 1, minHeight = 1)
private var lastSize = Size()

private lateinit var context: GLContext
private lateinit var fxContext: GLContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ import kotlin.concurrent.thread
open class AsyncBlitCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa){
profile: GLProfile
): NGGLCanvas(canvas, executor, profile){

private val paintLock = Object()
private val blitLock = Object()

private var needsBlit = AtomicBoolean(false)

private var drawSize = Size(minWidth = 1, minHeight = 1)
private var drawSize = Size()
private var transferSize = Size()
private var resultSize = Size()

Expand All @@ -44,21 +42,20 @@ open class AsyncBlitCanvasImpl(
private lateinit var resultFBO: Framebuffer

private lateinit var context: GLContext
private lateinit var contextWrapper: GLContext
private lateinit var resultContext: GLContext

private lateinit var dataBuffer: ByteBuffer
private lateinit var texture: Texture

private lateinit var passthroughShader: PassthroughShader
private val passthroughShader by lazy { PassthroughShader() }
private val fxaaShader by lazy { FXAAShader() }

private fun initializeThread(){
context = GLContext.create(0L, profile == GLProfile.Core)
contextWrapper = GLContext.create(context, profile == GLProfile.Core)
resultContext = GLContext.create(context, profile == GLProfile.Core)

resultContext.makeCurrent()
GLExecutor.loadBasicFunctionPointers()
passthroughShader = if(canvas.fxaa) FXAAShader() else PassthroughShader()

thread(isDaemon = true) {
context.makeCurrent()
executor.initGLFunctions()
Expand Down Expand Up @@ -113,8 +110,7 @@ open class AsyncBlitCanvasImpl(
resizeResultTexture(width, height)
glViewport(0, 0, width, height)
}

passthroughShader.apply(transferFBO, resultFBO)
(if(fxaa) fxaaShader else passthroughShader).apply(transferFBO, resultFBO)
resultFBO.readPixels(0, 0, resultSize.width, resultSize.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dataBuffer)
texture.updateData(dataBuffer, resultSize.width, resultSize.height)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@ import kotlin.concurrent.thread
open class AsyncIOSurfaceCanvasImpl(
canvas: GLCanvas,
executor: GLExecutor,
profile: GLProfile,
flipY: Boolean,
msaa: Int
): NGGLCanvas(canvas, executor, profile, flipY, msaa) {
profile: GLProfile
): NGGLCanvas(canvas, executor, profile) {

private val paintLock = Object()
private val blitLock = Object()

private var drawSize = Size(minWidth = 1, minHeight = 1)
private var drawSize = Size()
private var interopTextureSize = Size()
private var resultSize = Size()

Expand All @@ -52,6 +50,7 @@ open class AsyncIOSurfaceCanvasImpl(

private var needsBlit = AtomicBoolean(false)

private lateinit var filteredFBO: Framebuffer
private lateinit var filterShader: PassthroughShader

private fun initializeThread(){
Expand All @@ -69,9 +68,7 @@ open class AsyncIOSurfaceCanvasImpl(
paint()
synchronized(blitLock) {
interopTextureSize.executeOnDifferenceWith(drawSize, ::updateSurfaceSize)
if(canvas.fxaa)
filterShader.apply(fboGL, sharedFboGL)
else fboGL.blitTo(sharedFboGL)
fboGL.blitTo(sharedFboGL)
}
needsBlit.set(true)

Expand Down
Loading

0 comments on commit 6f42684

Please sign in to comment.