import { Asset } from 'expo-asset'; import ExpoCheckbox from 'expo-checkbox'; import { ExpoWebGLRenderingContext, GLView } from 'expo-gl'; import React, { useEffect, useState } from 'react'; import { Text, StyleSheet, View, TouchableHighlight } from 'react-native'; import { runOnUI } from 'react-native-reanimated'; async function onContextCreate(gl: ExpoWebGLRenderingContext) { const vert = gl.createShader(gl.VERTEX_SHADER)!; gl.shaderSource( vert, ` precision highp float; attribute vec2 position; varying vec2 uv; void main () { uv = position; gl_Position = vec4(1.0 - 2.0 * position, 0, 1); }` ); gl.compileShader(vert); const frag = gl.createShader(gl.FRAGMENT_SHADER)!; gl.shaderSource( frag, ` precision highp float; uniform sampler2D texture; varying vec2 uv; void main () { gl_FragColor = texture2D(texture, vec2(uv.x, uv.y)); }` ); gl.compileShader(frag); const program = gl.createProgram()!; gl.attachShader(program, vert); gl.attachShader(program, frag); gl.linkProgram(program); gl.useProgram(program); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); const verts = new Float32Array([-2, 0, 0, -2, 2, 2]); gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW); const positionAttrib = gl.getAttribLocation(program, 'position'); gl.enableVertexAttribArray(positionAttrib); gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0); const asset = Asset.fromModule(require('../../../assets/images/nikki.png')); await asset.downloadAsync(); const texture = gl.createTexture(); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, asset as any); gl.uniform1i(gl.getUniformLocation(program, 'texture'), 0); gl.clearColor(0, 0, 1, 1); // tslint:disable-next-line: no-bitwise gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2); gl.endFrameEXP(); } function BusyJSThreadSelector() { const [fakeBusyJSThread, setFakeBusyJSThread] = useState(false); useEffect(() => { if (!fakeBusyJSThread) { return; } const interval = setInterval(() => { let test_value = 0; const start = Date.now(); while (Date.now() - start < 990) { test_value += Math.random(); } console.log(`js - ${test_value}`); }, 1000); return () => clearInterval(interval); }, [fakeBusyJSThread]); return ( setFakeBusyJSThread(!fakeBusyJSThread)} value={fakeBusyJSThread} /> fake work on js thread ); } function BusyWorkletThreadSelector() { const [fakeBusyWorkletThread, setFakeBusyWorkletThread] = useState(true); useEffect(() => { if (!fakeBusyWorkletThread) { return; } const interval = setInterval(() => { runOnUI(() => { 'worklet'; let test_value = 0; const start = Date.now(); while (Date.now() - start < 990) { test_value += Math.random(); } console.log(`worklet - ${test_value}`); })(); }, 1000); return () => clearInterval(interval); }, [fakeBusyWorkletThread]); return ( setFakeBusyWorkletThread(!fakeBusyWorkletThread)} value={fakeBusyWorkletThread} /> fake work on worklet thread ); } export default function GLViewOnBusyThread() { const [show, setShow] = useState(true); return ( This screen is expected to lag. It's faking work on JS and worklet threads. Toggle GLView few times to make sure it does no crash. {show ? ( ) : ( no gl view )} setShow(!show)}> TOGGLE ); } GLViewOnBusyThread.title = 'Creating GLView when a thread is busy'; const styles = StyleSheet.create({ flex: { flex: 1, }, checkboxRow: { flexDirection: 'row', alignItems: 'center', marginLeft: 10, }, placeholder: { flex: 1, justifyContent: 'center', alignItems: 'center', }, text: { padding: 10, fontSize: 16, }, buttonText: { fontSize: 22, }, button: { height: 100, alignItems: 'center', justifyContent: 'center', backgroundColor: '#2196f3', marginTop: 10, }, });