Skip to content

Commit

Permalink
improved control over clear behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
fabmax committed Feb 2, 2025
1 parent 2ec4afc commit e1a8c48
Show file tree
Hide file tree
Showing 36 changed files with 161 additions and 131 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package de.fabmax.kool

import de.fabmax.kool.modules.ui2.setupUiScene
import de.fabmax.kool.pipeline.ClearColor
import de.fabmax.kool.pipeline.ClearColorLoad
import de.fabmax.kool.scene.Scene
import de.fabmax.kool.util.Color
import de.fabmax.kool.util.launchDelayed

class KoolApplication(val ctx: KoolContext)
Expand All @@ -27,7 +28,7 @@ inline fun KoolApplication.addScene(name: String = "content-scene", block: Scene
* The provided [block] can be used to set up the scene and add content to it.
*/
inline fun KoolApplication.addUiScene(
clearColor: Color? = null,
clearColor: ClearColor = ClearColorLoad,
name: String = "ui-scene",
block: Scene.() -> Unit
): Scene = addScene(name) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package de.fabmax.kool.modules.ui2

import de.fabmax.kool.pipeline.ClearColor
import de.fabmax.kool.pipeline.ClearColorLoad
import de.fabmax.kool.scene.OrthographicCamera
import de.fabmax.kool.scene.Scene
import de.fabmax.kool.util.Color

/**
* Creates a new scene and sets it up as a UI scene.
Expand All @@ -11,7 +12,7 @@ import de.fabmax.kool.util.Color
*/
fun UiScene(
name: String = "UiScene",
clearColor: Color? = null,
clearColor: ClearColor = ClearColorLoad,
block: Scene.() -> Unit
) = Scene(name).apply {
setupUiScene(clearColor)
Expand All @@ -23,7 +24,7 @@ fun UiScene(
* clip size to the viewport size. Also, by default, screen-clearing is disabled, because UIs usually are drawn on
* top of stuff, which should not be cleared away.
*/
fun Scene.setupUiScene(clearColor: Color? = null) {
fun Scene.setupUiScene(clearColor: ClearColor = ClearColorLoad) {
this.clearColor = clearColor

camera = OrthographicCamera()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import de.fabmax.kool.pipeline.shading.DepthShader
import de.fabmax.kool.scene.Mesh
import de.fabmax.kool.scene.Node
import de.fabmax.kool.scene.NodeId
import de.fabmax.kool.util.Color
import de.fabmax.kool.util.UniqueId


Expand Down Expand Up @@ -105,9 +104,6 @@ class NormalLinearDepthMapPass(

init {
mirrorIfInvertedClipY()
onAfterCollectDrawCommands += {
clearColor = Color.GREEN
}
}

override fun getDepthPipeline(mesh: Mesh, ctx: KoolContext): DrawPipeline? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ abstract class OffscreenPass(
val numColorAttachments: Int
get() = if (colorAttachments is ColorAttachmentTextures) colorAttachments.attachments.size else 1

override val clearColors: Array<Color?> = Array(numColorAttachments) { Color.BLACK }
override val clearColors = MutableList<ClearColor>(numColorAttachments) { ClearColorFill(Color.BLACK) }
override var clearDepth: ClearDepth = ClearDepthFill

fun createColorTextureProps(attachment: Int = 0): TextureProps {
check(colorAttachments is ColorAttachmentTextures)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ abstract class RenderPass(name: String, val mipMode: MipMode) : GpuPass(name) {
val numTextureMipLevels: Int get() = mipMode.getTextureMipLevels(size)
val numRenderMipLevels: Int get() = mipMode.getRenderMipLevels(size)

abstract val clearColors: Array<Color?>
var clearColor: Color?
get() = clearColors.getOrNull(0)
set(value) { clearColors[0] = value }
var clearDepth = true
abstract val clearColors: List<ClearColor>
abstract val clearDepth: ClearDepth

abstract val views: List<View>

Expand Down Expand Up @@ -218,3 +215,13 @@ abstract class RenderPass(name: String, val mipMode: MipMode) : GpuPass(name) {
}
}
}

sealed interface ClearColor
data object ClearColorLoad : ClearColor
data object ClearColorDontCare : ClearColor
data class ClearColorFill(val clearColor: Color) : ClearColor

sealed interface ClearDepth
data object ClearDepthLoad : ClearDepth
data object ClearDepthDontCare : ClearDepth
data object ClearDepthFill : ClearDepth
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,14 @@ abstract class GlRenderPass(val backend: RenderBackendGl): BaseReleasable() {

fun clear(renderPass: RenderPass) {
for (i in renderPass.clearColors.indices) {
renderPass.clearColors[i]?.let { color ->
val clearMode = renderPass.clearColors[i]
if (clearMode is ClearColorFill) {
colorBufferClearVal.clear()
color.putTo(colorBufferClearVal)
clearMode.clearColor.putTo(colorBufferClearVal)
gl.clearBufferfv(gl.COLOR, i, colorBufferClearVal)
}
}
if (renderPass.clearDepth) {
if (renderPass.clearDepth == ClearDepthFill) {
GlState.setWriteDepth(true, gl)
gl.clearDepth(if (renderPass.isReverseDepth) 0f else 1f)
gl.clear(gl.DEPTH_BUFFER_BIT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import de.fabmax.kool.pipeline.shading.BlurShader
import de.fabmax.kool.pipeline.shading.BlurShaderConfig
import de.fabmax.kool.scene.Node
import de.fabmax.kool.scene.addMesh
import de.fabmax.kool.util.Color
import kotlin.math.sqrt

class BloomBlurPass(kernelSize: Int, thresholdPass: BloomThresholdPass) :
Expand Down Expand Up @@ -54,8 +53,6 @@ class BloomBlurPass(kernelSize: Int, thresholdPass: BloomThresholdPass) :

pingContent.fullScreenQuad(pingShader)
pongContent.fullScreenQuad(pongShader)
ping.clearColor = Color(0f, 0f, 0f, 0f)
pong.clearColor = Color(0f, 0f, 0f, 0f)

bloomStrength = 1f

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import de.fabmax.kool.pipeline.TexFormat
import de.fabmax.kool.scene.Mesh
import de.fabmax.kool.scene.Node
import de.fabmax.kool.scene.addMesh
import de.fabmax.kool.util.Color
import de.fabmax.kool.util.releaseWith

class BloomThresholdPass(deferredPipeline: DeferredPipeline, cfg: DeferredPipelineConfig) :
Expand All @@ -35,8 +34,6 @@ class BloomThresholdPass(deferredPipeline: DeferredPipeline, cfg: DeferredPipeli
private val quad: Mesh

init {
clearColor = Color.BLACK

drawNode.apply {
isFrustumChecked = false
quad = addMesh(Attribute.POSITIONS, Attribute.TEXTURE_COORDS) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package de.fabmax.kool.pipeline.deferred

import de.fabmax.kool.math.Vec2i
import de.fabmax.kool.pipeline.OffscreenPass2d
import de.fabmax.kool.pipeline.SamplerSettings
import de.fabmax.kool.pipeline.TexFormat
import de.fabmax.kool.pipeline.Texture2d
import de.fabmax.kool.pipeline.*
import de.fabmax.kool.scene.Mesh
import de.fabmax.kool.scene.PerspectiveCamera
import de.fabmax.kool.scene.PerspectiveProxyCam
Expand Down Expand Up @@ -55,10 +52,10 @@ class MaterialPass(pipeline: DeferredPipeline, suffix: String) :

// encoded position is in view space -> z value of valid position is always negative, use a positive z value
// in clear color to encode clear areas
clearColors[0] = Color(0f, 0f, 1f, 0f)
clearColors[1] = Color(0f, 0f, 0f, 0f)
clearColors[2] = Color(0f, 0f, 0f, 0f)
clearColors[3] = Color(0f, 0f, 0f, 0f)
clearColors[0] = ClearColorFill(Color(0f, 0f, 1f, 0f))
clearColors[1] = ClearColorFill(Color(0f, 0f, 0f, 0f))
clearColors[2] = ClearColorFill(Color(0f, 0f, 0f, 0f))
clearColors[3] = ClearColorFill(Color(0f, 0f, 0f, 0f))
}

override fun afterCollectDrawCommands(updateEvent: UpdateEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package de.fabmax.kool.pipeline.deferred

import de.fabmax.kool.pipeline.OffscreenPass2d
import de.fabmax.kool.pipeline.TexFormat
import de.fabmax.kool.util.Color

class PbrLightingPass(pipeline: DeferredPipeline, suffix: String, val materialPass: MaterialPass) :
OffscreenPass2d(
Expand All @@ -17,7 +16,6 @@ class PbrLightingPass(pipeline: DeferredPipeline, suffix: String, val materialPa
mirrorIfInvertedClipY()
val scene = pipeline.scene
lighting = scene.lighting
clearColor = Color(0f, 0f, 0f, 0f)
camera = materialPass.camera
isUpdateDrawNode = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import de.fabmax.kool.pipeline.FullscreenShaderUtil.fullscreenQuadVertexStage
import de.fabmax.kool.pipeline.FullscreenShaderUtil.generateFullscreenQuad
import de.fabmax.kool.scene.Node
import de.fabmax.kool.scene.addMesh
import de.fabmax.kool.util.Color

class ReflectionDenoisePass(reflectionPass: OffscreenPass2d) :
OffscreenPass2d(
Expand All @@ -23,8 +22,6 @@ class ReflectionDenoisePass(reflectionPass: OffscreenPass2d) :
private lateinit var denoiseShader: DenoiseShader

init {
clearColor = Color(0f, 0f, 0f, 0f)

drawNode.apply {
addMesh(Attribute.POSITIONS, Attribute.TEXTURE_COORDS) {
generateFullscreenQuad()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import de.fabmax.kool.pipeline.FullscreenShaderUtil.fullscreenQuadVertexStage
import de.fabmax.kool.pipeline.FullscreenShaderUtil.generateFullscreenQuad
import de.fabmax.kool.scene.Node
import de.fabmax.kool.scene.addMesh
import de.fabmax.kool.util.Color
import de.fabmax.kool.util.Uint8Buffer
import de.fabmax.kool.util.releaseWith
import kotlin.random.Random
Expand All @@ -32,8 +31,6 @@ class ReflectionPass(val baseReflectionStep: Float) :
var scrSpcReflectionIterations by ssrShader::maxIterations

init {
clearColor = Color(0f, 0f, 0f, 0f)

drawNode.apply {
addMesh(Attribute.POSITIONS, Attribute.TEXTURE_COORDS) {
generateFullscreenQuad()
Expand Down
24 changes: 11 additions & 13 deletions kool-core/src/commonMain/kotlin/de/fabmax/kool/scene/Scene.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import de.fabmax.kool.math.MutableVec3i
import de.fabmax.kool.math.RayD
import de.fabmax.kool.math.RayF
import de.fabmax.kool.math.Vec3i
import de.fabmax.kool.pipeline.ComputePass
import de.fabmax.kool.pipeline.GpuPass
import de.fabmax.kool.pipeline.OffscreenPass
import de.fabmax.kool.pipeline.RenderPass
import de.fabmax.kool.pipeline.*
import de.fabmax.kool.pipeline.backend.DepthRange
import de.fabmax.kool.util.*
import kotlin.time.Duration.Companion.seconds
Expand All @@ -30,10 +27,10 @@ open class Scene(name: String? = null) : Node(name) {
val lighting = Lighting()
val mainRenderPass: ScreenPass = ScreenPass()

var clearColor: Color?
var clearColor: ClearColor
get() = mainRenderPass.clearColor
set(value) { mainRenderPass.clearColor = value }
var clearDepth: Boolean
var clearDepth: ClearDepth
get() = mainRenderPass.clearDepth
set(value) { mainRenderPass.clearDepth = value }

Expand Down Expand Up @@ -146,20 +143,21 @@ open class Scene(name: String? = null) : Node(name) {
val DEFAULT_CLEAR_COLOR = Color(0.15f, 0.15f, 0.15f, 1f)
}

enum class FramebufferCaptureMode {
Disabled,
BeforeRender,
AfterRender
}

inner class ScreenPass : RenderPass("${name}:ScreenPass", MipMode.None) {
val screenView = View("screen", this@Scene, PerspectiveCamera())
var camera: Camera by screenView::camera
val viewport: Viewport by screenView::viewport
var useWindowViewport = true

override val numSamples: Int get() = KoolSystem.config.numSamples
override val clearColors: Array<Color?> = arrayOf(DEFAULT_CLEAR_COLOR)

private val _clearColors = mutableListOf<ClearColor>(ClearColorFill(DEFAULT_CLEAR_COLOR))
override val clearColors: List<ClearColor> get() = _clearColors
override var clearDepth: ClearDepth = ClearDepthFill

var clearColor: ClearColor
get() = clearColors[0]
set(value) { _clearColors.set(0, value) }

private val _views = mutableListOf(screenView)
override val views: List<View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class ClearHelper(val backend: RenderBackendVk) {

fun clear(passEncoderState: PassEncoderState) {
val rp = passEncoderState.renderPass
val clearColor = rp.clearColor
val clearColor = (rp.clearColors[0] as? ClearColorFill)?.clearColor
val clearDepth = if (rp.isReverseDepth) 0f else 1f

if (clearColor != prevColor || clearDepth != prevDepth) {
Expand All @@ -98,7 +98,7 @@ class ClearHelper(val backend: RenderBackendVk) {

val clearPipeline = when {
clearColor == null -> clearDepthOnly
!rp.clearDepth -> clearColorOnly
rp.clearDepth != ClearDepthFill -> clearColorOnly
else -> clearColorAndDepth
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package de.fabmax.kool.pipeline.backend.vk
import de.fabmax.kool.pipeline.*
import de.fabmax.kool.util.logT
import org.lwjgl.vulkan.KHRDynamicRendering.vkCmdBeginRenderingKHR
import org.lwjgl.vulkan.VK10.*
import org.lwjgl.vulkan.VK10.VK_ATTACHMENT_STORE_OP_STORE

class OffscreenPass2dVk(
val parentPass: OffscreenPass2d,
Expand Down Expand Up @@ -78,25 +78,28 @@ class OffscreenPass2dVk(
}

override fun beginRenderPass(passEncoderState: PassEncoderState, forceLoad: Boolean) {
val isLoadColor = forceLoad || parentPass.clearColor == null
val isLoadDepth = forceLoad || !parentPass.clearDepth

val mipLevel = passEncoderState.mipLevel
val width = (parentPass.width shr mipLevel).coerceAtLeast(1)
val height = (parentPass.height shr mipLevel).coerceAtLeast(1)
val colorLoadOp = if (isLoadColor) VK_ATTACHMENT_LOAD_OP_LOAD else VK_ATTACHMENT_LOAD_OP_CLEAR
val depthLoadOp = if (isLoadDepth) VK_ATTACHMENT_LOAD_OP_LOAD else VK_ATTACHMENT_LOAD_OP_CLEAR

val isLoadDepth = forceLoad || parentPass.clearDepth == ClearDepthLoad
var isLoadColor = forceLoad
for (i in parentPass.clearColors.indices) {
if (parentPass.clearColors[i] == ClearColorLoad) {
isLoadColor = true
}
}

attachments.transitionToAttachmentLayout(isLoadColor, isLoadDepth, passEncoderState)
val renderingInfo = setupRenderingInfo(
width = width,
height = height,
forceLoad = forceLoad,
colorImageViews = attachments.getColorViews(mipLevel),
colorLoadOp = colorLoadOp,
colorClearModes = parentPass.clearColors,
colorStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
clearColors = parentPass.clearColors.mapNotNull { it },
depthImageView = attachments.getDepthView(mipLevel),
depthLoadOp = depthLoadOp,
depthClearMode = parentPass.clearDepth,
isReverseDepth = parentPass.isReverseDepth,
)
vkCmdBeginRenderingKHR(passEncoderState.commandBuffer, renderingInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package de.fabmax.kool.pipeline.backend.vk
import de.fabmax.kool.pipeline.*
import de.fabmax.kool.util.logT
import org.lwjgl.vulkan.KHRDynamicRendering.vkCmdBeginRenderingKHR
import org.lwjgl.vulkan.VK10.*
import org.lwjgl.vulkan.VK10.VK_ATTACHMENT_STORE_OP_STORE

class OffscreenPassCubeVk(
val parentPass: OffscreenPassCube,
Expand Down Expand Up @@ -74,26 +74,29 @@ class OffscreenPassCubeVk(
}

override fun beginRenderPass(passEncoderState: PassEncoderState, forceLoad: Boolean) {
val isLoadColor = forceLoad || parentPass.clearColor == null
val isLoadDepth = forceLoad || !parentPass.clearDepth

val mipLevel = passEncoderState.mipLevel
val layer = passEncoderState.layer
val width = (parentPass.width shr mipLevel).coerceAtLeast(1)
val height = (parentPass.height shr mipLevel).coerceAtLeast(1)
val colorLoadOp = if (isLoadColor) VK_ATTACHMENT_LOAD_OP_LOAD else VK_ATTACHMENT_LOAD_OP_CLEAR
val depthLoadOp = if (isLoadDepth) VK_ATTACHMENT_LOAD_OP_LOAD else VK_ATTACHMENT_LOAD_OP_CLEAR

val isLoadDepth = forceLoad || parentPass.clearDepth == ClearDepthLoad
var isLoadColor = forceLoad
for (i in parentPass.clearColors.indices) {
if (parentPass.clearColors[i] == ClearColorLoad) {
isLoadColor = true
}
}

attachments.transitionToAttachmentLayout(isLoadColor, isLoadDepth, passEncoderState)
val renderingInfo = setupRenderingInfo(
width = width,
height = height,
forceLoad = forceLoad,
colorImageViews = attachments.getColorViews(mipLevel, layer),
colorLoadOp = colorLoadOp,
colorClearModes = parentPass.clearColors,
colorStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
clearColors = parentPass.clearColors.mapNotNull { it },
depthImageView = attachments.getDepthView(mipLevel, layer),
depthLoadOp = depthLoadOp,
depthClearMode = parentPass.clearDepth,
isReverseDepth = parentPass.isReverseDepth,
)
vkCmdBeginRenderingKHR(passEncoderState.commandBuffer, renderingInfo)
Expand Down
Loading

0 comments on commit e1a8c48

Please sign in to comment.