Skip to content

Commit 341ea0e

Browse files
Merge pull request #123 from scenerygraphics/javafx-fixes
JavaFX fixes, with better materialType determination in OpenGLRenderer and more efficient JavaFX rendering.
2 parents 1e610d0 + b766db3 commit 341ea0e

File tree

8 files changed

+207
-97
lines changed

8 files changed

+207
-97
lines changed

pom.xml

+13-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113

114114
<slf4j.version>1.7.25</slf4j.version>
115115
<lwjgl.version>3.1.3</lwjgl.version>
116-
<spirvcrossj.version>0.3.0</spirvcrossj.version>
116+
<spirvcrossj.version>0.3.1</spirvcrossj.version>
117117
<jvrpn.version>1.1.0</jvrpn.version>
118118

119119
<license.licenseName>lgpl_v3</license.licenseName>
@@ -492,6 +492,18 @@
492492
<artifactId>scifio</artifactId>
493493
</dependency>
494494

495+
<dependency>
496+
<groupId>net.imagej</groupId>
497+
<artifactId>imagej</artifactId>
498+
<version>2.0.0-rc-59</version>
499+
<scope>test</scope>
500+
</dependency>
501+
502+
<dependency>
503+
<groupId>io.scif</groupId>
504+
<artifactId>scifio</artifactId>
505+
</dependency>
506+
495507
</dependencies>
496508

497509
<repositories>

src/main/kotlin/graphics/scenery/backends/opengl/OpenGLRenderer.kt

+81-53
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.jogamp.opengl.util.FPSAnimator
77
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil
88
import graphics.scenery.*
99
import graphics.scenery.backends.*
10-
import graphics.scenery.backends.ShaderCompilationException
1110
import graphics.scenery.controls.TrackerInput
1211
import graphics.scenery.fonts.SDFFontAtlas
1312
import graphics.scenery.spirvcrossj.Loader
@@ -122,9 +121,11 @@ class OpenGLRenderer(hub: Hub,
122121
var initialized = false
123122
private set
124123

124+
private var pboBuffers: Array<ByteBuffer?> = arrayOf(null, null)
125+
private var pboBufferAvailable = arrayOf(true, true)
125126
@Volatile private var pbos: IntArray = intArrayOf(0, 0)
126127
private var readIndex = 0
127-
private var updateIndex = 0
128+
private var updateIndex = 1
128129

129130
private var renderConfig: RenderConfigReader.RenderConfig
130131
override var renderConfigFile = ""
@@ -1265,7 +1266,7 @@ class OpenGLRenderer(hub: Hub,
12651266
}
12661267
}
12671268

