@@ -47,39 +47,99 @@ data class FBOSizeOverride(
4747
4848/* *
4949 * A composable that displays OpenGL content.
50- * @param state The state of the GLSurfaceView .
51- * @param modifier The modifier to apply to the GLSurfaceView .
50+ * @param state The state of the [GLSurface] .
51+ * @param modifier The modifier to apply to the [GLSurface] .
5252 * @param paint The paint to draw the contents on the compose scene.
5353 * @param glContextProvider The provider of the OpenGL context (default: [GLContextProviderFactory.detected]).
54- * @param presentMode The present mode of the GLSurfaceView (default: [GLSurfaceView.PresentMode.FIFO]).
55- *
54+ * @param presentMode The present mode of the GLSurfaceView (default: [GLSurface.PresentMode.FIFO]).
55+ * @param swapChainSize The size of the swap chain (default: 10).
56+ * @param fboSizeOverride The size override of the FBO (default: null).
57+ * @param cleanup The cleanup block to run when the [GLSurface] is destroyed (default: {}).
58+ * @param draw The draw block to render the OpenGL content.
59+ * @see [GLDrawScope]
5660 */
5761@Composable
5862fun GLSurfaceView (
5963 state : GLSurfaceState = rememberGLSurfaceState(),
6064 modifier : Modifier = Modifier ,
6165 paint : Paint = Paint (),
6266 glContextProvider : GLContextProvider <* > = GLContextProviderFactory .detected,
63- presentMode : GLSurfaceView .PresentMode = GLSurfaceView .PresentMode .FIFO ,
67+ presentMode : GLSurface .PresentMode = GLSurface .PresentMode .FIFO ,
6468 swapChainSize : Int = 10,
6569 fboSizeOverride : FBOSizeOverride ? = null,
6670 cleanup : () -> Unit = {},
6771 draw : GLDrawScope .() -> Unit ,
6872) {
69- var invalidations by remember { mutableStateOf(0 ) }
70- val surfaceView = remember {
73+ val surfaceView = rememberGLSurface(
74+ state = state,
75+ glContextProvider = glContextProvider,
76+ presentMode = presentMode,
77+ swapChainSize = swapChainSize,
78+ fboSizeOverride = fboSizeOverride,
79+ cleanup = cleanup,
80+ draw = draw,
81+ )
82+ GLSurfaceView (surfaceView, modifier, paint)
83+ }
84+
85+ /* *
86+ * A composable that remembers a [GLSurface].
87+ * @param state The state of the [GLSurface].
88+ * @param glContextProvider The provider of the OpenGL context (default: [GLContextProviderFactory.detected]).
89+ * @param presentMode The present mode of the GLSurfaceView (default: [GLSurface.PresentMode.FIFO]).
90+ * @param swapChainSize The size of the swap chain (default: 10).
91+ * @param fboSizeOverride The size override of the FBO (default: null).
92+ * @param cleanup The cleanup block to run when the [GLSurface] is destroyed (default: {}).
93+ * @param draw The draw block to render the OpenGL content.
94+ */
95+ @Composable
96+ fun rememberGLSurface (
97+ state : GLSurfaceState = rememberGLSurfaceState(),
98+ glContextProvider : GLContextProvider <* > = GLContextProviderFactory .detected,
99+ presentMode : GLSurface .PresentMode = GLSurface .PresentMode .FIFO ,
100+ swapChainSize : Int = 10,
101+ fboSizeOverride : FBOSizeOverride ? = null,
102+ cleanup : () -> Unit = {},
103+ draw : GLDrawScope .() -> Unit ,
104+ ): GLSurface {
105+ val surfaceView = remember(state, glContextProvider, presentMode, swapChainSize, cleanup, draw) {
71106 val currentContext = glContextProvider.fromCurrent() ? : error(" No current EGL context" )
72- GLSurfaceView (
107+ GLSurface (
73108 state = state,
74109 parentContext = currentContext,
75- invalidate = { invalidations++ },
76- paint = paint,
77110 presentMode = presentMode,
78111 swapChainSize = swapChainSize,
79112 cleanupBlock = cleanup,
80113 drawBlock = draw,
114+ fboSizeOverride = fboSizeOverride,
81115 )
82116 }
117+ DisposableEffect (surfaceView) {
118+ surfaceView.launch()
119+ onDispose {
120+ surfaceView.interrupt()
121+ }
122+ }
123+ LaunchedEffect (fboSizeOverride) {
124+ surfaceView.fboSizeOverride = fboSizeOverride
125+ fboSizeOverride?.size?.let (surfaceView::resize)
126+ }
127+
128+ return surfaceView
129+ }
130+
131+ /* *
132+ * A composable that displays OpenGL content.
133+ * @param surface The [GLSurface] to display.
134+ * @param modifier The modifier to apply to the [GLSurface].
135+ * @param paint The paint to draw the contents on the compose scene.
136+ */
137+ @Composable
138+ fun GLSurfaceView (
139+ surface : GLSurface ,
140+ modifier : Modifier = Modifier ,
141+ paint : Paint = Paint (),
142+ ) {
83143 val window = LocalWindow .current
84144 var directContext by remember { mutableStateOf<DirectContext ?>(null ) }
85145 LaunchedEffect (window) {
@@ -96,19 +156,20 @@ fun GLSurfaceView(
96156 Canvas (
97157 modifier = Modifier
98158 .onSizeChanged {
99- if (fboSizeOverride == null ) {
100- surfaceView .resize(it)
159+ if (surface. fboSizeOverride == null ) {
160+ surface .resize(it)
101161 }
102162 }.let {
103- if (fboSizeOverride != null ) {
163+ val override = surface.fboSizeOverride
164+ if (override != null ) {
104165 it.matchParentSize()
105166 .drawWithContent {
106- val xScale = size.width / fboSizeOverride .width
107- val yScale = size.height / fboSizeOverride .height
167+ val xScale = size.width / override .width
168+ val yScale = size.height / override .height
108169 val scale = minOf(xScale, yScale)
109170 translate(
110- (size.width - fboSizeOverride .width * scale) * fboSizeOverride .transformOrigin.pivotFractionX,
111- (size.height - fboSizeOverride .height * scale) * fboSizeOverride .transformOrigin.pivotFractionY,
171+ (size.width - override .width * scale) * override .transformOrigin.pivotFractionX,
172+ (size.height - override .height * scale) * override .transformOrigin.pivotFractionY,
112173 ) {
113174 scale(scale, Offset .Zero ) {
114175 this @drawWithContent.drawContent()
@@ -120,34 +181,23 @@ fun GLSurfaceView(
120181 }
121182 }
122183 ) {
123- invalidations.let {
184+ surface. invalidations.let {
124185 directContext?.let { directContext ->
125- surfaceView .display(drawContext.canvas.nativeCanvas, directContext)
186+ surface .display(drawContext.canvas.nativeCanvas, directContext, paint )
126187 }
127188 }
128189 }
129190 }
130- DisposableEffect (surfaceView) {
131- surfaceView.launch()
132- onDispose {
133- surfaceView.interrupt()
134- // surfaceView.join()
135- }
136- }
137- LaunchedEffect (fboSizeOverride) {
138- fboSizeOverride?.size?.let (surfaceView::resize)
139- }
140191}
141192
142- class GLSurfaceView internal constructor(
193+ class GLSurface internal constructor(
143194 private val state : GLSurfaceState ,
144195 private val parentContext : GLContext <* >,
145196 private val drawBlock : GLDrawScope .() -> Unit ,
146197 private val cleanupBlock : () -> Unit = {},
147- private val invalidate : () -> Unit = {},
148- private val paint : Paint = Paint (),
149198 private val presentMode : PresentMode = PresentMode .MAILBOX ,
150199 private val swapChainSize : Int = 10 ,
200+ internal var fboSizeOverride : FBOSizeOverride ? = null ,
151201) : Thread(" GLSurfaceView-${index.getAndIncrement()} " ) {
152202 enum class PresentMode (internal val impl : (Int , (IntSize ) -> FBO ) -> FBOSwapChain ) {
153203 /* *
@@ -168,6 +218,7 @@ class GLSurfaceView internal constructor(
168218 private var renderContext: GLContext <* >? = null
169219 private var size: IntSize = IntSize .Zero
170220 private var fboPool: FBOPool ? = null
221+ internal var invalidations by mutableStateOf(0L )
171222
172223 internal fun launch () {
173224 GL .createCapabilities()
@@ -186,17 +237,18 @@ class GLSurfaceView internal constructor(
186237 state.requestUpdate()
187238 }
188239
189- internal fun display (canvas : Canvas , displayContext : DirectContext ) {
240+ internal fun display (canvas : Canvas , displayContext : DirectContext , paint : Paint ) {
190241 val t1 = System .nanoTime()
191- fboPool?.display { displayImpl(canvas, displayContext) }
192- invalidate()
242+ fboPool?.display { displayImpl(canvas, displayContext, paint ) }
243+ invalidations = t1
193244 val t2 = System .nanoTime()
194245 state.onDisplay(t2, (t2 - t1).nanoseconds)
195246 }
196247
197248 private fun GLDisplayScope.displayImpl (
198249 canvas : Canvas ,
199250 displayContext : DirectContext ,
251+ paint : Paint ,
200252 ) {
201253 val rt = BackendRenderTarget .makeGL(
202254 fbo.size.width,
@@ -252,8 +304,8 @@ class GLSurfaceView internal constructor(
252304 break
253305 }
254306 val waitTime = renderResult.getOrNull()
255- invalidate()
256307 val renderEnd = System .nanoTime()
308+ invalidations = renderEnd
257309 state.onRender(renderEnd, (renderEnd - renderStart).nanoseconds)
258310 lastFrame = renderStart
259311 try {
@@ -280,7 +332,7 @@ class GLSurfaceView internal constructor(
280332 }
281333
282334 companion object {
283- private val logger = LoggerFactory .getLogger(GLSurfaceView ::class .java)
335+ private val logger = LoggerFactory .getLogger(GLSurface ::class .java)
284336 private val index = AtomicLong (0L )
285337 }
286338}
0 commit comments