[osx, gles] expose gles surface and gles API to orca apps. git statusWARNING: No memory checks whatsoever for nowgit status

This commit is contained in:
Martin Fouilleul 2023-08-03 11:37:32 +02:00
parent a658e714c3
commit 754dfc2f0e
18 changed files with 5905 additions and 361 deletions

3
.gitignore vendored
View File

@ -16,10 +16,13 @@ bin/*
Debug/* Debug/*
scripts/__pycache__
src/gles_api.json
src/bindgen_core_api.c src/bindgen_core_api.c
src/bindgen_gles_api.c src/bindgen_gles_api.c
sdk/io_stubs.c sdk/io_stubs.c
sdk/orca_surface.c sdk/orca_surface.c
sdk/gl31.h
*bind_gen.c *bind_gen.c
.vscode/settings.json .vscode/settings.json

View File

@ -57,6 +57,10 @@ elif [ $target = orca ] ; then
LIBS="-Lbin -lmilepost -lwasm3" LIBS="-Lbin -lmilepost -lwasm3"
FLAGS="-g -DLOG_COMPILE_DEBUG -mmacos-version-min=10.15.4 -maes" FLAGS="-g -DLOG_COMPILE_DEBUG -mmacos-version-min=10.15.4 -maes"
# generate gl31 header and json spec
python3 ./scripts/gles_gen.py --spec milepost/ext/gl.xml --header sdk/gl31.h --json src/gles_api.json
# generate wasm3 api bindings # generate wasm3 api bindings
python3 ./scripts/bindgen.py core \ python3 ./scripts/bindgen.py core \

@ -1 +1 @@
Subproject commit 6221370aa0e8c520ebde179a1e715a8ed2e28611 Subproject commit 12fa7be765b139f41e45aa802b3e1558ba704fb9

3
samples/glesTriangle/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Triangle
profile.dtrace
profile.spall

View File

@ -0,0 +1,17 @@
@echo off
:: compile wasm module
set wasmFlags=--target=wasm32^
--no-standard-libraries ^
-fno-builtin ^
-Wl,--no-entry ^
-Wl,--export-dynamic ^
-g ^
-O2 ^
-mbulk-memory ^
-D__ORCA__ ^
-isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src
clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c
python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --name Triangle --resource-dir data module.wasm

33
samples/glesTriangle/build.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
set -euo pipefail
if [[ -x /usr/local/opt/llvm/bin/clang ]]; then
CLANG=/usr/local/opt/llvm/bin/clang
elif [[ -x /opt/homebrew/opt/llvm/bin/clang ]]; then
CLANG=/opt/homebrew/opt/llvm/bin/clang
else
echo "Could not find Homebrew clang; this script will probably not work."
CLANG=clang
fi
STDLIB_DIR=../../cstdlib
ORCA_SDK_DIR=../../sdk
MILEPOST_DIR=../../milepost
wasmFlags="--target=wasm32 \
--no-standard-libraries \
-fno-builtin \
-Wl,--no-entry \
-Wl,--export-dynamic \
-g \
-O2 \
-mbulk-memory \
-D__ORCA__ \
-I $STDLIB_DIR/include \
-I $ORCA_SDK_DIR \
-I $MILEPOST_DIR/ext -I $MILEPOST_DIR -I $MILEPOST_DIR/src"
$CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c
python3 ../../scripts/mkapp.py --orca-dir ../.. --name Triangle --resource-dir data module.wasm

View File

@ -0,0 +1,96 @@
#include <keys.h>
#include <graphics.h>
#include <math.h>
#include <orca.h>
vec2 frameSize = {100, 100};
mg_surface surface;
unsigned int program;
const char* vshaderSource =
"attribute vec4 vPosition;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position = transform*vPosition;\n"
"}\n";
const char* fshaderSource =
"precision mediump float;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
void compile_shader(GLuint shader, const char* source)
{
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
int err = glGetError();
if(err)
{
log_info("gl error");
}
}
ORCA_EXPORT void OnInit(void)
{
surface = mg_surface_gles();
mg_surface_prepare(surface);
unsigned int vshader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER);
program = glCreateProgram();
compile_shader(vshader, vshaderSource);
compile_shader(fshader, fshaderSource);
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
{
log_info("frame resize %u, %u", width, height);
frameSize.x = width;
frameSize.y = height;
}
ORCA_EXPORT void OnFrameRefresh(void)
{
f32 aspect = frameSize.x/frameSize.y;
mg_surface_prepare(surface);
glClearColor(0, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
static float alpha = 0;
glViewport(0, 0, frameSize.x * 2, frameSize.y * 2);
GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0,
-sinf(alpha)/aspect, cosf(alpha), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};
alpha += 2*M_PI/120;
glUniformMatrix4fv(0, 1, false, matrix);
GLfloat vertices[] = {
-0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0};
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
mg_surface_present(surface);
}

View File

@ -45,9 +45,6 @@ mg_image ballImage;
mg_image paddleImage; mg_image paddleImage;
mg_font pongFont; mg_font pongFont;
// TODO(ben): Why is this here? Why isn't it forward-declared by some header?
mg_surface mg_surface_main(void);
f32 lerp(f32 a, f32 b, f32 t); f32 lerp(f32 a, f32 b, f32 t);
mp_rect blockRect(int i); mp_rect blockRect(int i);
int checkCollision(mp_rect block); int checkCollision(mp_rect block);
@ -69,7 +66,7 @@ str8 loadFile(mem_arena* arena, str8 filename) {
ORCA_EXPORT void OnInit(void) ORCA_EXPORT void OnInit(void)
{ {
surface = mg_surface_main(); surface = mg_surface_canvas();
canvas = mg_canvas_create(); canvas = mg_canvas_create();
waterImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/underwater.jpg")), false); waterImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/underwater.jpg")), false);

0
samples/ui/build.sh Normal file → Executable file
View File

View File

@ -12,12 +12,10 @@ mg_font font;
ui_context ui; ui_context ui;
mem_arena textArena = {0}; mem_arena textArena = {0};
mg_surface mg_surface_main(void);
ORCA_EXPORT void OnInit(void) ORCA_EXPORT void OnInit(void)
{ {
//TODO create surface for main window //TODO create surface for main window
surface = mg_surface_main(); surface = mg_surface_canvas();
canvas = mg_canvas_create(); canvas = mg_canvas_create();
ui_init(&ui); ui_init(&ui);

228
scripts/gles_gen.py Normal file
View File

@ -0,0 +1,228 @@
from reg_modified import *
import xml.etree.ElementTree as et
from argparse import ArgumentParser
def gen_gles_header(spec, filename):
# Generates the GLES header, wrapping gl functions
# prototypes in ORCA_IMPORT() macro
gles2through31Pat = '2\.[0-9]|3\.[01]'
allVersions = '.*'
genOpts = CGeneratorOptions(
filename=filename,
apiname='gles2',
profile='common',
versions=gles2through31Pat,
emitversions=allVersions,
protectProto=False,
procMacro='ORCA_IMPORT')
reg = Registry()
tree = et.parse(spec)
reg.loadElementTree(tree)
gen = COutputGenerator()
reg.setGenerator(gen)
reg.apiGen(genOpts)
def get_bindgen_tag_for_type(typeName):
typeToTags = {
"void": "v",
"GLenum": "i",
"GLbitfield": "i",
"GLboolean": "i",
"GLbyte": "i",
"GLubyte": "i",
"GLchar": "i",
"GLshort": "i",
"GLushort": "i",
"GLhalf": "i",
"GLhalfARB": "i",
"GLuint": "i",
"GLint": "i",
"GLclampx": "i",
"GLsizei": "i",
"GLfixed": "i",
"GLuint64": "I",
"GLint64": "I",
"GLintptr": "I",
"GLsizeiptr": "I",
"GLfloat": "f",
"GLclampf": "f",
"GLdouble": "F",
"GLclampd": "F",
"GLsync": "p"
}
if typeName[len(typeName)-1] == '*':
return "p"
else:
tag = typeToTags.get(typeName)
return tag
def gen_gles_bindgen_json(spec, filename):
# Gather gles 3.1 required functions
tree = et.parse(spec)
api = []
for feature in tree.iterfind('feature[@api="gles2"]'):
if float(feature.get('number')) > 3.1:
break
for require in feature.iter('require'):
if require.get('profile') == 'compatibility':
continue
for command in require.iter('command'):
api.append(command.get('name'))
for remove in feature.iter('remove'):
for command in remove.iter('command'):
api.remove(command.get('name'))
# put all GL commands in a dict
commands = dict()
commandsSpec = tree.find('./commands')
for command in commandsSpec.iter('command'):
name = command.find('proto/name')
commands[name.text] = command
# TODO: Generate json descriptions for commands in api
manualBind = [
"glShaderSource"]
json = '[\n'
for name in api:
if name in manualBind:
continue
command = commands.get(name)
if command == None:
print("Couldn't find definition for required command '" + name + "'")
exit(-1)
proto = command.find("proto")
ptype = proto.find("ptype")
retType = ''
if proto.text != None:
retType += proto.text
if ptype != None:
if ptype.text != None:
retType += ptype.text
if ptype.tail != None:
retType += ptype.tail
retType = retType.strip()
retTag = get_bindgen_tag_for_type(retType)
if retTag == None:
print("Couldn't find tag for GL type '" + retType + "'")
exit(-1)
entry = '{\n\t"name": "' + name + '",\n'
entry += '\t"cname": "' + name + '",\n'
entry += '\t"ret": { "name": "' + retType + '", "tag": "' + retTag + '"},\n'
entry += '\t"args": [ '
# iterate through params
for param in command.iter('param'):
argNode = param.find('name')
argName = argNode.text
typeNode = param.find('ptype')
typeName = ''
if param.text != None:
typeName += param.text
if typeNode != None:
if typeNode.text != None:
typeName += typeNode.text
if typeNode.tail != None:
typeName += typeNode.tail
typeName = typeName.strip()
typeTag = get_bindgen_tag_for_type(typeName)
if typeTag == None:
print("Couldn't find tag for GL type '" + typeName + "' in function '"+ name +"'")
exit(-1)
entry += '\n'
entry += '\t\t{"name": "'+ argName +'",\n'
entry += '\t\t "type": {"name": "'+ typeName +'", "tag": "'+ typeTag +'"}'
if param.get('len') != None:
lenString = param.get('len')
tokens = lenString.split('*')
if lenString.startswith("COMPSIZE"):
print("Warning: function " + name + ": parameter " + argName + " lenght uses COMPSIZE")
else:
entry += ',\n'
entry += '\t\t "len": {'
if len(tokens) == 2:
if tokens[1].isnumeric() == False:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '"count": "' + tokens[0] + '", "components": "'+ tokens[1] + '"'
elif len(tokens) == 1:
if tokens[0].isnumeric():
entry += '"components":'+ tokens[0]
else:
entry += '"count": "'+ tokens[0] + '"'
else:
print("Warning: function " + name + ": couldn't parse parameter '" + argName + "' lenght attribute")
entry += '}'
elif typeTag == "p":
print("Warning: function " + name + ": parameter " + argName + " has no len attribute")
entry += '},'
entry = entry[:-1]
entry += '\n\t]\n}'
json += entry
json += ',\n'
json = json[:-2]
json += '\n]'
# write json to jsonFile
f = open(filename, 'w')
f.write(json)
f.close()
#----------------------------------------
# driver
#----------------------------------------
parser = ArgumentParser()
parser.add_argument("-s", "--spec")
parser.add_argument("--header")
parser.add_argument("-j", "--json")
args = parser.parse_args()
glesHeader = args.header
jsonFile = args.json
gen_gles_header(args.spec, glesHeader)
gen_gles_bindgen_json(args.spec, jsonFile)

View File

@ -137,6 +137,8 @@ def macos_make_app(args):
<string>icon.icns</string> <string>icon.icns</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
<string>True</string> <string>True</string>
<key>MetalCaptureEnabled</key>
<true/>
</dict> </dict>
</plist> </plist>
""".format(app_name=app_name, version=version, bundle_sig=bundle_sig, icon_file=icon_file) """.format(app_name=app_name, version=version, bundle_sig=bundle_sig, icon_file=icon_file)

1171
scripts/reg_modified.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,4 +25,9 @@
#error "Orca apps can only be compiled with clang for now" #error "Orca apps can only be compiled with clang for now"
#endif #endif
#include"gl31.h"
mg_surface mg_surface_canvas();
mg_surface mg_surface_gles();
#endif //__ORCA_H_ #endif //__ORCA_H_

View File

@ -36,12 +36,6 @@
{"name": "pixels", {"name": "pixels",
"type": {"name": "u8*", "tag": "p"}}] "type": {"name": "u8*", "tag": "p"}}]
}, },
{
"name": "mg_surface_main",
"cname": "orca_surface_main",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
},
{ {
"name": "mg_surface_prepare", "name": "mg_surface_prepare",
"cname": "mg_surface_prepare", "cname": "mg_surface_prepare",
@ -75,4 +69,17 @@
"type": {"name": "u32", "tag": "i"}}, "type": {"name": "u32", "tag": "i"}},
{"name": "elements", {"name": "elements",
"type": {"name": "mg_path_elt*", "tag": "p"}}] "type": {"name": "mg_path_elt*", "tag": "p"}}]
}] },
{
"name": "mg_surface_canvas",
"cname": "orca_surface_canvas",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
},
{
"name": "mg_surface_gles",
"cname": "orca_surface_gles",
"ret": {"name": "mg_surface", "tag": "S"},
"args": []
}
]

File diff suppressed because it is too large Load Diff

View File

@ -170,11 +170,38 @@ void orca_log(log_level level,
msg); msg);
} }
mg_surface orca_surface_main(void) mg_surface orca_surface_canvas(void)
{ {
return(__orcaApp.surface); return(__orcaApp.surface);
} }
typedef struct orca_surface_create_data
{
mp_window window;
mg_surface_api api;
mg_surface surface;
} orca_surface_create_data;
i32 orca_surface_gles_callback(void* user)
{
orca_surface_create_data* data = (orca_surface_create_data*)user;
data->surface = mg_surface_create_for_window(data->window, data->api);
return(0);
}
mg_surface orca_surface_gles(void)
{
orca_surface_create_data data = {
.surface = mg_surface_nil(),
.window = __orcaApp.window,
.api = MG_GLES
};
mp_dispatch_on_main_thread_sync(orca_surface_gles_callback, (void*)&data);
return(data.surface);
}
void orca_surface_render_commands(mg_surface surface, void orca_surface_render_commands(mg_surface surface,
mg_color clearColor, mg_color clearColor,
u32 primitiveCount, u32 primitiveCount,
@ -303,7 +330,7 @@ void orca_runtime_init(orca_runtime* runtime)
#include"io_api_bind_gen.c" #include"io_api_bind_gen.c"
#include"gles_api_bind_gen.c" #include"gles_api_bind_gen.c"
#include"manual_gles_api.c" #include"gles_api_bind_manual.c"
i32 orca_runloop(void* user) i32 orca_runloop(void* user)
{ {
@ -765,6 +792,7 @@ int main(int argc, char** argv)
app->canvas = mg_canvas_create(); app->canvas = mg_canvas_create();
mg_surface_swap_interval(app->surface, 1); mg_surface_swap_interval(app->surface, 1);
app->debugOverlay.show = false; app->debugOverlay.show = false;
app->debugOverlay.surface = mg_surface_create_for_window(app->window, MG_CANVAS); app->debugOverlay.surface = mg_surface_create_for_window(app->window, MG_CANVAS);
app->debugOverlay.canvas = mg_canvas_create(); app->debugOverlay.canvas = mg_canvas_create();