MAKE: added update target for flextgl

master
Martin Gerhardy 2020-05-21 21:45:51 +02:00
parent 2f394d8605
commit 73c15f98f3
8 changed files with 229 additions and 119 deletions

View File

@ -170,6 +170,16 @@ update-simplexnoise:
$(call UPDATE_GIT,simplexnoise,https://github.com/simongeilfus/SimplexNoise.git)
cp $(UPDATEDIR)/simplexnoise.sync/include/Simplex.h src/modules/noise
update-flextgl:
$(call UPDATE_GIT,flextgl,https://github.com/mosra/flextgl.git)
cp $(UPDATEDIR)/flextgl.sync/*.py tools/flextGL
cp $(UPDATEDIR)/flextgl.sync/README.md tools/flextGL
cp $(UPDATEDIR)/flextgl.sync/COPYING tools/flextGL
rm -rf tools/flextGL/templates/sdl
rm -rf tools/flextGL/templates/vulkan
cp -r $(UPDATEDIR)/flextgl.sync/templates/sdl tools/flextGL/templates
cp -r $(UPDATEDIR)/flextgl.sync/templates/vulkan tools/flextGL/templates
# TODO simpleai support
# TODO lua support
updatelibs: update-nuklear update-libuv update-stb update-googletest update-benchmark update-backward update-dearimgui update-flatbuffers update-enet update-glm update-sdl2 update-glslang update-simplecpp

View File

@ -1,7 +1,7 @@
flextGL
=======
[![Build Status](https://travis-ci.com/mosra/flextgl.svg?branch=master)](https://travis-ci.com/mosra/flextgl)
[![Build Status](https://travis-ci.org/mosra/flextgl.svg?branch=master)](https://travis-ci.org/mosra/flextgl)
[![Coverage Status](https://codecov.io/gh/mosra/flextgl/branch/master/graph/badge.svg)](https://codecov.io/gh/mosra/flextgl)
flextGL is an OpenGL and Vulkan header and loader generator.
@ -15,7 +15,7 @@ It is a bit different than other comparable systems:
- For Vulkan, it's possible to adapt the templates to generate separate
instance-specific and device-specific loader for faster runtime
performance, or switch from globally visible symbols to local ones
([blog post with details](http://blog.magnum.graphics/hacking/simple-efficient-vulkan-loading-with-flextgl/))
([blog post with details](https://blog.magnum.graphics/hacking/simple-efficient-vulkan-loading-with-flextgl/))
- Only requested extensions are loaded
- Flexible python template system for source generation
- Source templates easy to adapt to project requirements
@ -28,6 +28,11 @@ You will need the following dependencies:
### What's new?
- **October 2019:** Breaking change -- the GL `<KHR/khrplatform.h>` include
is now required to be specified by the template instead of being added
implicitly from the `gl.xml` definition. This is done in order to allow
more flexibility and is consistent with how `vk_platform.h` is handled.
See commit bef1e12c98562fa87b698751a75d9da84e11c98d for details.
- **May 2018:** Vulkan support, 100% test coverage,
[@mosra](https://github.com/mosra) took over the maintainership from
[@ginkgo](https://github.com/ginkgo)
@ -147,7 +152,7 @@ Generated API for Vulkan
For simplicity, the default template generates all function pointers globally
and loads them as instance-specific. See
[this blog post](http://blog.magnum.graphics/hacking/simple-efficient-vulkan-loading-with-flextgl/)
[this blog post](https://blog.magnum.graphics/hacking/simple-efficient-vulkan-loading-with-flextgl/)
for other options. Apart from Vulkan APIs, two functions are defined:
- `void flextVkInit()`
@ -173,21 +178,11 @@ At the moment, there are three template sets available:
> This loads the extensions using a framework-agnostic method with WGL
> AGL or GLX. This is probably a sensible default for most people.
- `glfw`
- `glfw3`, `glfw3-es`
> This uses GLFW 2's functions for loading and testing for OpenGL
> extensions. It will obviously only work with GLFW, but is well tested and
> the generated source code is very easy to understand.
- `glfw3`
> This works like the `glfw` template, but uses GLFW 3 instead. In this
> template, a pointer to the GLFWwindow has to be passed as a parameter of
> `flextInit()`.
- `glfw3-es`
> Used for generating OpenGL ES loading code.
> These use GLFW 3 functions for loading and testing for OpenGL extensions
> either for desktop OpenGL or OpenGL ES. In these templates, the
> `flextInit()` function takes a pointer to `GLFWwindow`.
- `lite`

View File

@ -37,6 +37,7 @@ gl_spec_url = 'http://www.opengl.org/registry/api/gl.xml'
# tags were also named differently). I hope this will not be changing much in
# the future, as that would break loading of older versions.
vk_spec_url = 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/{}/xml/vk.xml'
vk_spec_url10 = 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/{}-core/src/spec/vk.xml'
################################################################################
# Spec file download
@ -250,7 +251,7 @@ def xml_parse_type_name_pair(node):
if ptype == None: ptype = node.find('type')
return (name, type, ptype.text.strip() if ptype != None else None)
def extract_enums(feature, enum_extensions, extension_number = None):
def extract_enums(feature, enum_extensions, *, extension_number=None, enum_extends_blacklist=set()):
subsetEnums = []
for enum in feature.findall('enum'):
@ -259,6 +260,10 @@ def extract_enums(feature, enum_extensions, extension_number = None):
if 'extends' in enum.attrib:
extends = enum.attrib['extends']
# See the comment about VK_KHR_sampler_ycbcr_conversion in
# parse_xml_extensions()
if extends in enum_extends_blacklist: continue
# VkSamplerAddressMode from VK_KHR_sampler_mirror_clamp_to_edge
# has an explicit value. The sanest way, yet they say "this
# is a special case, and should not be repeated".
@ -380,6 +385,8 @@ def parse_xml_types(root, enum_extensions, promoted_enum_extensions, api):
name = type.attrib['name']
enumdef = root.find("./enums[@name='{}']".format(name))
if enumdef: # Some Vulkan enums are empty (bitsets)
written_enum_values = set()
for enum in enumdef.findall('enum'):
if 'bitpos' in enum.attrib:
values += [' {} = 1 << {}'.format(enum.attrib['name'], enum.attrib['bitpos'])]
@ -387,8 +394,9 @@ def parse_xml_types(root, enum_extensions, promoted_enum_extensions, api):
values += [' {} = {}'.format(enum.attrib['name'], enum.attrib['alias'])]
else:
values += [' {} = {}'.format(enum.attrib['name'], enum.attrib['value'])]
if name in enum_extensions:
written_enum_values.add(enum.attrib['name'])
if name in enum_extensions:
# Extension enum values might be promoted to core in later
# versions, create a map with their values to avoid having
# aliases to nonexistent values
@ -400,7 +408,25 @@ def parse_xml_types(root, enum_extensions, promoted_enum_extensions, api):
# Value is either a concrete value, an existing alias or
# an extracted value from a promoted alias above
for extension, value in enum_extensions[name]:
values += [' {} = {}'.format(extension, extensions[value] if value in extensions else value)]
# If the enum value is a (negative) number, write that
if not value[0].isalpha():
value_to_write = value
# If it's an alias to a promoted extension and the
# original value haven't been written yet, write the
# core name. If the original value is already written,
# it's better to show the alias explicitly for
# documentation purposes instead of showing the same
# value twice without any apparent reason
elif value in extensions and not value in written_enum_values:
value_to_write = extensions[value]
# Otherwise, if it's an alias and the target wasn't
# written yet, it's a problem
else:
assert value in written_enum_values, "Alias target for %s not found: %s" % (extension, value)
value_to_write = value
values += [' {} = {}'.format(extension, value_to_write)]
written_enum_values.add(extension)
definition = '\ntypedef enum {{\n{}\n}} {};'.format(',\n'.join(values), name)
@ -546,16 +572,61 @@ def parse_xml_features(root, version):
def parse_xml_extensions(root, extensions, enum_extensions, version):
subsets = []
for name, _ in extensions:
# Extensions might have dependencies, resolve them to avoid dangling
# aliases
extension_set = set()
def resolve_extension_dependencies(name):
# Added as a dependency already, don't add it twice
if name in extension_set: return []
extension_set.add(name)
extension = root.find("./extensions/extension[@name='{}{}']".format(version.prefix, name))
if extension is None:
print('%s is not an extension' % name)
return []
required = []
# Extensions can require other extensions
if 'requires' in extension.attrib:
for i in extension.attrib['requires'].split(','):
required += resolve_extension_dependencies(i[len(version.prefix):])
# ... and have interactions with other extensions. If that's the case,
# add the interacted-with extension isn't already in the set, add it
# (and all its dependencies) there so it's early enough
for interaction in extension.findall('require[@extension]'):
interaction_suffix = interaction.attrib['extension'][len(version.prefix):]
if not interaction_suffix in extension_set and interaction_suffix in [e[0] for e in extensions]:
required += resolve_extension_dependencies(interaction_suffix)
# Add the original last so the dependencies it needs are before
required += [name]
return required
extensions_with_dependencies = []
for name, _ in extensions:
extensions_with_dependencies += resolve_extension_dependencies(name)
# Ensure there are no accidental duplicates
assert len(extensions_with_dependencies) == len(set(extensions_with_dependencies))
for name in extensions_with_dependencies:
extension = root.find("./extensions/extension[@name='{}{}']".format(version.prefix, name))
if (extension==None):
print ('%s is not an extension' % name)
continue
subsetTypes = []
subsetEnums = []
subsetCommands = []
# At least in Vulkan 1.1.124, VK_KHR_sampler_ycbcr_conversion (which is
# promoted to 1.1) lists an extension to VkDebugReportObjectTypeEXT
# in a general <require> and then again (properly) in
# <require extension="VK_EXT_debug_report">. If VK_EXT_debug_report is
# not requested, that causes an assert. To circumvent that, add all
# type extensions which aren't requested to a blacklist to ignore
# later.
enum_extends_blacklist = set()
for require in extension.findall('./require[@extension]'):
# The extended extension is requested, no blaclisting
if require.attrib['extension'] in extension_set: continue
for enum in require.findall('enum'):
enum_extends_blacklist.add(enum.attrib['extends'])
for require in extension.findall('./require'):
# Given set of names is restricted to some API or profile subset
# (e.g. KHR_debug has different set of names for 'gl' and 'gles2')
@ -563,12 +634,17 @@ def parse_xml_extensions(root, extensions, enum_extensions, version):
if require.attrib['api'] != version.api: continue
if 'profile' in require.attrib and require.attrib['profile'] != version.profile: continue
# Vulkan extensions can have interactions with other extensions.
# Add those only if the other extensions is present as well.
if 'extension' in require.attrib and require.attrib['extension'] not in extension_set:
continue
subsetTypes += extract_names(require, 'type')
subsetCommands += extract_names(require, 'command')
# The 'number' attribute is available only in vk.xml, extract_enums()
# asserts that it's available if needed
enums_to_add, enum_extensions = extract_enums(require, enum_extensions, extension.attrib.get('number'))
enums_to_add, enum_extensions = extract_enums(require, enum_extensions, extension_number=extension.attrib.get('number'), enum_extends_blacklist=enum_extends_blacklist)
subsetEnums += enums_to_add
subsets.append(APISubset(name, subsetTypes, subsetEnums, subsetCommands))
@ -579,8 +655,9 @@ def generate_passthru(dependencies, types):
written_types = set()
def write_type(type, written_types, passthru):
# We're handling vk_platform ourselves; VK_API_VERSION is deprecated
if not type.definition or type.name in ['vk_platform', 'VK_API_VERSION']:
# We're handling vk_platform ( khrplatform ourselves; VK_API_VERSION is
# deprecated
if not type.definition or type.name in ['vk_platform', 'khrplatform', 'VK_API_VERSION']:
return passthru
# Ensure all dependencies are written already. Using a simple linear
@ -731,7 +808,7 @@ def parse_xml(file, version, extensions, funcslist, funcsblacklist):
# Source generation
################################################################################
def generate_source(options, version, enums, functions_by_category, passthru, extensions, types, raw_enums):
def generate_source(argsstring, options, version, enums, functions_by_category, passthru, extensions, types, raw_enums):
template_pattern = re.compile("(.*).template")
# Sort by categories and sort the functions inside the categories
@ -747,7 +824,8 @@ def generate_source(options, version, enums, functions_by_category, passthru, ex
'version' : version,
'extensions': extensions,
'types': types,
'raw_enums': raw_enums}
'raw_enums': raw_enums,
'args': argsstring}
if not os.path.isdir(options.template_dir):
print ('%s is not a directory' % options.template_dir)
exit(1)

View File

@ -1,19 +1,23 @@
#!/usr/bin/env python3
import sys
import os.path
from optparse import OptionParser
import flext
def main(options, profile):
def main(argsstring, options, profile):
version,extensions,funcslist,funcsblacklist = flext.parse_profile(profile)
# Download spec file(s) if necessary
if version.api == 'vulkan':
if version.release:
version_string = 'v{}.{}.{}'.format(version.major, version.minor, version.release)
spec_url = flext.vk_spec_url.format(version_string)
if version.major == 1 and version.minor == 0:
spec_url = flext.vk_spec_url10.format(version_string)
else:
spec_url = flext.vk_spec_url.format(version_string)
spec_file = 'vk.{}.xml'.format(version_string)
else:
spec_url = flext.vk_spec_url.format('master')
@ -28,8 +32,8 @@ def main(options, profile):
passthru, enums, functions, types, raw_enums = flext.parse_xml(spec_file, version, extensions, funcslist, funcsblacklist)
# Generate source from templates
flext.generate_source(options, version, enums, functions, passthru,
extensions, types, raw_enums)
flext.generate_source(argsstring, options, version, enums, functions,
passthru, extensions, types, raw_enums)
def parse_args(): # pragma: no cover
@ -60,4 +64,4 @@ def parse_args(): # pragma: no cover
if __name__ == "__main__": # pragma: no cover
# Read command line arguments and profile settings
main(*parse_args())
main(' '.join(sys.argv[1:]), *parse_args())

View File

@ -1,90 +1,86 @@
@require(passthru, functions, enums, options, version, extensions)
/* WARNING: This file was automatically generated */
/* Do not edit. */
@require(passthru, functions, enums, options, version, extensions, args)
/*
This file was generated using https://github.com/mosra/flextgl:
path/to/flextGLgen.py @args
Do not edit directly, modify the template or profile and regenerate.
*/
#include "flextGL.h"
#include <SDL.h>
#include <SDL.h>
#ifdef __cplusplus
extern "C" {
#endif
void flextLoadOpenGLFunctions(void);
/**
* \return -1 on error, 0 on success
* \sa SDL_GetError
*/
int flextInit(void)
{
@if version.int_value() >= 32 and not version.profile == 'core':
GLint profile;
@end
int major;
int minor;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
flextLoadOpenGLFunctions();
/* --- Check for minimal version and profile --- */
if (major * 10 + minor < @version.int_value()!s) {
return SDL_SetError("OpenGL context hasn't the expected version @version.major!s.@version.minor!s.");
}
@if version.int_value() >= 32 and not version.profile == 'core':
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
if ((profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) == 0) {
return SDL_SetError("This application requires a compatibility profile");
}
@end
/* --- Check for extensions --- */
@for extension,required in extensions:
@if required:
if (!SDL_GL_ExtensionSupported("GL_@extension")) {
return SDL_SetError("OpenGL extension @extension not supported.");
}
@else:
if (SDL_GL_ExtensionSupported("GL_@extension")) {
FLEXT_@extension = GL_TRUE;
}
@end
@end
return 0;
}
void flextLoadOpenGLFunctions(void)
{
/* --- Function pointer loading --- */
void flextLoadOpenGLFunctions(void) {
@for category,funcs in functions:
@if funcs:
@if category not in ['VERSION_1_0_DEPRECATED', 'VERSION_1_1_DEPRECATED']:
/* GL_@category */
@for f in funcs:
glpf@f.name = (PFNGL@f.name.upper()_PROC*)SDL_GL_GetProcAddress("gl@f.name");
@end
@end
@end
@end
}
/* ----------------------- Extension flag definitions ---------------------- */
int flextInit(void) {
int major;
int minor;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
flextLoadOpenGLFunctions();
/* Check for minimal version and profile */
if(major * 10 + minor < @version.int_value()!s) {
return SDL_SetError("OpenGL context hasn't the expected version @version.major!s.@version.minor!s.");
}
@if version.int_value() >= 32 and not version.profile == 'core':
GLint profile;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
if((profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) == 0) {
return SDL_SetError("This application requires a compatibility profile");
}
@end
@if extensions:
/* --- Check for extensions --- */
@for extension,required in extensions:
@if required:
if(!SDL_GL_ExtensionSupported("GL_@extension")) {
return SDL_SetError("OpenGL extension @extension not supported.");
}
@else:
if(SDL_GL_ExtensionSupported("GL_@extension")) {
FLEXT_@extension = GL_TRUE;
}
@end
@end
@end
return 0;
}
@if extensions:
/* Extension flag definitions */
@for extension,required in extensions:
int FLEXT_@extension = GL_FALSE;
@end
/* ---------------------- Function pointer definitions --------------------- */
@end
/* Function pointer definitions */
@for category,funcs in functions:
@if len(funcs) > 0:
@if len(funcs) > 0 and category not in ['VERSION_1_0_DEPRECATED', 'VERSION_1_1_DEPRECATED' ]:
/* GL_@category */
@for f in funcs:
@ -93,7 +89,6 @@ PFNGL@f.name.upper()_PROC* glpf@f.name = NULL;
@end
@end
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,15 @@
@require(passthru, functions, enums, options, version, extensions)
/* WARNING: This file was automatically generated */
/* Do not edit. */
@require(passthru, functions, enums, options, version, extensions, args)
#ifndef __gl_h_
#define __gl_h_
/*
This file was generated using https://github.com/mosra/flextgl:
path/to/flextGLgen.py @args
Do not edit directly, modify the template or profile and regenerate.
*/
#include <KHR/khrplatform.h>
#ifdef __cplusplus
extern "C" {
@ -29,47 +35,54 @@ extern "C" {
#define GLAPI extern
#endif
/* -------------------------------- DATA TYPES ------------------------------- */
/* ------------------------------- DATA TYPES ------------------------------ */
@passthru
/* ----------------------------------- ENUMS --------------------------------- */
/* ---------------------------------- ENUMS -------------------------------- */
@enums
/* --------------------------- FUNCTION PROTOTYPES --------------------------- */
/* -------------------------- FUNCTION PROTOTYPES -------------------------- */
@for cat,funcs in functions:
@if funcs:
/* GL_@cat */
@for f in funcs:
@if cat in ['VERSION_1_0_DEPRECATED', 'VERSION_1_1_DEPRECATED']:
@for f in funcs:
GLAPI @f.returntype APIENTRY gl@f.name (@f.param_list_string());
@end
@else:
@for f in funcs:
typedef @f.returntype (APIENTRY PFNGL@f.name.upper()_PROC (@f.param_list_string()));
@end
@end
@for f in funcs:
@for f in funcs:
GLAPI PFNGL@f.name.upper()_PROC* glpf@f.name;
@end
@end
@for f in funcs:
@for f in funcs:
#define gl@f.name glpf@f.name
@end
@end
@end
/* --------------------------- CATEGORY DEFINES ------------------------------ */
@end
/* -------------------------- CATEGORY DEFINES ----------------------------- */
@for cat,funcs in functions:
#define GL_@cat
@end
/* ---------------------- Flags for optional extensions ---------------------- */
@if extensions:
/* --------------------- FLAGS FOR OPTIONAL EXTENSIONS --------------------- */
@for extension,required in extensions:
extern int FLEXT_@extension;
@end
@end
int flextInit(void);
#define FLEXT_MAJOR_VERSION @version.major!s
@ -84,4 +97,4 @@ int flextInit(void);
}
#endif
#endif /* _gl_h_ */
#endif

View File

@ -1,4 +1,12 @@
@require(passthru, functions, enums, options, version, extensions)
@require(passthru, functions, enums, options, version, extensions, args)
/*
This file was generated using https://github.com/mosra/flextgl:
path/to/flextGLgen.py @args
Do not edit directly, modify the template or profile and regenerate.
*/
#include "flextVk.h"
@for category,funcs in functions:

View File

@ -1,6 +1,13 @@
@require(passthru, functions, enums, options, version, extensions)
@require(passthru, functions, enums, options, version, extensions, args)
#ifndef _flextvk_h_
#define _flextvk_h_
/*
This file was generated using https://github.com/mosra/flextgl:
path/to/flextGLgen.py @args
Do not edit directly, modify the template or profile and regenerate.
*/
#include <stdint.h>
#include <stddef.h>