@@ -76,53 +76,59 @@ void main () {
7676 } ,
7777} ) ;
7878
79- // -- GL render check: reads pixels from the Surface to verify non-black output --
79+ // -- GL render check: reads pixels inside the Node's onDraw callback
80+ // (after gl.drawArrays but before endFrameEXP buffer swap) --
8081
8182function useGLRenderCheck ( surfaceRef : React . RefObject < any > ) {
8283 const [ status , setStatus ] = useState ( "pending" ) ;
83- useEffect ( ( ) => {
84- const timer = setTimeout ( ( ) => {
85- try {
86- const surface = surfaceRef . current ;
87- if ( ! surface || ! surface . gl ) {
88- setStatus ( "no-gl" ) ;
89- return ;
90- }
91- const gl : WebGLRenderingContext = surface . gl ;
92- const pixels = new Uint8Array ( 4 * 4 * 4 ) ; // sample 4x4 center
93- const w = gl . drawingBufferWidth ;
94- const h = gl . drawingBufferHeight ;
95- const x = Math . floor ( w / 2 ) - 2 ;
96- const y = Math . floor ( h / 2 ) - 2 ;
97- gl . readPixels ( x , y , 4 , 4 , gl . RGBA , gl . UNSIGNED_BYTE , pixels ) ;
98- let nonBlack = false ;
99- for ( let i = 0 ; i < pixels . length ; i += 4 ) {
100- if ( pixels [ i ] > 5 || pixels [ i + 1 ] > 5 || pixels [ i + 2 ] > 5 ) {
101- nonBlack = true ;
102- break ;
103- }
104- }
105- setStatus ( nonBlack ? "rendered" : "black" ) ;
106- } catch {
107- setStatus ( "error" ) ;
84+ const checked = useRef ( false ) ;
85+ const onDraw = useCallback ( ( ) => {
86+ if ( checked . current ) return ;
87+ const surface = surfaceRef . current ;
88+ if ( ! surface ?. gl ) return ;
89+ checked . current = true ;
90+ const gl : WebGLRenderingContext = surface . gl ;
91+ const pixels = new Uint8Array ( 4 * 4 * 4 ) ;
92+ const w = gl . drawingBufferWidth ;
93+ const h = gl . drawingBufferHeight ;
94+ gl . readPixels (
95+ Math . floor ( w / 2 ) - 2 ,
96+ Math . floor ( h / 2 ) - 2 ,
97+ 4 ,
98+ 4 ,
99+ gl . RGBA ,
100+ gl . UNSIGNED_BYTE ,
101+ pixels ,
102+ ) ;
103+ let nonBlack = false ;
104+ for ( let i = 0 ; i < pixels . length ; i += 4 ) {
105+ if ( pixels [ i ] > 5 || pixels [ i + 1 ] > 5 || pixels [ i + 2 ] > 5 ) {
106+ nonBlack = true ;
107+ break ;
108108 }
109- } , 500 ) ;
110- return ( ) => clearTimeout ( timer ) ;
109+ }
110+ setStatus ( nonBlack ? "rendered" : "black" ) ;
111111 } , [ surfaceRef ] ) ;
112- return status ;
112+ return { status, onDraw } ;
113113}
114114
115115// -- Components --
116116
117- function HelloGL ( { surfaceRef } : { surfaceRef ?: React . RefObject < any > } ) {
117+ function HelloGL ( {
118+ surfaceRef,
119+ onDraw,
120+ } : {
121+ surfaceRef ?: React . RefObject < any > ;
122+ onDraw ?: ( ) => void ;
123+ } ) {
118124 return (
119125 < Surface ref = { surfaceRef } style = { styles . surface } >
120- < Node shader = { shaders . helloGL } />
126+ < Node shader = { shaders . helloGL } onDraw = { onDraw } />
121127 </ Surface >
122128 ) ;
123129}
124130
125- function HelloBlue ( { surfaceRef } : { surfaceRef ?: React . RefObject < any > } ) {
131+ function HelloBlue ( { surfaceRef, onDraw } : { surfaceRef ?: React . RefObject < any > ; onDraw ?: ( ) => void } ) {
126132 const [ blue , setBlue ] = useState ( 0 ) ;
127133 useEffect ( ( ) => {
128134 const start = Date . now ( ) ;
@@ -138,7 +144,7 @@ function HelloBlue({ surfaceRef }: { surfaceRef?: React.RefObject<any> }) {
138144 ) ;
139145}
140146
141- function ColorDisc ( { surfaceRef } : { surfaceRef ?: React . RefObject < any > } ) {
147+ function ColorDisc ( { surfaceRef, onDraw } : { surfaceRef ?: React . RefObject < any > ; onDraw ?: ( ) => void } ) {
142148 return (
143149 < Surface style = { styles . surface } >
144150 < Node
@@ -152,7 +158,7 @@ function ColorDisc({ surfaceRef }: { surfaceRef?: React.RefObject<any> }) {
152158 ) ;
153159}
154160
155- function RotatingHello ( { surfaceRef } : { surfaceRef ?: React . RefObject < any > } ) {
161+ function RotatingHello ( { surfaceRef, onDraw } : { surfaceRef ?: React . RefObject < any > ; onDraw ?: ( ) => void } ) {
156162 const [ angle , setAngle ] = useState ( 0 ) ;
157163 useEffect ( ( ) => {
158164 const start = Date . now ( ) ;
@@ -176,7 +182,7 @@ function RotatingHello({ surfaceRef }: { surfaceRef?: React.RefObject<any> }) {
176182 ) ;
177183}
178184
179- function MotionBlurDemo ( { surfaceRef } : { surfaceRef ?: React . RefObject < any > } ) {
185+ function MotionBlurDemo ( { surfaceRef, onDraw } : { surfaceRef ?: React . RefObject < any > ; onDraw ?: ( ) => void } ) {
180186 const [ t , setT ] = useState ( 0 ) ;
181187 useEffect ( ( ) => {
182188 const start = Date . now ( ) ;
@@ -249,7 +255,7 @@ export default function App() {
249255 const [ selected , setSelected ] = useState ( 0 ) ;
250256 const Example = examples [ selected ] . component ;
251257 const surfaceRef = useRef < any > ( null ) ;
252- const glStatus = useGLRenderCheck ( surfaceRef ) ;
258+ const { status : glStatus , onDraw } = useGLRenderCheck ( surfaceRef ) ;
253259
254260 return (
255261 < SafeAreaView style = { styles . container } testID = "app-root" >
@@ -260,7 +266,7 @@ export default function App() {
260266 </ View >
261267
262268 < View style = { styles . canvasContainer } testID = "canvas-container" >
263- < Example surfaceRef = { surfaceRef } />
269+ < Example surfaceRef = { surfaceRef } onDraw = { onDraw } />
264270 </ View >
265271 < Text testID = "gl-status" style = { styles . glStatus } >
266272 gl:{ glStatus }
0 commit comments