1268-
if (!n.metadata.containsKey("OpenGLRenderer")) {
1269+
if (!n.metadata.containsKey("OpenGLRenderer") || !n.initialized) {
12691270
n.metadata.put("OpenGLRenderer", OpenGLObjectState())
12701271
initializeNode(n)
12711272
return@nonInstancedDrawing
@@ -1540,7 +1541,7 @@ class OpenGLRenderer(hub: Hub,
15401541
}
15411542

15421543
readIndex = (readIndex + 1) % 2
1543-
updateIndex = (readIndex + 1) % 2
1544+
updateIndex = (updateIndex + 1) % 2
15441545

15451546
if (pbos[0] == 0 || pbos[1] == 0 || mustRecreateFramebuffers) {
15461547
gl.glGenBuffers(2, pbos, 0)
@@ -1552,21 +1553,42 @@ class OpenGLRenderer(hub: Hub,
15521553
gl.glBufferData(GL4.GL_PIXEL_PACK_BUFFER, window.width * window.height * 4L, null, GL4.GL_STREAM_READ)
15531554

15541555
gl.glBindBuffer(GL4.GL_PIXEL_PACK_BUFFER, 0)
1556+
1557+
if(pboBuffers[0] != null) {
1558+
MemoryUtil.memFree(pboBuffers[0])
1559+
}
1560+
1561+
if(pboBuffers[1] != null) {
1562+
MemoryUtil.memFree(pboBuffers[1])
1563+
}
1564+
1565+
pboBuffers[0] = null
1566+
pboBuffers[1] = null
15551567
}
15561568

1557-
gl.glBindBuffer(GL4.GL_PIXEL_PACK_BUFFER, pbos[readIndex])
1569+
if(pboBuffers[0] == null) {
1570+
pboBuffers[0] = MemoryUtil.memAlloc(4*window.width*window.height)
1571+
}
15581572

1559-
gl.glReadBuffer(GL4.GL_FRONT)
1560-
gl.glReadPixels(0, 0, window.width, window.height, GL4.GL_BGRA, GL4.GL_UNSIGNED_BYTE, 0)
1573+
if(pboBuffers[1] == null) {
1574+
pboBuffers[1] = MemoryUtil.memAlloc(4*window.width*window.height)
1575+
}
15611576

15621577
gl.glBindBuffer(GL4.GL_PIXEL_PACK_BUFFER, pbos[updateIndex])
15631578

1564-
val buffer = gl.glMapBuffer(GL4.GL_PIXEL_PACK_BUFFER, GL4.GL_READ_ONLY)
1565-
if (buffer != null) {
1579+
gl.glReadBuffer(GL4.GL_BACK)
1580+
gl.glReadPixels(0, 0, window.width, window.height, GL4.GL_BGRA, GL4.GL_UNSIGNED_BYTE, 0)
1581+
1582+
gl.glGetBufferSubData(GL4.GL_PIXEL_PACK_BUFFER, 0,
1583+
4L * window.width * window.height, pboBuffers[updateIndex])
1584+
1585+
if (!mustRecreateFramebuffers) {
15661586
Platform.runLater {
1567-
if (!mustRecreateFramebuffers) embedPanel.update(buffer)
1587+
pboBuffers[readIndex]?.let {
1588+
val id = viewportPass.output.values.first().getTextureId("Viewport")
1589+
embedPanel.update(it, id = id)
1590+
}
15681591
}
1569-
gl.glUnmapBuffer(GL4.GL_PIXEL_PACK_BUFFER)
15701592
}
15711593

15721594
gl.glBindBuffer(GL4.GL_PIXEL_PACK_BUFFER, 0)
@@ -1633,6 +1655,10 @@ class OpenGLRenderer(hub: Hub,
16331655
* @return True if the initialisation went alright, False if it failed.
16341656
*/
16351657
fun initializeNode(node: Node): Boolean {
1658+
if(!node.lock.tryLock(2, TimeUnit.MILLISECONDS)) {
1659+
return false
1660+
}
1661+
16361662
val s: OpenGLObjectState
16371663

16381664
if (node.instanceOf == null) {
@@ -1696,21 +1722,17 @@ class OpenGLRenderer(hub: Hub,
16961722
}
16971723

16981724
if (node is HasGeometry) {
1699-
node.lock.tryLock(100, TimeUnit.MILLISECONDS)
1700-
if (node.lock.tryLock()) {
1701-
setVerticesAndCreateBufferForNode(node)
1702-
setNormalsAndCreateBufferForNode(node)
1725+
setVerticesAndCreateBufferForNode(node)
1726+
setNormalsAndCreateBufferForNode(node)
17031727

1704-
if (node.texcoords.limit() > 0) {
1705-
setTextureCoordsAndCreateBufferForNode(node)
1706-
}
1707-
1708-
if (node.indices.limit() > 0) {
1709-
setIndicesAndCreateBufferForNode(node)
1710-
}
1728+
if (node.texcoords.limit() > 0) {
1729+
setTextureCoordsAndCreateBufferForNode(node)
1730+
}
17111731

1712-
node.lock.unlock()
1732+
if (node.indices.limit() > 0) {
1733+
setIndicesAndCreateBufferForNode(node)
17131734
}
1735+
17141736
}
17151737

17161738
val matricesUbo = OpenGLUBO(backingBuffer = buffers["UBOBuffer"])
@@ -1726,35 +1748,13 @@ class OpenGLRenderer(hub: Hub,
17261748
s.UBOs.put("Matrices", this)
17271749
}
17281750

1729-
17301751
loadTexturesForNode(node, s)
17311752

17321753
val materialUbo = OpenGLUBO(backingBuffer = buffers["UBOBuffer"])
1733-
var materialType = 0
1734-
1735-
if (node.material.textures.containsKey("ambient") && !s.defaultTexturesFor.contains("ambient")) {
1736-
materialType = materialType or MATERIAL_HAS_AMBIENT
1737-
}
1738-
1739-
if (node.material.textures.containsKey("diffuse") && !s.defaultTexturesFor.contains("diffuse")) {
1740-
materialType = materialType or MATERIAL_HAS_DIFFUSE
1741-
}
1742-
1743-
if (node.material.textures.containsKey("specular") && !s.defaultTexturesFor.contains("specular")) {
1744-
materialType = materialType or MATERIAL_HAS_SPECULAR
1745-
}
1746-
1747-
if (node.material.textures.containsKey("normal") && !s.defaultTexturesFor.contains("normal")) {
1748-
materialType = materialType or MATERIAL_HAS_NORMAL
1749-
}
1750-
1751-
if (node.material.textures.containsKey("alphamask") && !s.defaultTexturesFor.contains("alphamask")) {
1752-
materialType = materialType or MATERIAL_HAS_ALPHAMASK
1753-
}
17541754

17551755
with(materialUbo) {
17561756
name = "MaterialProperties"
1757-
add("materialType", { materialType })
1757+
add("materialType", { node.materialToMaterialType() })
17581758
add("Ka", { node.material.ambient })
17591759
add("Kd", { node.material.diffuse })
17601760
add("Ks", { node.material.specular })
@@ -1785,9 +1785,44 @@ class OpenGLRenderer(hub: Hub,
17851785
node.metadata[this.javaClass.simpleName] = s
17861786

17871787
s.initialized = true
1788+
node.lock.unlock()
17881789
return true
17891790
}
17901791

1792+
private fun Node.materialToMaterialType(): Int {
1793+
var materialType = 0
1794+
val s = this.metadata["OpenGLRenderer"] as? OpenGLObjectState ?: return 0
1795+
1796+
s.defaultTexturesFor.clear()
1797+
arrayOf("ambient", "diffuse", "specular", "normal", "alphamask", "displacement").forEach {
1798+
if (!s.textures.containsKey(it)) {
1799+
s.defaultTexturesFor.add(it)
1800+
}
1801+
}
1802+
1803+
if (this.material.textures.containsKey("ambient") && !s.defaultTexturesFor.contains("ambient")) {
1804+
materialType = materialType or MATERIAL_HAS_AMBIENT
1805+
}
1806+
1807+
if (this.material.textures.containsKey("diffuse") && !s.defaultTexturesFor.contains("diffuse")) {
1808+
materialType = materialType or MATERIAL_HAS_DIFFUSE
1809+
}
1810+
1811+
if (this.material.textures.containsKey("specular") && !s.defaultTexturesFor.contains("specular")) {
1812+
materialType = materialType or MATERIAL_HAS_SPECULAR
1813+
}
1814+
1815+
if (this.material.textures.containsKey("normal") && !s.defaultTexturesFor.contains("normal")) {
1816+
materialType = materialType or MATERIAL_HAS_NORMAL
1817+
}
1818+
1819+
if (this.material.textures.containsKey("alphamask") && !s.defaultTexturesFor.contains("alphamask")) {
1820+
materialType = materialType or MATERIAL_HAS_ALPHAMASK
1821+
}
1822+
1823+
return materialType
1824+
}
1825+
17911826
/**
17921827
* Parallel forEach implementation for HashMaps.
17931828
*
@@ -1908,13 +1943,6 @@ class OpenGLRenderer(hub: Hub,
19081943
}
19091944
}
19101945

1911-
arrayOf("ambient", "diffuse", "specular", "normal", "alphamask", "displacement").forEach {
1912-
if (!s.textures.containsKey(it)) {
1913-
// s.textures.putIfAbsent(it, textureCache["DefaultTexture"]!!)
1914-
s.defaultTexturesFor.add(it)
1915-
}
1916-
}
1917-
19181946
node.material.needsTextureReload = false
19191947
s.initialized = true
19201948
node.lock.unlock()

src/main/kotlin/graphics/scenery/backends/vulkan/FXSwapchain.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class FXSwapchain(device: VulkanDevice,
241241
}
242242

243243
override fun postPresent(image: Int) {
244-
if (vulkanSwapchainRecreator.mustRecreate) {
244+
if (vulkanSwapchainRecreator.mustRecreate && sharingBuffer.initialized()) {
245245
return
246246
}
247247

@@ -283,7 +283,7 @@ class FXSwapchain(device: VulkanDevice,
283283
VK10.vkQueueWaitIdle(queue)
284284

285285
Platform.runLater {
286-
if (lock.tryLock() && !vulkanSwapchainRecreator.mustRecreate) {
286+
if (lock.tryLock() && !vulkanSwapchainRecreator.mustRecreate && sharingBuffer.initialized()) {
287287
val imageByteSize = window.width * window.height * 4
288288
val buffer = sharingBuffer.mapIfUnmapped().getByteBuffer(imageByteSize)
289289

src/main/kotlin/graphics/scenery/backends/vulkan/VulkanBuffer.kt

+4
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ class VulkanBuffer(val device: VulkanDevice, val size: Long, val usage: Int, val
156156
copyFrom(stagingBuffer)
157157
}
158158

159+
fun initialized(): Boolean {
160+
return ((vulkanBuffer != -1L) && (memory != -1L))
161+
}
162+
159163
override fun close() {
160164
logger.debug("Closing buffer $this ...")
161165

src/main/kotlin/graphics/scenery/utils/DirectWritableImage.kt

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
package graphics.scenery.utils
22

3-
import java.lang.reflect.Array
4-
import java.lang.reflect.InvocationTargetException
5-
import java.nio.ByteBuffer
6-
73
import coremem.ContiguousMemoryInterface
84
import javafx.scene.image.WritableImage
5+
import java.lang.reflect.Array
96
import java.lang.reflect.Field
7+
import java.lang.reflect.InvocationTargetException
108
import java.lang.reflect.Method
9+
import java.nio.ByteBuffer
1110

1211
/**
1312
* Direct writable image
1413
1514
* @author Loic Royer <royerloic@gmail.com>, Ulrik Guenther <hello@ulrik.is>
1615
*/
1716
class DirectWritableImage(pWidth: Int, pHeight: Int) : WritableImage(pWidth, pHeight) {
18-
private var getWritablePlatformImage: Method
17+
var getWritablePlatformImage: Method
1918
private var pixelBuffer: Field
2019
private var serial: Field
2120
private var pixelsDirty: Method
@@ -69,7 +68,7 @@ class DirectWritableImage(pWidth: Int, pHeight: Int) : WritableImage(pWidth, pHe
6968
private fun writeToImageDirectly(direct: ByteBuffer,
7069
writableImg: WritableImage) {
7170
// Get the platform image
72-
val prismImg = getWritablePlatformImage.invoke(writableImg) as com.sun.prism.Image
71+
val prismImg = getWritablePlatformImage(writableImg) as com.sun.prism.Image
7372

7473
// Replace the buffer
7574
pixelBuffer.set(prismImg, direct)
@@ -87,7 +86,7 @@ class DirectWritableImage(pWidth: Int, pHeight: Int) : WritableImage(pWidth, pHe
8786
// Get the platform image
8887
val getWritablePlatformImage = javafx.scene.image.Image::class.java.getDeclaredMethod("getWritablePlatformImage")
8988
getWritablePlatformImage.isAccessible = true
90-
val prismImg = getWritablePlatformImage.invoke(writableImg) as com.sun.prism.Image
89+
val prismImg = getWritablePlatformImage(writableImg) as com.sun.prism.Image
9190

9291
// Replace the buffer
9392
val pixelBuffer = com.sun.prism.Image::class.java.getDeclaredField("pixelBuffer")
@@ -106,7 +105,7 @@ class DirectWritableImage(pWidth: Int, pHeight: Int) : WritableImage(pWidth, pHe
106105
Array.getInt(serial.get(prismImg), 0) + 1)
107106

108107
// Invalidate the WritableImage
109-
pixelsDirty.invoke(writableImg)
108+
pixelsDirty(writableImg)
110109
}
111110

112111
}

0 commit comments

Comments
 (0)