Skip to content

Commit 22a0ccf

Browse files
committed
Couple of minor vulkan backend fixes
1 parent 7ad3446 commit 22a0ccf

10 files changed

Lines changed: 95 additions & 42 deletions

File tree

kool-backend-wgpu4k/src/commonMain/kotlin/de/fabmax/kool/pipeline/backend/wgpu/WgpuTextureLoader.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@ internal class WgpuTextureLoader(val backend: GPUBackend) {
2525

2626
var loaded = loadedTextures[data.id]
2727
if (loaded != null && loaded.isReleased) { loadedTextures -= data.id }
28-
29-
loaded = when {
30-
tex is Texture1d && data is ImageData1d -> loadTexture1d(tex, data)
31-
tex is Texture2d && data is ImageData2d -> loadTexture2d(tex, data)
32-
tex is Texture3d && data is ImageData3d -> loadTexture3d(tex, data)
33-
tex is TextureCube && data is ImageDataCube -> loadTextureCube(tex, data)
34-
tex is Texture2dArray && data is ImageData3d -> loadTexture2dArray(tex, data)
35-
tex is TextureCubeArray && data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
36-
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
28+
loaded = loadedTextures.getOrPut(data.id) {
29+
when (tex) {
30+
is Texture1d if data is ImageData1d -> loadTexture1d(tex, data)
31+
is Texture2d if data is ImageData2d -> loadTexture2d(tex, data)
32+
is Texture3d if data is ImageData3d -> loadTexture3d(tex, data)
33+
is TextureCube if data is ImageDataCube -> loadTextureCube(tex, data)
34+
is Texture2dArray if data is ImageData3d -> loadTexture2dArray(tex, data)
35+
is TextureCubeArray if data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
36+
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
37+
}
38+
}
39+
if (loaded !== tex.gpuTexture) {
40+
tex.gpuTexture?.release()
41+
tex.gpuTexture = loaded
3742
}
38-
tex.gpuTexture?.release()
39-
tex.gpuTexture = loaded
4043
}
4144

4245
private fun loadTexture1d(tex: Texture1d, data: ImageData1d): WgpuTextureResource {

kool-core/src/commonMain/kotlin/de/fabmax/kool/pipeline/backend/gl/TextureLoaderGl.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ object TextureLoaderGl {
2222
var loaded = loadedTextures[data.id]
2323
if (loaded != null && loaded.isReleased) { loadedTextures -= data.id }
2424
loaded = loadedTextures.getOrPut(data.id) {
25-
when {
26-
tex is Texture1d && data is ImageData1d -> loadTexture1dCompat(tex, data, backend)
27-
tex is Texture2d && data is ImageData2d -> loadTexture2d(tex, data, backend)
28-
tex is Texture3d && data is ImageData3d -> loadTexture3d(tex, data, backend)
29-
tex is TextureCube && data is ImageDataCube -> loadTextureCube(tex, data, backend)
30-
tex is Texture2dArray && data is ImageData3d -> loadTexture2dArray(tex, data, backend)
31-
tex is TextureCubeArray && data is ImageDataCubeArray -> loadTextureCubeArray(tex, data, backend)
25+
when (tex) {
26+
is Texture1d if data is ImageData1d -> loadTexture1dCompat(tex, data, backend)
27+
is Texture2d if data is ImageData2d -> loadTexture2d(tex, data, backend)
28+
is Texture3d if data is ImageData3d -> loadTexture3d(tex, data, backend)
29+
is TextureCube if data is ImageDataCube -> loadTextureCube(tex, data, backend)
30+
is Texture2dArray if data is ImageData3d -> loadTexture2dArray(tex, data, backend)
31+
is TextureCubeArray if data is ImageDataCubeArray -> loadTextureCubeArray(tex, data, backend)
3232
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
3333
}
3434
}

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/BindGroupDataVk.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class BindGroupDataVk(
9999
val ubo = bindGroup.uboBindings[i]
100100
if (ubo.isUpdate(frameIdx, ubo.binding.modCount.count) || resetBindGroup) {
101101
ubo.binding.buffer.buffer.useRaw { raw -> ubo.mappedBuffers[frameIdx].put(raw).flip() }
102+
backend.memManager.flushBuffer(ubo.buffers[frameIdx].vkBuffer)
102103
}
103104
}
104105
}
@@ -431,6 +432,7 @@ class BindGroupDataVk(
431432
is Float32Buffer -> upload.useRaw { stagingBuf.mapped!!.asFloatBuffer().put(it) }
432433
is MixedBuffer -> upload.useRaw { stagingBuf.mapped!!.put(it) }
433434
}
435+
backend.memManager.flushBuffer(stagingBuf)
434436
gpuBuffer.copyFrom(stagingBuf, passEncoderState.commandBuffer)
435437
}
436438
}
@@ -475,6 +477,7 @@ class BindGroupDataVk(
475477
)
476478
if (buffer.uploadData == null) {
477479
vkCmdFillBuffer(commandBuffer, gpuBuffer.vkBuffer.handle, 0L, VK_WHOLE_SIZE, 0)
480+
bufferTransferWriteBarrier(commandBuffer)
478481
}
479482
buffer.gpuBuffer = gpuBuffer
480483
}

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/GpuBufferVk.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package de.fabmax.kool.pipeline.backend.vk
33
import de.fabmax.kool.pipeline.GpuBufferImpl
44
import de.fabmax.kool.pipeline.backend.stats.BufferInfo
55
import de.fabmax.kool.util.*
6+
import org.lwjgl.vulkan.KHRSynchronization2.vkCmdPipelineBarrier2KHR
67
import org.lwjgl.vulkan.VK10.vkCmdCopyBuffer
8+
import org.lwjgl.vulkan.VK13.*
79
import org.lwjgl.vulkan.VkBufferCopy
810
import org.lwjgl.vulkan.VkCommandBuffer
11+
import org.lwjgl.vulkan.VkMemoryBarrier2
912

1013
class GpuBufferVk(
1114
val backend: RenderBackendVk,
@@ -20,6 +23,7 @@ class GpuBufferVk(
2023
fun copyFrom(srcBuffer: VkBuffer, commandBuffer: VkCommandBuffer, size: Long = srcBuffer.bufferSize) {
2124
bufferCopy[0].set(0L, 0L, size)
2225
vkCmdCopyBuffer(commandBuffer, srcBuffer.handle, vkBuffer.handle, bufferCopy)
26+
bufferTransferWriteBarrier(commandBuffer)
2327
}
2428

2529
override fun doRelease() {
@@ -32,6 +36,19 @@ class GpuBufferVk(
3236
}
3337
}
3438

39+
internal fun bufferTransferWriteBarrier(commandBuffer: VkCommandBuffer) = scopedMem {
40+
val dependency = callocVkDependencyInfo {
41+
val barrier = VkMemoryBarrier2.calloc(1, this@scopedMem)
42+
barrier[0].`sType$Default`()
43+
barrier[0].srcAccessMask(VK_ACCESS_2_TRANSFER_WRITE_BIT)
44+
barrier[0].srcStageMask(VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT)
45+
barrier[0].dstAccessMask(VK_ACCESS_2_MEMORY_READ_BIT or VK_ACCESS_2_MEMORY_WRITE_BIT)
46+
barrier[0].dstStageMask(VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
47+
pMemoryBarriers(barrier)
48+
}
49+
vkCmdPipelineBarrier2KHR(commandBuffer, dependency)
50+
}
51+
3552
class GrowingBufferVk(
3653
val backend: RenderBackendVk,
3754
bufferInfo: MemoryInfo
@@ -49,6 +66,7 @@ class GrowingBufferVk(
4966
checkSize(bufSize)
5067
backend.memManager.stagingBuffer(bufSize) { stagingBuf ->
5168
data.useRaw { stagingBuf.mapped!!.asFloatBuffer().put(it) }
69+
backend.memManager.flushBuffer(stagingBuf)
5270
buffer.copyFrom(stagingBuf, commandBuffer)
5371
}
5472
}
@@ -60,6 +78,7 @@ class GrowingBufferVk(
6078
checkSize(bufSize)
6179
backend.memManager.stagingBuffer(bufSize) { stagingBuf ->
6280
data.useRaw { stagingBuf.mapped!!.asIntBuffer().put(it) }
81+
backend.memManager.flushBuffer(stagingBuf)
6382
buffer.copyFrom(stagingBuf, commandBuffer)
6483
}
6584
}
@@ -71,6 +90,7 @@ class GrowingBufferVk(
7190
checkSize(bufSize)
7291
backend.memManager.stagingBuffer(bufSize) { stagingBuf ->
7392
data.useRaw { stagingBuf.mapped!!.put(it) }
93+
backend.memManager.flushBuffer(stagingBuf)
7494
buffer.copyFrom(stagingBuf, commandBuffer)
7595
}
7696
}

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/ImageVk.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class ImageVk(
119119
scopedMem(stack) {
120120
val prevLayout = lastKnownLayout
121121
transitionLayout(
122-
VK_IMAGE_LAYOUT_UNDEFINED,
122+
prevLayout,
123123
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
124124
commandBuffer,
125125
stack = this

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/MemoryManager.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ class MemoryManager(val backend: RenderBackendVk) : BaseReleasable() {
3535
impl.freeBuffer(deferTicks, buffer)
3636
}
3737

38+
fun flushBuffer(buffer: VkBuffer, offset: Long = 0L, size: Long = VK_WHOLE_SIZE) {
39+
impl.flushAllocation(buffer.allocation, offset, size)
40+
}
41+
42+
fun invalidateBuffer(buffer: VkBuffer, offset: Long = 0L, size: Long = VK_WHOLE_SIZE) {
43+
impl.invalidateAllocation(buffer.allocation, offset, size)
44+
}
45+
3846
inline fun stagingBuffer(
3947
size: Long,
4048
usage: Int = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
@@ -107,6 +115,8 @@ class MemoryManager(val backend: RenderBackendVk) : BaseReleasable() {
107115
fun freeImage(deferTicks: Int, image: VkImage)
108116
fun mapMemory(allocation: Long): Long
109117
fun unmapMemory(allocation: Long)
118+
fun flushAllocation(allocation: Long, offset: Long, size: Long)
119+
fun invalidateAllocation(allocation: Long, offset: Long, size: Long)
110120
fun freeResources()
111121
}
112122

@@ -238,6 +248,14 @@ class MemoryManager(val backend: RenderBackendVk) : BaseReleasable() {
238248
vmaUnmapMemory(allocator, allocation)
239249
}
240250

251+
override fun flushAllocation(allocation: Long, offset: Long, size: Long) {
252+
vmaFlushAllocation(allocator, allocation, offset, size)
253+
}
254+
255+
override fun invalidateAllocation(allocation: Long, offset: Long, size: Long) {
256+
vmaInvalidateAllocation(allocator, allocation, offset, size)
257+
}
258+
241259
fun printMemoryStats() {
242260
scopedMem {
243261
val pp = mallocPointer(1)

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/PassEncoderState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class PassEncoderState(val backend: RenderBackendVk) {
5151
with(stack) {
5252
commandBuffer.end()
5353
backend.device.graphicsQueue.submit(backend.swapchain.inFlightFence, this) {
54-
pWaitDstStageMask(ints(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT))
54+
pWaitDstStageMask(ints(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT or VK_PIPELINE_STAGE_TRANSFER_BIT))
5555
pCommandBuffers(pointers(commandBuffer))
5656
pSignalSemaphores(longs(backend.swapchain.renderFinishedSema.handle))
5757
pWaitSemaphores(longs(backend.swapchain.imageAvailableSema.handle))

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/RenderBackendVk.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class RenderBackendVk(val ctx: Lwjgl3Context) : RenderBackendJvm {
303303
gpuReadbacks.filterIsInstance<ReadbackStorageBuffer>().filter { it.mapBuffer != null }.forEach { readback ->
304304
val mapBuffer = readback.mapBuffer!!
305305
val mapped = checkNotNull(mapBuffer.vkBuffer.mapped) { "readback buffer was not created mapped" }
306+
memManager.invalidateBuffer(mapBuffer.vkBuffer)
306307
readback.resultBuffer.copyFrom(mapped)
307308
mapBuffer.release()
308309
readback.deferred.complete(Unit)
@@ -311,6 +312,7 @@ class RenderBackendVk(val ctx: Lwjgl3Context) : RenderBackendJvm {
311312
gpuReadbacks.filterIsInstance<ReadbackTexture>().filter { it.mapBuffer != null }.forEach { readback ->
312313
val mapBuffer = readback.mapBuffer!!
313314
val mapped = checkNotNull(mapBuffer.vkBuffer.mapped) { "readback buffer was not created mapped" }
315+
memManager.invalidateBuffer(mapBuffer.vkBuffer)
314316
val gpuTex = readback.texture.gpuTexture as ImageVk
315317
val format = readback.texture.format
316318
val dst = ImageData.createBuffer(format, gpuTex.width, gpuTex.height, gpuTex.depth)

kool-core/src/desktopMain/kotlin/de/fabmax/kool/pipeline/backend/vk/TextureLoaderVk.kt

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,21 @@ class TextureLoaderVk(val backend: RenderBackendVk) {
2424

2525
var loaded = loadedTextures[data.id]
2626
if (loaded != null && loaded.isReleased) { loadedTextures -= data.id }
27-
28-
loaded = when {
29-
tex is Texture1d && data is ImageData1d -> loadTexture1d(tex, data)
30-
tex is Texture2d && data is ImageData2d -> loadTexture2d(tex, data)
31-
tex is Texture3d && data is ImageData3d -> loadTexture3d(tex, data)
32-
tex is TextureCube && data is ImageDataCube -> loadTextureCube(tex, data)
33-
tex is Texture2dArray && data is ImageData3d -> loadTexture2dArray(tex, data)
34-
tex is TextureCubeArray && data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
35-
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
27+
loaded = loadedTextures.getOrPut(data.id) {
28+
when (tex) {
29+
is Texture1d if data is ImageData1d -> loadTexture1d(tex, data)
30+
is Texture2d if data is ImageData2d -> loadTexture2d(tex, data)
31+
is Texture3d if data is ImageData3d -> loadTexture3d(tex, data)
32+
is TextureCube if data is ImageDataCube -> loadTextureCube(tex, data)
33+
is Texture2dArray if data is ImageData3d -> loadTexture2dArray(tex, data)
34+
is TextureCubeArray if data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
35+
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
36+
}
37+
}
38+
if (loaded !== tex.gpuTexture) {
39+
tex.gpuTexture?.release()
40+
tex.gpuTexture = loaded
3641
}
37-
tex.gpuTexture?.release()
38-
tex.gpuTexture = loaded
3942
}
4043

4144
private fun loadTexture1d(tex: Texture1d, data: ImageData1d): ImageVk = loadTexture(
@@ -134,6 +137,7 @@ class TextureLoaderVk(val backend: RenderBackendVk) {
134137
val bufSize = width * height * depth * layers * data.format.vkBytesPerPx.toLong()
135138
backend.memManager.stagingBuffer(bufSize, bufferDeleteTicks = 0) { stagingBuf ->
136139
copyTextureData(data, stagingBuf, data.format)
140+
backend.memManager.flushBuffer(stagingBuf)
137141

138142
backend.commandPool.singleShotCommands { commandBuffer ->
139143
val dstLayout = when {

kool-core/src/webMain/kotlin/de/fabmax/kool/pipeline/backend/webgpu/WgpuTextureLoader.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@ internal class WgpuTextureLoader(val backend: RenderBackendWebGpu) {
3434

3535
var loaded = loadedTextures[data.id]
3636
if (loaded != null && loaded.isReleased) { loadedTextures -= data.id }
37-
38-
loaded = when {
39-
tex is Texture1d && data is ImageData1d -> loadTexture1d(tex, data)
40-
tex is Texture2d && data is ImageData2d -> loadTexture2d(tex, data)
41-
tex is Texture3d && data is ImageData3d -> loadTexture3d(tex, data)
42-
tex is TextureCube && data is ImageDataCube -> loadTextureCube(tex, data)
43-
tex is Texture2dArray && data is ImageData3d -> loadTexture2dArray(tex, data)
44-
tex is TextureCubeArray && data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
45-
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
37+
loaded = loadedTextures.getOrPut(data.id) {
38+
when (tex) {
39+
is Texture1d if data is ImageData1d -> loadTexture1d(tex, data)
40+
is Texture2d if data is ImageData2d -> loadTexture2d(tex, data)
41+
is Texture3d if data is ImageData3d -> loadTexture3d(tex, data)
42+
is TextureCube if data is ImageDataCube -> loadTextureCube(tex, data)
43+
is Texture2dArray if data is ImageData3d -> loadTexture2dArray(tex, data)
44+
is TextureCubeArray if data is ImageDataCubeArray -> loadTextureCubeArray(tex, data)
45+
else -> error("Invalid texture / image data combination: ${tex::class.simpleName} / ${data::class.simpleName}")
46+
}
47+
}
48+
if (loaded !== tex.gpuTexture) {
49+
tex.gpuTexture?.release()
50+
tex.gpuTexture = loaded
4651
}
47-
tex.gpuTexture?.release()
48-
tex.gpuTexture = loaded
4952
}
5053

5154
private fun loadTexture1d(tex: Texture1d, data: ImageData1d): WgpuTextureResource {

0 commit comments

Comments
 (0)