From 9acadac916b0748425378db752b5b7e2baa59ef5 Mon Sep 17 00:00:00 2001 From: Kylogias <45217130+Kylogias@users.noreply.github.com> Date: Wed, 30 Jul 2025 10:34:52 -0400 Subject: [PATCH 1/2] Split OpenGL functionality into its own file CNFG_BATCH no longer implies CNFGOGL --- CNFG.c | 4 + CNFGFunctions.c | 475 ---------------------------------------------- CNFGOGL.c | 487 ++++++++++++++++++++++++++++++++++++++++++++++++ CNFGWinDriver.c | 10 +- CNFGXDriver.c | 4 +- Makefile | 4 +- rawdraw_sf.h | 159 +++++++++------- 7 files changed, 589 insertions(+), 554 deletions(-) create mode 100644 CNFGOGL.c diff --git a/CNFG.c b/CNFG.c index 49affc2..9dcbd41 100644 --- a/CNFG.c +++ b/CNFG.c @@ -22,6 +22,10 @@ int CNFGLastScancode = 0; #include "CNFGFunctions.c" +#ifdef CNFGOGL +#include "CNFGOGL.c" +#endif + #ifdef CNFG3D #include "CNFG3D.c" #endif diff --git a/CNFGFunctions.c b/CNFGFunctions.c index 6b2b7d2..84dec79 100644 --- a/CNFGFunctions.c +++ b/CNFGFunctions.c @@ -454,472 +454,6 @@ void CNFGSetLineWidth( short width ) #if !defined( CNFG_WASM ) && !defined( CNFGHTTP ) -//In WASM, Javascript takes over this functionality. - -//Shader compilation errors go to stderr. -#include - -#ifndef GL_VERTEX_SHADER -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_LINK_STATUS 0x8B82 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_CLAMP_TO_EDGE 0x812F -#define LGLchar char -#else -#define LGLchar GLchar -#endif - -#ifdef CNFG_WINDOWS -#define CNFGOGL_NEED_EXTENSION -#include -#endif - -#ifdef CNFGOGL_NEED_EXTENSION -// If we are going to be defining our own function pointer call - #ifdef CNFG_WINDOWS - // Make sure to use __stdcall on Windows - #define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ - typedef ret (__stdcall *CNFGTYPE##name)( __VA_ARGS__ ); \ - ret (__stdcall *CNFG##name)( __VA_ARGS__ ); - #else - #define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ - typedef ret (*CNFGTYPE##name)( __VA_ARGS__ ); \ - ret (*CNFG##name)( __VA_ARGS__ ); - #endif -#else -//If we are going to be defining the real call -#define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ - ret name (__VA_ARGS__); -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -int (*MyFunc)( int program, const LGLchar *name ); - -CHEWTYPEDEF( GLint, glGetUniformLocation, return, (program,name), GLuint program, const LGLchar *name ) -CHEWTYPEDEF( void, glEnableVertexAttribArray, , (index), GLuint index ) -CHEWTYPEDEF( void, glUseProgram, , (program), GLuint program ) -CHEWTYPEDEF( void, glGetProgramInfoLog, , (program,maxLength, length, infoLog), GLuint program, GLsizei maxLength, GLsizei *length, LGLchar *infoLog ) -CHEWTYPEDEF( void, glGetProgramiv, , (program,pname,params), GLuint program, GLenum pname, GLint *params ) -CHEWTYPEDEF( void, glBindAttribLocation, , (program,index,name), GLuint program, GLuint index, const LGLchar *name ) -CHEWTYPEDEF( void, glGetShaderiv, , (shader,pname,params), GLuint shader, GLenum pname, GLint *params ) -CHEWTYPEDEF( GLuint, glCreateShader, return, (e), GLenum e ) -CHEWTYPEDEF( void, glVertexAttribPointer, , (index,size,type,normalized,stride,pointer), GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer ) -CHEWTYPEDEF( void, glShaderSource, , (shader,count,string,length), GLuint shader, GLsizei count, const LGLchar *const*string, const GLint *length ) -CHEWTYPEDEF( void, glAttachShader, , (program,shader), GLuint program, GLuint shader ) -CHEWTYPEDEF( void, glCompileShader, ,(shader), GLuint shader ) -CHEWTYPEDEF( void, glGetShaderInfoLog , , (shader,maxLength, length, infoLog), GLuint shader, GLsizei maxLength, GLsizei *length, LGLchar *infoLog ) -CHEWTYPEDEF( GLuint, glCreateProgram, return, () , void ) -CHEWTYPEDEF( void, glLinkProgram, , (program), GLuint program ) -CHEWTYPEDEF( void, glDeleteShader, , (shader), GLuint shader ) -CHEWTYPEDEF( void, glUniform4f, , (location,v0,v1,v2,v3), GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3 ) -CHEWTYPEDEF( void, glUniform1i, , (location,i0), GLint location, GLint i0 ) -CHEWTYPEDEF( void, glActiveTexture, , (texture), GLenum texture ) - -#ifndef CNFGOGL_NEED_EXTENSION -#define CNFGglGetUniformLocation glGetUniformLocation -#define CNFGglEnableVertexAttribArray glEnableVertexAttribArray -#define CNFGglUseProgram glUseProgram -#define CNFGglEnableVertexAttribArray glEnableVertexAttribArray -#define CNFGglUseProgram glUseProgram -#define CNFGglGetProgramInfoLog glGetProgramInfoLog -#define CNFGglGetProgramiv glGetProgramiv -#define CNFGglShaderSource glShaderSource -#define CNFGglCreateShader glCreateShader -#define CNFGglAttachShader glAttachShader -#define CNFGglGetShaderiv glGetShaderiv -#define CNFGglCompileShader glCompileShader -#define CNFGglGetShaderInfoLog glGetShaderInfoLog -#define CNFGglCreateProgram glCreateProgram -#define CNFGglLinkProgram glLinkProgram -#define CNFGglDeleteShader glDeleteShader -#define CNFGglUniform4f glUniform4f -#define CNFGglBindAttribLocation glBindAttribLocation -#define CNFGglVertexAttribPointer glVertexAttribPointer -#define CNFGglUniform1i glUniform1i -#define CNFGglActiveTexture glActiveTexture - -#endif - -#ifdef __cplusplus -}; -#endif - -#ifdef CNFGOGL_NEED_EXTENSION -#ifdef CNFG_WINDOWS - -//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions -void * CNFGGetProcAddress(const char *name) -{ - void *p = (void *)wglGetProcAddress(name); - if(p == 0 || - (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || - (p == (void*)-1) ) - { - static HMODULE module; - if( !module ) module = LoadLibraryA("opengl32.dll"); - p = (void *)GetProcAddress(module, name); - } - // We were unable to load the required openGL function - if (!p) { - fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); - } - return p; -} - -#else -#include - - -void * CNFGGetProcAddress(const char *name) -{ - //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. - void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); - //printf( "%s = %p\n", name, v1 ); - if( !v1 ) v1 = dlsym( 0, name ); - return v1; -} - -#endif - -// Try and load openGL extension functions required for rawdraw -static void CNFGLoadExtensionsInternal() -{ - CNFGglGetUniformLocation = (CNFGTYPEglGetUniformLocation) CNFGGetProcAddress( "glGetUniformLocation" ); - CNFGglEnableVertexAttribArray = (CNFGTYPEglEnableVertexAttribArray)CNFGGetProcAddress( "glEnableVertexAttribArray" ); - CNFGglUseProgram = (CNFGTYPEglUseProgram)CNFGGetProcAddress( "glUseProgram" ); - CNFGglGetProgramInfoLog = (CNFGTYPEglGetProgramInfoLog)CNFGGetProcAddress( "glGetProgramInfoLog" ); - CNFGglBindAttribLocation = (CNFGTYPEglBindAttribLocation)CNFGGetProcAddress( "glBindAttribLocation" ); - CNFGglGetProgramiv = (CNFGTYPEglGetProgramiv)CNFGGetProcAddress( "glGetProgramiv" ); - CNFGglGetShaderiv = (CNFGTYPEglGetShaderiv)CNFGGetProcAddress( "glGetShaderiv" ); - CNFGglVertexAttribPointer = (CNFGTYPEglVertexAttribPointer)CNFGGetProcAddress( "glVertexAttribPointer" ); - CNFGglCreateShader = (CNFGTYPEglCreateShader)CNFGGetProcAddress( "glCreateShader" ); - CNFGglShaderSource = (CNFGTYPEglShaderSource)CNFGGetProcAddress( "glShaderSource" ); - CNFGglAttachShader = (CNFGTYPEglAttachShader)CNFGGetProcAddress( "glAttachShader" ); - CNFGglCompileShader = (CNFGTYPEglCompileShader)CNFGGetProcAddress( "glCompileShader" ); - CNFGglGetShaderInfoLog = (CNFGTYPEglGetShaderInfoLog)CNFGGetProcAddress( "glGetShaderInfoLog" ); - CNFGglDeleteShader = (CNFGTYPEglDeleteShader)CNFGGetProcAddress( "glDeleteShader" ); - CNFGglLinkProgram = (CNFGTYPEglLinkProgram)CNFGGetProcAddress( "glLinkProgram" ); - CNFGglCreateProgram = (CNFGTYPEglCreateProgram)CNFGGetProcAddress( "glCreateProgram" ); - CNFGglUniform4f = (CNFGTYPEglUniform4f)CNFGGetProcAddress( "glUniform4f" ); - CNFGglUniform1i = (CNFGTYPEglUniform1i)CNFGGetProcAddress( "glUniform1i" ); - CNFGglActiveTexture = (CNFGTYPEglActiveTexture)CNFGGetProcAddress("glActiveTexture"); - - // Check if any of these functions didn't get loaded - uint8_t not_all_functions_loaded = - !CNFGglGetUniformLocation || !CNFGglEnableVertexAttribArray || !CNFGglUseProgram || - !CNFGglGetProgramInfoLog || !CNFGglBindAttribLocation || !CNFGglGetProgramiv || - !CNFGglVertexAttribPointer || !CNFGglCreateShader || !CNFGglShaderSource || - !CNFGglAttachShader || !CNFGglCompileShader || !CNFGglGetShaderInfoLog || - !CNFGglDeleteShader || !CNFGglLinkProgram || !CNFGglCreateProgram || - !CNFGglUniform4f || !CNFGglUniform1i || !CNFGglActiveTexture; - if (not_all_functions_loaded) { - fprintf( - stderr, - "[rawdraw][err]: Unable to load all openGL extensions required for rawdraw\n" - "\tPlease update your graphics drivers or unexpected crashes may occur.\n" - ); - } - - // Give a very stern warning if unable to create or compile shaders - if (!CNFGglCreateShader || !CNFGglCompileShader) { - fprintf( - stderr, - "[rawdraw][err]: Unable to create or compile shaders, this will cause a fatal error if " - "openGL is used.\n" - "\tUpdate your video graphics drivers or switch to software graphics.\n" - ); - } -} -#else -static void CNFGLoadExtensionsInternal() { } -#endif - - - -GLuint gRDShaderProg = -1; -GLuint gRDBlitProg = -1; -GLuint gRDShaderProgUX = -1; -GLuint gRDBlitProgUX = -1; -GLuint gRDBlitProgUT = -1; -GLuint gRDBlitProgTex = -1; -GLuint gRDLastResizeW; -GLuint gRDLastResizeH; - - -GLuint CNFGGLInternalLoadShader( const char * vertex_shader, const char * fragment_shader ) -{ - GLuint fragment_shader_object = 0; - GLuint vertex_shader_object = 0; - GLuint program = 0; - int ret; - - vertex_shader_object = CNFGglCreateShader(GL_VERTEX_SHADER); - if (!vertex_shader_object) { - fprintf( stderr, "Error: glCreateShader(GL_VERTEX_SHADER) " - "failed: 0x%08X\n", glGetError()); - goto fail; - } - - CNFGglShaderSource(vertex_shader_object, 1, &vertex_shader, NULL); - CNFGglCompileShader(vertex_shader_object); - - CNFGglGetShaderiv(vertex_shader_object, GL_COMPILE_STATUS, &ret); - if (!ret) { - fprintf( stderr,"Error: vertex shader compilation failed!\n"); - CNFGglGetShaderiv(vertex_shader_object, GL_INFO_LOG_LENGTH, &ret); - - if (ret > 1) { - char * log = (char*)alloca(ret+1); - CNFGglGetShaderInfoLog(vertex_shader_object, ret, NULL, log); - fprintf( stderr, "%s", log); - } - goto fail; - } - - fragment_shader_object = CNFGglCreateShader(GL_FRAGMENT_SHADER); - if (!fragment_shader_object) { - fprintf( stderr, "Error: glCreateShader(GL_FRAGMENT_SHADER) " - "failed: 0x%08X\n", glGetError()); - goto fail; - } - - CNFGglShaderSource(fragment_shader_object, 1, &fragment_shader, NULL); - CNFGglCompileShader(fragment_shader_object); - - CNFGglGetShaderiv(fragment_shader_object, GL_COMPILE_STATUS, &ret); - if (!ret) { - fprintf( stderr, "Error: fragment shader compilation failed!\n"); - CNFGglGetShaderiv(fragment_shader_object, GL_INFO_LOG_LENGTH, &ret); - - if (ret > 1) { - char * log = (char*)alloca(ret+1); - CNFGglGetShaderInfoLog(fragment_shader_object, ret, NULL, log); - fprintf( stderr, "%s", log); - } - goto fail; - } - - program = CNFGglCreateProgram(); - if (!program) { - fprintf( stderr, "Error: failed to create program!\n"); - goto fail; - } - - CNFGglAttachShader(program, vertex_shader_object); - CNFGglAttachShader(program, fragment_shader_object); - - CNFGglBindAttribLocation(program, 0, "a0"); - CNFGglBindAttribLocation(program, 1, "a1"); - - CNFGglLinkProgram(program); - - CNFGglGetProgramiv(program, GL_LINK_STATUS, &ret); - if (!ret) { - fprintf( stderr, "Error: program linking failed!\n"); - CNFGglGetProgramiv(program, GL_INFO_LOG_LENGTH, &ret); - - if (ret > 1) { - //TODO: Refactor to remove malloc reliance. - #ifndef __clang__ - char *log = (char*)alloca(ret); - CNFGglGetProgramInfoLog(program, ret, NULL, log); - fprintf( stderr, "%s", log); - #endif - } - goto fail; - } - return program; -fail: - if( !vertex_shader_object ) CNFGglDeleteShader( vertex_shader_object ); - if( !fragment_shader_object ) CNFGglDeleteShader( fragment_shader_object ); - if( !program ) CNFGglDeleteShader( program ); - return -1; -} - -#if defined( CNFGEWGL ) && !defined( CNFG_NO_PRECISION ) -#define PRECISIONA "lowp" -#define PRECISIONB "mediump" -#else -#define PRECISIONA -#define PRECISIONB -#endif - -void CNFGSetupBatchInternal() -{ - short w, h; - - CNFGLoadExtensionsInternal(); - - CNFGGetDimensions( &w, &h ); - - gRDShaderProg = CNFGGLInternalLoadShader( - "uniform vec4 xfrm;" - "attribute vec3 a0;" - "attribute vec4 a1;" - "varying " PRECISIONA " vec4 vc;" - "void main() { gl_Position = vec4( a0.xy*xfrm.xy+xfrm.zw, a0.z, 0.5 ); vc = a1; }", - - "varying " PRECISIONA " vec4 vc;" - "void main() { gl_FragColor = vec4(vc.abgr); }" - ); - - CNFGglUseProgram( gRDShaderProg ); - gRDShaderProgUX = CNFGglGetUniformLocation ( gRDShaderProg , "xfrm" ); - - - gRDBlitProg = CNFGGLInternalLoadShader( - "uniform vec4 xfrm;" - "attribute vec3 a0;" - "attribute vec4 a1;" - "varying " PRECISIONB " vec2 tc;" - "void main() { gl_Position = vec4( a0.xy*xfrm.xy+xfrm.zw, a0.z, 0.5 ); tc = a1.xy; }", - - "varying " PRECISIONB " vec2 tc;" - "uniform sampler2D tex;" - "void main() { gl_FragColor = texture2D(tex,tc)." - -#if !defined( CNFGRASTERIZER ) -"wzyx" -#else -"wxyz" -#endif -";}" ); - - CNFGglUseProgram( gRDBlitProg ); - gRDBlitProgUX = CNFGglGetUniformLocation ( gRDBlitProg , "xfrm" ); - gRDBlitProgUT = CNFGglGetUniformLocation ( gRDBlitProg , "tex" ); - glGenTextures( 1, &gRDBlitProgTex ); - - CNFGglEnableVertexAttribArray(0); - CNFGglEnableVertexAttribArray(1); - - glDisable(GL_DEPTH_TEST); - glDepthMask( GL_FALSE ); - glEnable( GL_BLEND ); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - CNFGVertPlace = 0; -} - -#ifndef CNFGRASTERIZER -void CNFGInternalResize(short x, short y) -#else -void CNFGInternalResizeOGLBACKEND(short x, short y) -#endif -{ - glViewport( 0, 0, x, y ); - gRDLastResizeW = x; - gRDLastResizeH = y; - if (gRDShaderProg == 0xFFFFFFFF) { return; } // Prevent trying to set uniform if the shader isn't ready yet. - CNFGglUseProgram( gRDShaderProg ); - CNFGglUniform4f( gRDShaderProgUX, 1.f/x, -1.f/y, -0.5f, 0.5f); -} - -void CNFGEmitBackendTriangles( const float * vertices, const uint32_t * colors, int num_vertices ) -{ - CNFGglUseProgram( gRDShaderProg ); - CNFGglUniform4f( gRDShaderProgUX, 1.f/gRDLastResizeW, -1.f/gRDLastResizeH, -0.5f, 0.5f); - CNFGglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); - CNFGglVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); - glDrawArrays( GL_TRIANGLES, 0, num_vertices); -} - - -#ifdef CNFGOGL -// this is here, so people don't have to include opengl -void CNFGDeleteTex( unsigned int tex ) -{ - glDeleteTextures(1, &tex); -} - -unsigned int CNFGTexImage( uint32_t *data, int w, int h ) -{ - GLuint tex; - - glGenTextures(1, &tex); - glEnable( GL_TEXTURE_2D ); - CNFGglActiveTexture( 0 ); - glBindTexture( GL_TEXTURE_2D, tex ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, data ); - - return (unsigned int)tex; -} - -void CNFGBlitTex( unsigned int tex, int x, int y, int w, int h ) -{ - if( w == 0 || h == 0 ) return; - - CNFGFlushRender(); - - CNFGglUseProgram( gRDBlitProg ); - CNFGglUniform4f( gRDBlitProgUX, - 1.f/gRDLastResizeW, -1.f/gRDLastResizeH, - -0.5f+x/(float)gRDLastResizeW, 0.5f-y/(float)gRDLastResizeH ); - CNFGglUniform1i( gRDBlitProgUT, 0 ); - - glBindTexture(GL_TEXTURE_2D, tex); - - const float verts[] = { - 0,0, (float)w,0, (float)w,(float)h, - 0,0, (float)w,(float)h, 0,(float)h, }; - static const uint8_t tex_verts[] = { - 0,0, 255,0, 255,255, - 0,0, 255,255, 0,255 }; - - CNFGglVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); - CNFGglVertexAttribPointer(1, 2, GL_UNSIGNED_BYTE, GL_TRUE, 0, tex_verts); - - glDrawArrays( GL_TRIANGLES, 0, 6); -} - -void CNFGSetScissors( int * xywh ) -{ - CNFGFlushRender(); - glEnable( GL_SCISSOR_TEST ); - glScissor( xywh[0], xywh[1], xywh[2], xywh[3] ); -} - -void CNFGGetScissors( int * xywh ) -{ - CNFGFlushRender(); - glGetIntegerv( GL_SCISSOR_BOX, xywh ); -} - -#endif - -#ifdef CNFGRASTERIZER -void CNFGBlitImageInternal( uint32_t * data, int x, int y, int w, int h ) -#else -void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) -#endif -{ - glEnable( GL_TEXTURE_2D ); - CNFGglActiveTexture( 0 ); - glBindTexture( GL_TEXTURE_2D, gRDBlitProgTex ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, data ); - - CNFGBlitTex( gRDBlitProgTex, x, y, w, h ); -} void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) { @@ -941,15 +475,6 @@ void CNFGFlushRender() CNFGVertPlace = 0; } -void CNFGClearFrame() -{ - glClearColor( ((CNFGBGColor&0xff000000)>>24)/255.0f, - ((CNFGBGColor&0xff0000)>>16)/255.0f, - (CNFGBGColor&0xff00)/65280.0f, - (CNFGBGColor&0xff)/255.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); -} - #endif #endif // CNFG_WASM diff --git a/CNFGOGL.c b/CNFGOGL.c new file mode 100644 index 0000000..17961a4 --- /dev/null +++ b/CNFGOGL.c @@ -0,0 +1,487 @@ +//Copyright (c) 2010-2025 <>< Charles Lohr, and several others! +// Licensed under the MIT/x11 or NewBSD License you choose. +// +// OpenGL Renderer (platform independent portions) + +#include "CNFG.h" + +#if !defined( CNFG_WASM ) && !defined( CNFGHTTP ) +//In WASM, Javascript takes over this functionality. + +//Shader compilation errors go to stderr. +#include + +#ifndef GL_VERTEX_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_LINK_STATUS 0x8B82 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CLAMP_TO_EDGE 0x812F +#define LGLchar char +#else +#define LGLchar GLchar +#endif + +#ifdef CNFG_WINDOWS +#define CNFGOGL_NEED_EXTENSION +#include +#endif + +#ifdef CNFGOGL_NEED_EXTENSION +// If we are going to be defining our own function pointer call + #ifdef CNFG_WINDOWS + // Make sure to use __stdcall on Windows + #define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ + typedef ret (__stdcall *CNFGTYPE##name)( __VA_ARGS__ ); \ + ret (__stdcall *CNFG##name)( __VA_ARGS__ ); + #else + #define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ + typedef ret (*CNFGTYPE##name)( __VA_ARGS__ ); \ + ret (*CNFG##name)( __VA_ARGS__ ); + #endif +#else +//If we are going to be defining the real call +#define CHEWTYPEDEF( ret, name, rv, paramcall, ... ) \ + ret name (__VA_ARGS__); +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +int (*MyFunc)( int program, const LGLchar *name ); + +CHEWTYPEDEF( GLint, glGetUniformLocation, return, (program,name), GLuint program, const LGLchar *name ) +CHEWTYPEDEF( void, glEnableVertexAttribArray, , (index), GLuint index ) +CHEWTYPEDEF( void, glUseProgram, , (program), GLuint program ) +CHEWTYPEDEF( void, glGetProgramInfoLog, , (program,maxLength, length, infoLog), GLuint program, GLsizei maxLength, GLsizei *length, LGLchar *infoLog ) +CHEWTYPEDEF( void, glGetProgramiv, , (program,pname,params), GLuint program, GLenum pname, GLint *params ) +CHEWTYPEDEF( void, glBindAttribLocation, , (program,index,name), GLuint program, GLuint index, const LGLchar *name ) +CHEWTYPEDEF( void, glGetShaderiv, , (shader,pname,params), GLuint shader, GLenum pname, GLint *params ) +CHEWTYPEDEF( GLuint, glCreateShader, return, (e), GLenum e ) +CHEWTYPEDEF( void, glVertexAttribPointer, , (index,size,type,normalized,stride,pointer), GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer ) +CHEWTYPEDEF( void, glShaderSource, , (shader,count,string,length), GLuint shader, GLsizei count, const LGLchar *const*string, const GLint *length ) +CHEWTYPEDEF( void, glAttachShader, , (program,shader), GLuint program, GLuint shader ) +CHEWTYPEDEF( void, glCompileShader, ,(shader), GLuint shader ) +CHEWTYPEDEF( void, glGetShaderInfoLog , , (shader,maxLength, length, infoLog), GLuint shader, GLsizei maxLength, GLsizei *length, LGLchar *infoLog ) +CHEWTYPEDEF( GLuint, glCreateProgram, return, () , void ) +CHEWTYPEDEF( void, glLinkProgram, , (program), GLuint program ) +CHEWTYPEDEF( void, glDeleteShader, , (shader), GLuint shader ) +CHEWTYPEDEF( void, glUniform4f, , (location,v0,v1,v2,v3), GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3 ) +CHEWTYPEDEF( void, glUniform1i, , (location,i0), GLint location, GLint i0 ) +CHEWTYPEDEF( void, glActiveTexture, , (texture), GLenum texture ) + +#ifndef CNFGOGL_NEED_EXTENSION +#define CNFGglGetUniformLocation glGetUniformLocation +#define CNFGglEnableVertexAttribArray glEnableVertexAttribArray +#define CNFGglUseProgram glUseProgram +#define CNFGglEnableVertexAttribArray glEnableVertexAttribArray +#define CNFGglUseProgram glUseProgram +#define CNFGglGetProgramInfoLog glGetProgramInfoLog +#define CNFGglGetProgramiv glGetProgramiv +#define CNFGglShaderSource glShaderSource +#define CNFGglCreateShader glCreateShader +#define CNFGglAttachShader glAttachShader +#define CNFGglGetShaderiv glGetShaderiv +#define CNFGglCompileShader glCompileShader +#define CNFGglGetShaderInfoLog glGetShaderInfoLog +#define CNFGglCreateProgram glCreateProgram +#define CNFGglLinkProgram glLinkProgram +#define CNFGglDeleteShader glDeleteShader +#define CNFGglUniform4f glUniform4f +#define CNFGglBindAttribLocation glBindAttribLocation +#define CNFGglVertexAttribPointer glVertexAttribPointer +#define CNFGglUniform1i glUniform1i +#define CNFGglActiveTexture glActiveTexture + +#endif + +#ifdef __cplusplus +}; +#endif + +#ifdef CNFGOGL_NEED_EXTENSION +#ifdef CNFG_WINDOWS + +//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions +void * CNFGGetProcAddress(const char *name) +{ + void *p = (void *)wglGetProcAddress(name); + if(p == 0 || + (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || + (p == (void*)-1) ) + { + static HMODULE module; + if( !module ) module = LoadLibraryA("opengl32.dll"); + p = (void *)GetProcAddress(module, name); + } + // We were unable to load the required openGL function + if (!p) { + fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); + } + return p; +} + +#else +#include + + +void * CNFGGetProcAddress(const char *name) +{ + //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. + void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); + //printf( "%s = %p\n", name, v1 ); + if( !v1 ) v1 = dlsym( 0, name ); + return v1; +} + +#endif + +// Try and load openGL extension functions required for rawdraw +static void CNFGLoadExtensionsInternal() +{ + CNFGglGetUniformLocation = (CNFGTYPEglGetUniformLocation) CNFGGetProcAddress( "glGetUniformLocation" ); + CNFGglEnableVertexAttribArray = (CNFGTYPEglEnableVertexAttribArray)CNFGGetProcAddress( "glEnableVertexAttribArray" ); + CNFGglUseProgram = (CNFGTYPEglUseProgram)CNFGGetProcAddress( "glUseProgram" ); + CNFGglGetProgramInfoLog = (CNFGTYPEglGetProgramInfoLog)CNFGGetProcAddress( "glGetProgramInfoLog" ); + CNFGglBindAttribLocation = (CNFGTYPEglBindAttribLocation)CNFGGetProcAddress( "glBindAttribLocation" ); + CNFGglGetProgramiv = (CNFGTYPEglGetProgramiv)CNFGGetProcAddress( "glGetProgramiv" ); + CNFGglGetShaderiv = (CNFGTYPEglGetShaderiv)CNFGGetProcAddress( "glGetShaderiv" ); + CNFGglVertexAttribPointer = (CNFGTYPEglVertexAttribPointer)CNFGGetProcAddress( "glVertexAttribPointer" ); + CNFGglCreateShader = (CNFGTYPEglCreateShader)CNFGGetProcAddress( "glCreateShader" ); + CNFGglShaderSource = (CNFGTYPEglShaderSource)CNFGGetProcAddress( "glShaderSource" ); + CNFGglAttachShader = (CNFGTYPEglAttachShader)CNFGGetProcAddress( "glAttachShader" ); + CNFGglCompileShader = (CNFGTYPEglCompileShader)CNFGGetProcAddress( "glCompileShader" ); + CNFGglGetShaderInfoLog = (CNFGTYPEglGetShaderInfoLog)CNFGGetProcAddress( "glGetShaderInfoLog" ); + CNFGglDeleteShader = (CNFGTYPEglDeleteShader)CNFGGetProcAddress( "glDeleteShader" ); + CNFGglLinkProgram = (CNFGTYPEglLinkProgram)CNFGGetProcAddress( "glLinkProgram" ); + CNFGglCreateProgram = (CNFGTYPEglCreateProgram)CNFGGetProcAddress( "glCreateProgram" ); + CNFGglUniform4f = (CNFGTYPEglUniform4f)CNFGGetProcAddress( "glUniform4f" ); + CNFGglUniform1i = (CNFGTYPEglUniform1i)CNFGGetProcAddress( "glUniform1i" ); + CNFGglActiveTexture = (CNFGTYPEglActiveTexture)CNFGGetProcAddress("glActiveTexture"); + + // Check if any of these functions didn't get loaded + uint8_t not_all_functions_loaded = + !CNFGglGetUniformLocation || !CNFGglEnableVertexAttribArray || !CNFGglUseProgram || + !CNFGglGetProgramInfoLog || !CNFGglBindAttribLocation || !CNFGglGetProgramiv || + !CNFGglVertexAttribPointer || !CNFGglCreateShader || !CNFGglShaderSource || + !CNFGglAttachShader || !CNFGglCompileShader || !CNFGglGetShaderInfoLog || + !CNFGglDeleteShader || !CNFGglLinkProgram || !CNFGglCreateProgram || + !CNFGglUniform4f || !CNFGglUniform1i || !CNFGglActiveTexture; + if (not_all_functions_loaded) { + fprintf( + stderr, + "[rawdraw][err]: Unable to load all openGL extensions required for rawdraw\n" + "\tPlease update your graphics drivers or unexpected crashes may occur.\n" + ); + } + + // Give a very stern warning if unable to create or compile shaders + if (!CNFGglCreateShader || !CNFGglCompileShader) { + fprintf( + stderr, + "[rawdraw][err]: Unable to create or compile shaders, this will cause a fatal error if " + "openGL is used.\n" + "\tUpdate your video graphics drivers or switch to software graphics.\n" + ); + } +} +#else +static void CNFGLoadExtensionsInternal() { } +#endif + + + +GLuint gRDShaderProg = -1; +GLuint gRDBlitProg = -1; +GLuint gRDShaderProgUX = -1; +GLuint gRDBlitProgUX = -1; +GLuint gRDBlitProgUT = -1; +GLuint gRDBlitProgTex = -1; +GLuint gRDLastResizeW; +GLuint gRDLastResizeH; + + +GLuint CNFGGLInternalLoadShader( const char * vertex_shader, const char * fragment_shader ) +{ + GLuint fragment_shader_object = 0; + GLuint vertex_shader_object = 0; + GLuint program = 0; + int ret; + + vertex_shader_object = CNFGglCreateShader(GL_VERTEX_SHADER); + if (!vertex_shader_object) { + fprintf( stderr, "Error: glCreateShader(GL_VERTEX_SHADER) " + "failed: 0x%08X\n", glGetError()); + goto fail; + } + + CNFGglShaderSource(vertex_shader_object, 1, &vertex_shader, NULL); + CNFGglCompileShader(vertex_shader_object); + + CNFGglGetShaderiv(vertex_shader_object, GL_COMPILE_STATUS, &ret); + if (!ret) { + fprintf( stderr,"Error: vertex shader compilation failed!\n"); + CNFGglGetShaderiv(vertex_shader_object, GL_INFO_LOG_LENGTH, &ret); + + if (ret > 1) { + char * log = (char*)alloca(ret+1); + CNFGglGetShaderInfoLog(vertex_shader_object, ret, NULL, log); + fprintf( stderr, "%s", log); + } + goto fail; + } + + fragment_shader_object = CNFGglCreateShader(GL_FRAGMENT_SHADER); + if (!fragment_shader_object) { + fprintf( stderr, "Error: glCreateShader(GL_FRAGMENT_SHADER) " + "failed: 0x%08X\n", glGetError()); + goto fail; + } + + CNFGglShaderSource(fragment_shader_object, 1, &fragment_shader, NULL); + CNFGglCompileShader(fragment_shader_object); + + CNFGglGetShaderiv(fragment_shader_object, GL_COMPILE_STATUS, &ret); + if (!ret) { + fprintf( stderr, "Error: fragment shader compilation failed!\n"); + CNFGglGetShaderiv(fragment_shader_object, GL_INFO_LOG_LENGTH, &ret); + + if (ret > 1) { + char * log = (char*)alloca(ret+1); + CNFGglGetShaderInfoLog(fragment_shader_object, ret, NULL, log); + fprintf( stderr, "%s", log); + } + goto fail; + } + + program = CNFGglCreateProgram(); + if (!program) { + fprintf( stderr, "Error: failed to create program!\n"); + goto fail; + } + + CNFGglAttachShader(program, vertex_shader_object); + CNFGglAttachShader(program, fragment_shader_object); + + CNFGglBindAttribLocation(program, 0, "a0"); + CNFGglBindAttribLocation(program, 1, "a1"); + + CNFGglLinkProgram(program); + + CNFGglGetProgramiv(program, GL_LINK_STATUS, &ret); + if (!ret) { + fprintf( stderr, "Error: program linking failed!\n"); + CNFGglGetProgramiv(program, GL_INFO_LOG_LENGTH, &ret); + + if (ret > 1) { + //TODO: Refactor to remove malloc reliance. + #ifndef __clang__ + char *log = (char*)alloca(ret); + CNFGglGetProgramInfoLog(program, ret, NULL, log); + fprintf( stderr, "%s", log); + #endif + } + goto fail; + } + return program; +fail: + if( !vertex_shader_object ) CNFGglDeleteShader( vertex_shader_object ); + if( !fragment_shader_object ) CNFGglDeleteShader( fragment_shader_object ); + if( !program ) CNFGglDeleteShader( program ); + return -1; +} + +#if defined( CNFGEWGL ) && !defined( CNFG_NO_PRECISION ) +#define PRECISIONA "lowp" +#define PRECISIONB "mediump" +#else +#define PRECISIONA +#define PRECISIONB +#endif + +void CNFGSetupBatchInternal() +{ + short w, h; + + CNFGLoadExtensionsInternal(); + + CNFGGetDimensions( &w, &h ); + + gRDShaderProg = CNFGGLInternalLoadShader( + "uniform vec4 xfrm;" + "attribute vec3 a0;" + "attribute vec4 a1;" + "varying " PRECISIONA " vec4 vc;" + "void main() { gl_Position = vec4( a0.xy*xfrm.xy+xfrm.zw, a0.z, 0.5 ); vc = a1; }", + + "varying " PRECISIONA " vec4 vc;" + "void main() { gl_FragColor = vec4(vc.abgr); }" + ); + + CNFGglUseProgram( gRDShaderProg ); + gRDShaderProgUX = CNFGglGetUniformLocation ( gRDShaderProg , "xfrm" ); + + + gRDBlitProg = CNFGGLInternalLoadShader( + "uniform vec4 xfrm;" + "attribute vec3 a0;" + "attribute vec4 a1;" + "varying " PRECISIONB " vec2 tc;" + "void main() { gl_Position = vec4( a0.xy*xfrm.xy+xfrm.zw, a0.z, 0.5 ); tc = a1.xy; }", + + "varying " PRECISIONB " vec2 tc;" + "uniform sampler2D tex;" + "void main() { gl_FragColor = texture2D(tex,tc)." + +#if !defined( CNFGRASTERIZER ) +"wzyx" +#else +"wxyz" +#endif +";}" ); + + CNFGglUseProgram( gRDBlitProg ); + gRDBlitProgUX = CNFGglGetUniformLocation ( gRDBlitProg , "xfrm" ); + gRDBlitProgUT = CNFGglGetUniformLocation ( gRDBlitProg , "tex" ); + glGenTextures( 1, &gRDBlitProgTex ); + + CNFGglEnableVertexAttribArray(0); + CNFGglEnableVertexAttribArray(1); + + glDisable(GL_DEPTH_TEST); + glDepthMask( GL_FALSE ); + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + CNFGVertPlace = 0; +} + +#ifndef CNFGRASTERIZER +void CNFGInternalResize(short x, short y) +#else +void CNFGInternalResizeOGLBACKEND(short x, short y) +#endif +{ + glViewport( 0, 0, x, y ); + gRDLastResizeW = x; + gRDLastResizeH = y; + if (gRDShaderProg == 0xFFFFFFFF) { return; } // Prevent trying to set uniform if the shader isn't ready yet. + CNFGglUseProgram( gRDShaderProg ); + CNFGglUniform4f( gRDShaderProgUX, 1.f/x, -1.f/y, -0.5f, 0.5f); +} + +void CNFGEmitBackendTriangles( const float * vertices, const uint32_t * colors, int num_vertices ) +{ + CNFGglUseProgram( gRDShaderProg ); + CNFGglUniform4f( gRDShaderProgUX, 1.f/gRDLastResizeW, -1.f/gRDLastResizeH, -0.5f, 0.5f); + CNFGglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); + CNFGglVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); + glDrawArrays( GL_TRIANGLES, 0, num_vertices); +} + + + +#ifdef CNFGRASTERIZER +void CNFGBlitImageInternal( uint32_t * data, int x, int y, int w, int h ) +#else +void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) +#endif +{ + glEnable( GL_TEXTURE_2D ); + CNFGglActiveTexture( 0 ); + glBindTexture( GL_TEXTURE_2D, gRDBlitProgTex ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data ); + + CNFGBlitTex( gRDBlitProgTex, x, y, w, h ); +} + +#ifndef CNFGRASTERIZER + +void CNFGClearFrame() +{ + glClearColor( ((CNFGBGColor&0xff000000)>>24)/255.0f, + ((CNFGBGColor&0xff0000)>>16)/255.0f, + (CNFGBGColor&0xff00)/65280.0f, + (CNFGBGColor&0xff)/255.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); +} + +#endif + +// this is here, so people don't have to include opengl +void CNFGDeleteTex( unsigned int tex ) +{ + glDeleteTextures(1, &tex); +} + +unsigned int CNFGTexImage( uint32_t *data, int w, int h ) +{ + GLuint tex; + + glGenTextures(1, &tex); + glEnable( GL_TEXTURE_2D ); + CNFGglActiveTexture( 0 ); + glBindTexture( GL_TEXTURE_2D, tex ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data ); + + return (unsigned int)tex; +} + +void CNFGBlitTex( unsigned int tex, int x, int y, int w, int h ) +{ + if( w == 0 || h == 0 ) return; + + CNFGFlushRender(); + + CNFGglUseProgram( gRDBlitProg ); + CNFGglUniform4f( gRDBlitProgUX, + 1.f/gRDLastResizeW, -1.f/gRDLastResizeH, + -0.5f+x/(float)gRDLastResizeW, 0.5f-y/(float)gRDLastResizeH ); + CNFGglUniform1i( gRDBlitProgUT, 0 ); + + glBindTexture(GL_TEXTURE_2D, tex); + + const float verts[] = { + 0,0, (float)w,0, (float)w,(float)h, + 0,0, (float)w,(float)h, 0,(float)h, }; + static const uint8_t tex_verts[] = { + 0,0, 255,0, 255,255, + 0,0, 255,255, 0,255 }; + + CNFGglVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + CNFGglVertexAttribPointer(1, 2, GL_UNSIGNED_BYTE, GL_TRUE, 0, tex_verts); + + glDrawArrays( GL_TRIANGLES, 0, 6); +} + +void CNFGSetScissors( int * xywh ) +{ + CNFGFlushRender(); + glEnable( GL_SCISSOR_TEST ); + glScissor( xywh[0], xywh[1], xywh[2], xywh[3] ); +} + +void CNFGGetScissors( int * xywh ) +{ + CNFGFlushRender(); + glGetIntegerv( GL_SCISSOR_BOX, xywh ); +} + +#endif // CNFG_WASM diff --git a/CNFGWinDriver.c b/CNFGWinDriver.c index 9a82987..190ae50 100644 --- a/CNFGWinDriver.c +++ b/CNFGWinDriver.c @@ -48,17 +48,17 @@ static short CNFGBufferx, CNFGBuffery; static void InternalHandleResize(); #endif +#ifdef CNFG_BATCH +static void InternalHandleResize() { } +#endif #ifdef CNFGOGL #include static HGLRC hRC=NULL; -static void InternalHandleResize() { } void CNFGSwapBuffers() { -#ifdef CNFG_BATCH #ifndef CNFGCONTEXTONLY CNFGFlushRender(); -#endif #endif SwapBuffers(CNFGlsWindowHDC); @@ -128,7 +128,7 @@ void CNFGGetDimensions( short * x, short * y ) *y = CNFGBuffery; } -#ifndef CNFGOGL +#ifndef CNFG_BATCH void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) { RECT r; @@ -422,7 +422,7 @@ int CNFGHandleInput() return !ShouldClose; } -#ifndef CNFGOGL +#ifndef CNFG_BATCH #ifndef CNFGRASTERIZER diff --git a/CNFGXDriver.c b/CNFGXDriver.c index 1ca4b33..323eaa0 100644 --- a/CNFGXDriver.c +++ b/CNFGXDriver.c @@ -559,6 +559,7 @@ void CNFGSwapBuffers() #else //CNFGOGL +#ifndef CNFG_BATCH #ifndef CNFGRASTERIZER void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) { @@ -593,9 +594,10 @@ void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) XPutImage(CNFGDisplay, CNFGWindow, CNFGWindowGC, xi, 0, 0, 0, 0, w, h ); } +#endif #endif //CNFGOGL -#if !defined( CNFGOGL) +#if !defined( CNFG_BATCH ) #define AGLF(x) x #else #define AGLF(x) static inline BACKEND_##x diff --git a/Makefile b/Makefile index 4b9d672..244e20c 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ all : rawdraw simple rawdraw_sf.h # are incompatible. -MINGW32:=/usr/bin/i686-w64-mingw32 +MINGW32:=/usr/bin/i686-w64-mingw32- rawdraw-clang.exe: rawdraw.c clang rawdraw.c -o rawdraw-clang.exe -g -O1 -Irawdraw -lopengl32 -lgdi32 -luser32 @@ -62,7 +62,7 @@ rawdraw_sf.h : tools/single_file_creator CNFG.h tools/rawdraw_http_page.h echo "//This file was automatically generated by Makefile at https://github.com/cntools/rawdraw" > $@ echo "//This single-file feature is still in early alpha testing." >> $@f echo "//Generated from files git hash $(shell git rev-parse HEAD) on $(shell date) (This is not the git hash of this file)" >> $@ - ./tools/single_file_creator CNFG.h CNFG.c CNFGWinDriver.c CNFGEGLLeanAndMean.c CNFGRasterizer.c CNFGEGLDriver.c CNFGWASMDriver.c CNFGXDriver.c CNFGFunctions.c CNFG3D.c CNFGAndroid.h CNFGHTTP.c tools/rawdraw_http_page.h >> $@ + ./tools/single_file_creator CNFG.h CNFG.c CNFGWinDriver.c CNFGEGLLeanAndMean.c CNFGRasterizer.c CNFGEGLDriver.c CNFGWASMDriver.c CNFGXDriver.c CNFGFunctions.c CNFGOGL.c CNFG3D.c CNFGAndroid.h CNFGHTTP.c tools/rawdraw_http_page.h >> $@ clean : rm -rf *.o *~ simple simple.exe rawdraw.exe rawdrawogl.exe rawdraw rawdraw_ogl rawdraw_mac rawdraw_mac_soft rawdraw_mac_cg rawdraw_mac_ogl ogltest ogltest.exe rawdraw_egl rawdraw_http rawdraw_sf.h rawdraw_sf.hf tools/single_file_creator tools/binary_to_buffer tools/rawdraw_http_page.h diff --git a/rawdraw_sf.h b/rawdraw_sf.h index 68f0ab5..4580ce1 100644 --- a/rawdraw_sf.h +++ b/rawdraw_sf.h @@ -1,5 +1,5 @@ //This file was automatically generated by Makefile at https://github.com/cntools/rawdraw -//Generated from files git hash 4775c42d1e2766f25a1407e7e3c69c153d99f302 on Tue Jul 29 10:35:19 AM EDT 2025 (This is not the git hash of this file) +//Generated from files git hash 65771c7a8c6c970449f5c520874d3e54b585e7d0 on Wed Jul 30 10:52:38 AM EDT 2025 (This is not the git hash of this file) // Copyright 2010-2021 <>< CNLohr, et. al. (Several other authors, many but not all mentioned) // Licensed under the MIT/x11 or NewBSD License you choose. // @@ -3787,17 +3787,17 @@ static short CNFGBufferx, CNFGBuffery; static void InternalHandleResize(); #endif +#ifdef CNFG_BATCH +static void InternalHandleResize() { } +#endif #ifdef CNFGOGL #include static HGLRC hRC=NULL; -static void InternalHandleResize() { } void CNFGSwapBuffers() { -#ifdef CNFG_BATCH #ifndef CNFGCONTEXTONLY CNFGFlushRender(); -#endif #endif SwapBuffers(CNFGlsWindowHDC); @@ -3867,7 +3867,7 @@ void CNFGGetDimensions( short * x, short * y ) *y = CNFGBuffery; } -#ifndef CNFGOGL +#ifndef CNFG_BATCH void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) { RECT r; @@ -4161,7 +4161,7 @@ int CNFGHandleInput() return !ShouldClose; } -#ifndef CNFGOGL +#ifndef CNFG_BATCH #ifndef CNFGRASTERIZER @@ -6207,6 +6207,7 @@ void CNFGSwapBuffers() #else //CNFGOGL +#ifndef CNFG_BATCH #ifndef CNFGRASTERIZER void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) { @@ -6241,9 +6242,10 @@ void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) XPutImage(CNFGDisplay, CNFGWindow, CNFGWindowGC, xi, 0, 0, 0, 0, w, h ); } +#endif #endif //CNFGOGL -#if !defined( CNFGOGL) +#if !defined( CNFG_BATCH ) #define AGLF(x) x #else #define AGLF(x) static inline BACKEND_##x @@ -7127,6 +7129,51 @@ void CNFGSetLineWidth( short width ) #endif +#if !defined( CNFG_WASM ) && !defined( CNFGHTTP ) + +void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) +{ +#ifdef CNFGRASTERIZER + CNFGBlitImageInternal( data, 0, 0, w, h ); + void CNFGSwapBuffersInternal(); + CNFGSwapBuffersInternal(); +#else + CNFGBlitImage( data, 0, 0, w, h ); +#endif +} + +#ifndef CNFGRASTERIZER + +void CNFGFlushRender() +{ + if( !CNFGVertPlace ) return; + CNFGEmitBackendTriangles( CNFGVertDataV, CNFGVertDataC, CNFGVertPlace ); + CNFGVertPlace = 0; +} + +#endif + +#endif // CNFG_WASM + +#else + +void CNFGFlushRender() { } + +#endif + + +#endif +#endif // CNFGHTTPSERVERONLY +#endif //_CNFG_C + + +#ifdef CNFGOGL +//Copyright (c) 2010-2025 <>< Charles Lohr, and several others! +// Licensed under the MIT/x11 or NewBSD License you choose. +// +// OpenGL Renderer (platform independent portions) + + #if !defined( CNFG_WASM ) && !defined( CNFGHTTP ) //In WASM, Javascript takes over this functionality. @@ -7506,7 +7553,40 @@ void CNFGEmitBackendTriangles( const float * vertices, const uint32_t * colors, } -#ifdef CNFGOGL + +#ifdef CNFGRASTERIZER +void CNFGBlitImageInternal( uint32_t * data, int x, int y, int w, int h ) +#else +void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) +#endif +{ + glEnable( GL_TEXTURE_2D ); + CNFGglActiveTexture( 0 ); + glBindTexture( GL_TEXTURE_2D, gRDBlitProgTex ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data ); + + CNFGBlitTex( gRDBlitProgTex, x, y, w, h ); +} + +#ifndef CNFGRASTERIZER + +void CNFGClearFrame() +{ + glClearColor( ((CNFGBGColor&0xff000000)>>24)/255.0f, + ((CNFGBGColor&0xff0000)>>16)/255.0f, + (CNFGBGColor&0xff00)/65280.0f, + (CNFGBGColor&0xff)/255.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); +} + +#endif + // this is here, so people don't have to include opengl void CNFGDeleteTex( unsigned int tex ) { @@ -7573,73 +7653,10 @@ void CNFGGetScissors( int * xywh ) glGetIntegerv( GL_SCISSOR_BOX, xywh ); } -#endif - -#ifdef CNFGRASTERIZER -void CNFGBlitImageInternal( uint32_t * data, int x, int y, int w, int h ) -#else -void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) -#endif -{ - glEnable( GL_TEXTURE_2D ); - CNFGglActiveTexture( 0 ); - glBindTexture( GL_TEXTURE_2D, gRDBlitProgTex ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, - GL_UNSIGNED_BYTE, data ); - - CNFGBlitTex( gRDBlitProgTex, x, y, w, h ); -} - -void CNFGUpdateScreenWithBitmap( uint32_t * data, int w, int h ) -{ -#ifdef CNFGRASTERIZER - CNFGBlitImageInternal( data, 0, 0, w, h ); - void CNFGSwapBuffersInternal(); - CNFGSwapBuffersInternal(); -#else - CNFGBlitImage( data, 0, 0, w, h ); -#endif -} - -#ifndef CNFGRASTERIZER - -void CNFGFlushRender() -{ - if( !CNFGVertPlace ) return; - CNFGEmitBackendTriangles( CNFGVertDataV, CNFGVertDataC, CNFGVertPlace ); - CNFGVertPlace = 0; -} - -void CNFGClearFrame() -{ - glClearColor( ((CNFGBGColor&0xff000000)>>24)/255.0f, - ((CNFGBGColor&0xff0000)>>16)/255.0f, - (CNFGBGColor&0xff00)/65280.0f, - (CNFGBGColor&0xff)/255.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); -} - -#endif - #endif // CNFG_WASM -#else - -void CNFGFlushRender() { } - #endif - -#endif -#endif // CNFGHTTPSERVERONLY -#endif //_CNFG_C - - #ifdef CNFG3D //Copyright 2012-2017 <>< Charles Lohr //You may license this file under the MIT/x11, NewBSD, or any GPL license. From 6370267a6e55d33910a73d009f5ebec8e6ef4a7e Mon Sep 17 00:00:00 2001 From: Kylogias <45217130+Kylogias@users.noreply.github.com> Date: Sat, 16 Aug 2025 10:59:49 -0400 Subject: [PATCH 2/2] Feature Complete Vulkan support --- .gitignore | 3 + CNFG.c | 6 + CNFG.h | 17 +- CNFGFunctions.c | 8 +- CNFGOGL.c | 75 ++-- CNFGVK.c | 754 +++++++++++++++++++++++++++++++ CNFGWinDriver.c | 13 + CNFGXDriver.c | 13 + Makefile | 22 +- README.md | 7 +- rawdraw_sf.h | 1035 +++++++++++++++++++++++++++++++++++++++++-- vk/cnfg.glsl | 62 +++ vk/cnfgshader.h | 148 +++++++ vk/shadertemplate.h | 17 + 14 files changed, 2092 insertions(+), 88 deletions(-) create mode 100644 CNFGVK.c create mode 100644 vk/cnfg.glsl create mode 100644 vk/cnfgshader.h create mode 100644 vk/shadertemplate.h diff --git a/.gitignore b/.gitignore index 5dd26fe..a672a89 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ TextTool/text ogltest rawdraw rawdraw_ogl +rawdraw_vk simple examples/fontsize examples/fontsize_ogl @@ -15,3 +16,5 @@ tools/binary_to_buffer tools/single_file_creator tools/rawdraw_http_page.h rawdraw_sf.hf + +vk/*temp diff --git a/CNFG.c b/CNFG.c index 9dcbd41..023795e 100644 --- a/CNFG.c +++ b/CNFG.c @@ -26,6 +26,12 @@ int CNFGLastScancode = 0; #include "CNFGOGL.c" #endif +#ifdef CNFGVK +#ifndef CNFGCONTEXTONLY +#include "CNFGVK.c" +#endif +#endif + #ifdef CNFG3D #include "CNFG3D.c" #endif diff --git a/CNFG.h b/CNFG.h index 7bc69a6..719c746 100644 --- a/CNFG.h +++ b/CNFG.h @@ -18,6 +18,9 @@ extern "C" { CNFG_USE_DOUBLE_FUNCTIONS -> Use double-precision floating point for CNFG3D. CNFGOGL -> Use an OpenGL Backend for all rawdraw functionality. ->Caveat->If using CNFG_HAS_XSHAPE, then, we do something realy wacky. + CNFGVK -> Use the experimental Vulkan backend + CNFGVK_VALIDATION_LAYERS -> Enable the validation layers of the batched renderer + CNFGVK_IMAGE_ALLOCATION -> Specify the amount of VRAM allocated towards images in the batched renderer CNFGRASTERIZER -> Software-rasterize the rawdraw calls, and, use CNFGUpdateScreenWithBitmap to send video to webpage. CNFGCONTEXTONLY -> Don't add any drawing functions, only opening a window to @@ -73,6 +76,15 @@ Usually tested combinations: #endif #endif +#ifdef CNFGVK + #define CNFG_BATCH 8192 + + #include + + // The drivers define the CNFG_SURFACE_EXTENSION macro for their required extensions + VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ); +#endif + typedef struct { short x, y; } RDPoint; @@ -111,6 +123,10 @@ void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ); void CNFGDeleteTex( unsigned int tex ); unsigned int CNFGTexImage( uint32_t *data, int w, int h ); void CNFGBlitTex( unsigned int tex, int x, int y, int w, int h ); +#endif + +#if defined( CNFGOGL ) || defined( CNFGVK ) +void CNFGSetVSync( int vson ); // Not supported on all systems void CNFGSetScissors( int * xywh ); void CNFGGetScissors( int * xywh ); #endif @@ -156,7 +172,6 @@ void CNFGInternalResize( short x, short y ); //don't call this. //Not available on all systems. Use The OGL portion with care. #ifdef CNFGOGL -void CNFGSetVSync( int vson ); void * CNFGGetExtension( const char * extname ); #endif diff --git a/CNFGFunctions.c b/CNFGFunctions.c index 84dec79..25da460 100644 --- a/CNFGFunctions.c +++ b/CNFGFunctions.c @@ -349,7 +349,7 @@ uint32_t CNFGVertDataC[CNFG_BATCH]; int CNFGVertPlace; static float wgl_last_width_over_2 = .5f; -static void EmitQuad( float cx0, float cy0, float cx1, float cy1, float cx2, float cy2, float cx3, float cy3 ) +void CNFGEmitQuad( float cx0, float cy0, float cx1, float cy1, float cx2, float cy2, float cx3, float cy3 ) { //Because quads are really useful, but it's best to keep them all triangles if possible. //This lets us draw arbitrary quads. @@ -375,7 +375,7 @@ void CNFGTackPixel( short x1, short y1 ) x1++; y1++; const float l2 = wgl_last_width_over_2; const float l2u = wgl_last_width_over_2+0.5f; - EmitQuad( x1-l2u, y1-l2u, x1+l2, y1-l2u, x1-l2u, y1+l2, x1+l2, y1+l2 ); + CNFGEmitQuad( x1-l2u, y1-l2u, x1+l2, y1-l2u, x1-l2u, y1+l2, x1+l2, y1+l2 ); } @@ -400,7 +400,7 @@ void CNFGTackSegment( short x1, short y1, short x2, short y2 ) iy1 -= dy/2 - 0.5f; //This logic is incorrect. XXX FIXME. - EmitQuad( (ix1 - orthox), (iy1 - orthoy), (ix1 + orthox), (iy1 + orthoy), (ix2 - orthox), (iy2 - orthoy), ( ix2 + orthox), ( iy2 + orthoy) ); + CNFGEmitQuad( (ix1 - orthox), (iy1 - orthoy), (ix1 + orthox), (iy1 + orthoy), (ix2 - orthox), (iy2 - orthoy), ( ix2 + orthox), ( iy2 + orthoy) ); } void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) @@ -409,7 +409,7 @@ void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) float iy1 = y1; float ix2 = x2; float iy2 = y2; - EmitQuad( ix1,iy1,ix2,iy1,ix1,iy2,ix2,iy2 ); + CNFGEmitQuad( ix1,iy1,ix2,iy1,ix1,iy2,ix2,iy2 ); } void CNFGTackPoly( RDPoint * points, int verts ) diff --git a/CNFGOGL.c b/CNFGOGL.c index 17961a4..59b0ede 100644 --- a/CNFGOGL.c +++ b/CNFGOGL.c @@ -29,6 +29,44 @@ #include #endif +#if defined(CNFGCONTEXTONLY) || defined(CNFGOGL_NEED_EXTENSION) +#ifdef CNFG_WINDOWS + +//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions +void * CNFGGetProcAddress(const char *name) +{ + void *p = (void *)wglGetProcAddress(name); + if(p == 0 || + (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || + (p == (void*)-1) ) + { + static HMODULE module; + if( !module ) module = LoadLibraryA("opengl32.dll"); + p = (void *)GetProcAddress(module, name); + } + // We were unable to load the required openGL function + if (!p) { + fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); + } + return p; +} + +#else +#include + + +void * CNFGGetProcAddress(const char *name) +{ + //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. + void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); + //printf( "%s = %p\n", name, v1 ); + if( !v1 ) v1 = dlsym( 0, name ); + return v1; +} + +#endif +#endif + #ifdef CNFGOGL_NEED_EXTENSION // If we are going to be defining our own function pointer call #ifdef CNFG_WINDOWS @@ -47,6 +85,7 @@ ret name (__VA_ARGS__); #endif +#ifndef CNFGCONTEXTONLY #ifdef __cplusplus extern "C" { @@ -104,41 +143,6 @@ CHEWTYPEDEF( void, glActiveTexture, , (texture), GLenum texture ) #endif #ifdef CNFGOGL_NEED_EXTENSION -#ifdef CNFG_WINDOWS - -//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions -void * CNFGGetProcAddress(const char *name) -{ - void *p = (void *)wglGetProcAddress(name); - if(p == 0 || - (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || - (p == (void*)-1) ) - { - static HMODULE module; - if( !module ) module = LoadLibraryA("opengl32.dll"); - p = (void *)GetProcAddress(module, name); - } - // We were unable to load the required openGL function - if (!p) { - fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); - } - return p; -} - -#else -#include - - -void * CNFGGetProcAddress(const char *name) -{ - //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. - void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); - //printf( "%s = %p\n", name, v1 ); - if( !v1 ) v1 = dlsym( 0, name ); - return v1; -} - -#endif // Try and load openGL extension functions required for rawdraw static void CNFGLoadExtensionsInternal() @@ -484,4 +488,5 @@ void CNFGGetScissors( int * xywh ) glGetIntegerv( GL_SCISSOR_BOX, xywh ); } +#endif // CNFGCONTEXTONLY #endif // CNFG_WASM diff --git a/CNFGVK.c b/CNFGVK.c new file mode 100644 index 0000000..ec1d28e --- /dev/null +++ b/CNFGVK.c @@ -0,0 +1,754 @@ +//Copyright (c) 2010-2025 <>< Charles Lohr, and several others! +// Licensed under the MIT/x11 or NewBSD License you choose. +// +// Vulkan Batched Renderer + +#include +#include +#include +#include +#include + +#include "vk/cnfgshader.h" + +#ifndef CNFGVK +#define CNFGVK +#define CNFG_BATCH 8192 +#define CNFG_SURFACE_EXTENSION "" +#define CNFGVK_VALIDATION_LAYERS + +#include "CNFG.h" +#endif + +#ifndef CNFGVK_FRAMES_IN_FLIGHT +#define CNFGVK_FRAMES_IN_FLIGHT 3 +#endif + +#ifndef CNFGVK_IMAGE_ALLOCATION +// Enough memory for a 4k framebuffer. As this is a huge upper limit, it can be redefined +#define CNFGVK_IMAGE_ALLOCATION 32*1024*1024 +#endif + +#define CNFGVK_BATCH_SIZE ( sizeof( CNFGVertDataC ) + sizeof( CNFGVertDataV ) + sizeof( float[4] ) ) +#define CNFG_LOAD_FUNC( var, name ) PFN_##name var = (PFN_##name)vkGetInstanceProcAddr( CNFGVkInstance, #name ) + +static VkInstance CNFGVkInstance = NULL; +static VkPhysicalDevice CNFGPhysicalDevice = NULL; +static VkDevice CNFGLogicalDevice = NULL; +static VkQueue CNFGGraphicsQueue = NULL; +static VkQueue CNFGPresentQueue = NULL; +static VkSurfaceKHR CNFGVkSurface = NULL; + +static VkSwapchainKHR CNFGSwapchain = NULL; +static VkExtent2D CNFGSwapchainExtent = { 0 }; +static VkImage* CNFGSwapchainImages = NULL; +static VkImageView* CNFGSwapchainViews = NULL; +static uint32_t CNFGSwapchainImageCount = 0; +static VkFormat CNFGSwapchainFormat = 0; + +static VkPipelineLayout CNFGPipelineLayout = NULL; +static VkPipeline CNFGBatchPipeline = NULL; +static VkPipeline CNFGImagePipeline = NULL; +static VkCommandPool CNFGGraphicsPool = NULL; +static VkCommandBuffer CNFGGraphicsCommands[CNFGVK_FRAMES_IN_FLIGHT] = { NULL }; + +static VkSemaphore* CNFGPresentSemas = NULL; +static VkSemaphore* CNFGRenderSemas = NULL; +static VkFence CNFGRenderFences[CNFGVK_FRAMES_IN_FLIGHT] = { NULL }; + +static VkDescriptorSetLayout CNFGDescriptorSetLayout = NULL; +static VkDescriptorPool CNFGDescriptorPool = NULL; +static VkDescriptorSet CNFGDescriptorSet = NULL; + +static VkBuffer CNFGBatchBuffer = NULL; +static VkCommandBuffer CNFGBatchCommand = NULL; +static VkFence CNFGBatchFence = NULL; +static VkImage CNFGImage = NULL; +static VkImageView CNFGImageView = NULL; +static VkDeviceMemory CNFGBatchMemory = NULL; +static void* CNFGBatchMap = NULL; + +static VkDeviceMemory CNFGImageMemory = NULL; +static void* CNFGImageMap = NULL; +static VkSampler CNFGSampler = NULL; + +static uint32_t CNFGCurSwapchainImage = -1; +static int CNFGCurFlight = 0; +static int CNFGCurSema = 0; +static int CNFGScissors[4] = { -1 }; +static int CNFGVSyncOn = 1; + +static const char * CNFGInstanceExtensions[] = { +#ifdef CNFGVK_VALIDATION_LAYERS + "VK_EXT_debug_utils", +#endif + CNFG_SURFACE_EXTENSION +}; +#define CNFG_NUM_INSTANCE_EXT sizeof(CNFGInstanceExtensions)/sizeof(*CNFGInstanceExtensions) + +static const char * CNFGDeviceExtensions[] = { "VK_KHR_swapchain" }; +#define CNFG_NUM_DEVICE_EXT sizeof(CNFGDeviceExtensions)/sizeof(*CNFGDeviceExtensions) + +#ifdef CNFGVK_VALIDATION_LAYERS +static const char * CNFGInstanceLayers[] = { "VK_LAYER_KHRONOS_validation" }; +#define CNFG_NUM_INSTANCE_LAYER sizeof(CNFGInstanceLayers)/sizeof(*CNFGInstanceLayers) + +static VkDebugUtilsMessengerEXT CNFGDebugMessenger = NULL; +static VkBool32 VKAPI_CALL CNFGDebugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData, + void* pUserData +) +{ + // Change the color of the terminal to reflect the severity of the message + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ) printf( "\x1B[2;44m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ) printf( "\x1B[40m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) printf( "\x1B[43m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ) printf( "\x1B[41;30m" ); + + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT ) printf( "GENERAL: " ); + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT ) printf( "VALIDATION: " ); + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ) printf( "PERFORMANCE: " ); + + printf( "%s\x1B[0m\n", pCallbackData->pMessage ); + + return VK_FALSE; +} + +#endif + +static int CNFGScorePhysicalDevice( VkPhysicalDevice dev, uint32_t * didx, uint32_t * pidx ) +{ + VkPhysicalDeviceProperties prop; + vkGetPhysicalDeviceProperties( dev, &prop ); + + uint32_t score = 0, api = prop.apiVersion; + printf( "Device Name: %s, API Version: %i.%i.%i\n", prop.deviceName, VK_VERSION_MAJOR( api ), VK_VERSION_MINOR( api ), VK_VERSION_PATCH( api ) ); + if ( api < VK_VERSION_1_3 ) return -100000; + if ( prop.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ) score += 5000; + + VkQueueFamilyProperties* qfp = NULL; + uint32_t qfc = 0; + vkGetPhysicalDeviceQueueFamilyProperties( dev, &qfc, NULL ); + qfp = alloca( qfc * sizeof(VkQueueFamilyProperties) ); + vkGetPhysicalDeviceQueueFamilyProperties( dev, &qfc, qfp ); + for ( int i = 0; i < qfc; i++ ) + { + VkBool32 support = VK_FALSE; + if ( qfp[i].queueFlags & VK_QUEUE_GRAPHICS_BIT ) + { + *didx = i; + } + vkGetPhysicalDeviceSurfaceSupportKHR( dev, i, CNFGVkSurface, &support ); + if ( support ) *pidx = i; + if ( *didx != -1 && *pidx != -1 ) break; + } + + if ( *didx == *pidx ) score += 1000; + if ( *pidx == -1 ) return -100001; + + return score; +} + +#define CREATE_MODULE(var, name) \ + VkShaderModuleCreateInfo CI_##var = { \ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .pNext = NULL, \ + .codeSize = sizeof( name ), .pCode = name \ + }; \ + vkCreateShaderModule( CNFGLogicalDevice, &CI_##var, NULL, &var ); + +static void CNFGCreatePipelines() +{ + VkShaderModule vert, batch, img; + CREATE_MODULE( vert, CNFGVertShader ); + CREATE_MODULE( batch, CNFGBatchShader ); + CREATE_MODULE( img, CNFGImageShader ); + + VkPipelineShaderStageCreateInfo psci[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, + .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = vert, .pName = "main" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = batch, .pName = "main" + } + }; + + static const VkDynamicState dynstates[] = { + VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamic = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .pNext = NULL, + .pDynamicStates = dynstates, .dynamicStateCount = sizeof( dynstates ) / sizeof( *dynstates ) + }; + VkPipelineVertexInputStateCreateInfo vinp = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pNext = NULL + }; + VkPipelineInputAssemblyStateCreateInfo inpasm = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = NULL, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST + }; + VkPipelineViewportStateCreateInfo vp = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = NULL, + .pViewports = NULL, .pScissors = NULL, .scissorCount = 1, .viewportCount = 1 + }; + VkPipelineRasterizationStateCreateInfo rast = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = NULL, + .polygonMode = VK_POLYGON_MODE_FILL, .lineWidth = 1 + }; + VkPipelineMultisampleStateCreateInfo msaa = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = NULL, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, .sampleShadingEnable = VK_FALSE + }; + VkPipelineColorBlendAttachmentState batt = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_TRUE, .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA + }; + VkPipelineColorBlendStateCreateInfo blend = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .pNext = NULL, + .logicOpEnable = VK_FALSE, .logicOp = VK_LOGIC_OP_COPY, .attachmentCount = 1, .pAttachments = &batt + }; + + VkDescriptorSetLayoutBinding desc[] = { + { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT }, + { .binding = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT }, + { .binding = 2, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT } + }; + + VkDescriptorSetLayoutCreateInfo dci = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = sizeof(desc)/sizeof(*desc), .pBindings = desc + }; + + vkCreateDescriptorSetLayout( CNFGLogicalDevice, &dci, NULL, &CNFGDescriptorSetLayout ); + + VkPipelineLayoutCreateInfo lci = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 1, .pSetLayouts = &CNFGDescriptorSetLayout }; + vkCreatePipelineLayout( CNFGLogicalDevice, &lci, NULL, &CNFGPipelineLayout ); + + VkPipelineRenderingCreateInfo rend = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, .pNext = NULL, + .colorAttachmentCount = 1, .pColorAttachmentFormats = &CNFGSwapchainFormat + }; + VkGraphicsPipelineCreateInfo batci = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = &rend, + .stageCount = 2, .pStages = psci, .pVertexInputState = &vinp, .pInputAssemblyState = &inpasm, + .pViewportState = &vp, .pRasterizationState = &rast, .pMultisampleState = &msaa, + .pColorBlendState = &blend, .pDynamicState = &dynamic, .layout = CNFGPipelineLayout, + .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = -1, + }; + vkCreateGraphicsPipelines( CNFGLogicalDevice, NULL, 1, &batci, NULL, &CNFGBatchPipeline ); + + psci[1].module = img; + vkCreateGraphicsPipelines( CNFGLogicalDevice, NULL, 1, &batci, NULL, &CNFGImagePipeline ); +} + +static void CNFGDestroySwapchain() +{ + vkDeviceWaitIdle( CNFGLogicalDevice ); + for (int i = 0; i < CNFGSwapchainImageCount; i++ ) + { + vkDestroyImageView( CNFGLogicalDevice, CNFGSwapchainViews[i], NULL ); + vkDestroySemaphore( CNFGLogicalDevice, CNFGRenderSemas[i], NULL ); + vkDestroySemaphore( CNFGLogicalDevice, CNFGPresentSemas[i], NULL ); + } + vkDestroySwapchainKHR( CNFGLogicalDevice, CNFGSwapchain, NULL ); + free( CNFGSwapchainImages ); + free( CNFGSwapchainViews ); +} + +static void CNFGCreateSwapchain() +{ + VkSurfaceCapabilitiesKHR sc = { 0 }; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR( CNFGPhysicalDevice, CNFGVkSurface, &sc ); + + VkSurfaceFormatKHR formats[256] = {0}; + uint32_t numFormat = 256; + VkPresentModeKHR presentModes[256] = {0}; + uint32_t numPresent = 256; + int fmtIdx = 0; + VkPresentModeKHR present = -1; + vkGetPhysicalDeviceSurfaceFormatsKHR( CNFGPhysicalDevice, CNFGVkSurface, &numFormat, formats ); + vkGetPhysicalDeviceSurfacePresentModesKHR( CNFGPhysicalDevice, CNFGVkSurface, &numPresent, presentModes ); + for (int i = 0; i < numFormat; i++) + { + if ( formats[i].format == VK_FORMAT_B8G8R8A8_UNORM && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ) fmtIdx = i; + } + for (int i = 0; i < numPresent; i++) + { + if ( presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR ) present = presentModes[i]; + else if ( presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR && present == -1 ) present = presentModes[i]; + } + if ( CNFGVSyncOn || (present == -1) ) present = VK_PRESENT_MODE_FIFO_KHR; + + uint32_t minImg = sc.minImageCount > 3 ? sc.minImageCount : 3; + uint32_t imgCount = sc.minImageCount + 1; + if ( sc.maxImageCount > 0 && imgCount > sc.maxImageCount ) imgCount = sc.maxImageCount; + if ( sc.maxImageCount > 0 && minImg > sc.maxImageCount ) minImg = sc.maxImageCount; + + CNFGSwapchainFormat = formats[fmtIdx].format; + CNFGSwapchainExtent = sc.currentExtent; + if ( CNFGScissors[2] > CNFGSwapchainExtent.width ) CNFGScissors[2] = CNFGSwapchainExtent.width; + if ( CNFGScissors[3] > CNFGSwapchainExtent.height ) CNFGScissors[3] = CNFGSwapchainExtent.height; + + VkSwapchainCreateInfoKHR scci = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = NULL, + .flags = 0, .surface = CNFGVkSurface, .minImageCount = minImg, + .imageFormat = CNFGSwapchainFormat, .imageColorSpace = formats[fmtIdx].colorSpace, + .imageExtent = sc.currentExtent, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .preTransform = sc.currentTransform, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present, .clipped = VK_TRUE, .oldSwapchain = NULL + }; + + if ( CNFGGraphicsQueue != CNFGPresentQueue ) + { + uint32_t devdqf, devpqf; + CNFGScorePhysicalDevice( CNFGPhysicalDevice, &devdqf, &devpqf ); + uint32_t qfis[] = { devdqf, devpqf }; + + scci.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + scci.queueFamilyIndexCount = 2; + scci.pQueueFamilyIndices = qfis; + } + + vkCreateSwapchainKHR( CNFGLogicalDevice, &scci, NULL, &CNFGSwapchain ); + vkGetSwapchainImagesKHR( CNFGLogicalDevice, CNFGSwapchain, &CNFGSwapchainImageCount, NULL); + CNFGSwapchainImages = malloc( sizeof( VkImage ) * CNFGSwapchainImageCount ); + CNFGSwapchainViews = malloc( sizeof( VkImageView ) * CNFGSwapchainImageCount ); + CNFGPresentSemas = malloc( sizeof(VkSemaphore) * CNFGSwapchainImageCount ); + CNFGRenderSemas = malloc( sizeof(VkSemaphore) * CNFGSwapchainImageCount ); + vkGetSwapchainImagesKHR( CNFGLogicalDevice, CNFGSwapchain, &CNFGSwapchainImageCount, CNFGSwapchainImages); + + VkImageViewCreateInfo ivci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = NULL, + .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = CNFGSwapchainFormat, + .subresourceRange.levelCount = 1, .subresourceRange.layerCount = 1, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT + }; + + for ( int i = 0; i < CNFGSwapchainImageCount; i++ ) + { + VkSemaphoreCreateInfo sema = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + vkCreateSemaphore( CNFGLogicalDevice, &sema, NULL, &CNFGPresentSemas[i] ); + vkCreateSemaphore( CNFGLogicalDevice, &sema, NULL, &CNFGRenderSemas[i] ); + + ivci.image = CNFGSwapchainImages[i]; + vkCreateImageView( CNFGLogicalDevice, &ivci, NULL, &CNFGSwapchainViews[i] ); + } +} + +static void CNFGCreateLogicalDevice( uint32_t * o_dqf, uint32_t * o_pqf ) +{ + uint32_t numDev = 0; + VkPhysicalDevice * dev; + vkEnumeratePhysicalDevices( CNFGVkInstance, &numDev, NULL ); + dev = alloca( sizeof(VkPhysicalDevice) * numDev ); + vkEnumeratePhysicalDevices( CNFGVkInstance, &numDev, dev ); + + int devIdx = -1, devScore = -1; + uint32_t devdqf = -1, devpqf = -1; + + for ( int i = 0; i < numDev; i++ ) + { + uint32_t newdqf = -1, newpqf = -1; + int newScore = CNFGScorePhysicalDevice( dev[i], &newdqf, &newpqf ); + if ( newScore > devScore ) + { + devIdx = i; + devScore = newScore; + devdqf = newdqf; + devpqf = newpqf; + } + } + + CNFGPhysicalDevice = dev[devIdx]; + float prio = 0; + VkDeviceQueueCreateInfo dqci = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = NULL, + .queueFamilyIndex = devdqf, + .queueCount = 1, + .pQueuePriorities = &prio + }; + + VkPhysicalDeviceVulkan13Features v13 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .pNext = NULL, + .dynamicRendering = VK_TRUE, + .synchronization2 = VK_TRUE + }; + VkPhysicalDeviceFeatures2 pdf = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .features = { 0 }, .pNext = &v13 }; + VkDeviceCreateInfo dci = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &pdf, + .pQueueCreateInfos = &dqci, .queueCreateInfoCount = 1, .ppEnabledExtensionNames = CNFGDeviceExtensions, .enabledExtensionCount = CNFG_NUM_DEVICE_EXT + }; + vkCreateDevice( CNFGPhysicalDevice, &dci, NULL, &CNFGLogicalDevice ); + vkGetDeviceQueue( CNFGLogicalDevice, devdqf, 0, &CNFGGraphicsQueue ); + vkGetDeviceQueue( CNFGLogicalDevice, devpqf, 0, &CNFGPresentQueue ); + + *o_dqf = devdqf; + *o_pqf = devpqf; +} + +static void CNFGAllocateMemory( uint64_t size, uint32_t bits, VkMemoryPropertyFlags props, VkDeviceMemory* outMem ) +{ + VkPhysicalDeviceMemoryProperties mem = { 0 }; + vkGetPhysicalDeviceMemoryProperties( CNFGPhysicalDevice, &mem ); + int memType = -1; + for ( int i = 0; i < mem.memoryTypeCount; i++ ) + { + if (( bits & ( 1 << i )) && ( mem.memoryTypes[i].propertyFlags & props ) == props ) + { + memType = i; + break; + } + } + + VkMemoryAllocateInfo alloc = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .allocationSize = size, .memoryTypeIndex = memType }; + vkAllocateMemory( CNFGLogicalDevice, &alloc, NULL, outMem ); +} + +static void CNFGCreateResources() +{ + VkBufferCreateInfo bbinfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = NULL, .size = CNFGVK_BATCH_SIZE, + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + vkCreateBuffer( CNFGLogicalDevice, &bbinfo, NULL, &CNFGBatchBuffer ); + VkMemoryRequirements memReq = { 0 }; + vkGetBufferMemoryRequirements( CNFGLogicalDevice, CNFGBatchBuffer, &memReq ); + CNFGAllocateMemory( memReq.size, memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &CNFGBatchMemory ); + vkBindBufferMemory( CNFGLogicalDevice, CNFGBatchBuffer, CNFGBatchMemory, 0 ); + + CNFGAllocateMemory( CNFGVK_IMAGE_ALLOCATION, 0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &CNFGImageMemory ); + + vkMapMemory( CNFGLogicalDevice, CNFGBatchMemory, 0, CNFGVK_BATCH_SIZE, 0, &CNFGBatchMap); + vkMapMemory( CNFGLogicalDevice, CNFGImageMemory, 0, CNFGVK_IMAGE_ALLOCATION, 0, &CNFGImageMap ); + + VkDescriptorPoolSize poolsize[] = { + { .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 2 }, + { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1 } + }; + VkDescriptorPoolCreateInfo poolci = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .maxSets = 1, .poolSizeCount = 2, .pPoolSizes = poolsize }; + vkCreateDescriptorPool( CNFGLogicalDevice, &poolci, NULL, &CNFGDescriptorPool ); + + VkDescriptorSetAllocateInfo setalloc = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, .descriptorPool = CNFGDescriptorPool, + .descriptorSetCount = 1, .pSetLayouts = &CNFGDescriptorSetLayout + }; + + VkSamplerCreateInfo sampci = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .minFilter = VK_FILTER_NEAREST, .magFilter = VK_FILTER_NEAREST, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE + }; + vkCreateSampler( CNFGLogicalDevice, &sampci, NULL, &CNFGSampler ); + + VkFenceCreateInfo fci = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; + vkAllocateDescriptorSets( CNFGLogicalDevice, &setalloc, &CNFGDescriptorSet ); + VkDescriptorBufferInfo infv = { .buffer = CNFGBatchBuffer, .offset = 0, .range = sizeof( CNFGVertDataV )+sizeof( float[4] ) }; + VkDescriptorBufferInfo infc = { .buffer = CNFGBatchBuffer, .offset = sizeof( CNFGVertDataV )+sizeof( float[4] ), .range = sizeof( CNFGVertDataC ) }; + + VkWriteDescriptorSet write[] = {{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 0, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .pBufferInfo = &infv + }, { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 1, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .pBufferInfo = &infc + }}; + vkUpdateDescriptorSets( CNFGLogicalDevice, 2, write, 0, NULL); + + vkCreateFence( CNFGLogicalDevice, &fci, NULL, &CNFGBatchFence ); + + for ( int i = 0; i < CNFGVK_FRAMES_IN_FLIGHT; i++ ) + { + VkFenceCreateInfo fence = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; + vkCreateFence( CNFGLogicalDevice, &fence, NULL, &CNFGRenderFences[i] ); + } +} + +void CNFGSetupBatchInternal() +{ + VkApplicationInfo app = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = "CNFG", + .pEngineName = "CNFG", + .applicationVersion = VK_MAKE_VERSION( 0, 9, 5 ), + .engineVersion = VK_MAKE_VERSION( 0, 9, 5 ), + .apiVersion = VK_API_VERSION_1_3 + }; + + VkInstanceCreateInfo instInf = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = NULL, + .pApplicationInfo = &app, + +#ifdef CNFGVK_VALIDATION_LAYERS + .ppEnabledLayerNames = CNFGInstanceLayers, + .enabledLayerCount = CNFG_NUM_INSTANCE_LAYER, +#endif + + .ppEnabledExtensionNames = CNFGInstanceExtensions, + .enabledExtensionCount = CNFG_NUM_INSTANCE_EXT + }; + + VkResult res = vkCreateInstance( &instInf, NULL, (VkInstance*)&CNFGVkInstance ); + if (res != VK_SUCCESS) { + fprintf( stderr, "Unable to create Vulkan instance with code %i\n", res ); + exit( -1 ); + } + +#ifdef CNFGVK_VALIDATION_LAYERS + VkDebugUtilsMessengerCreateInfoEXT msgInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = NULL, + .messageSeverity = (VkDebugUtilsMessageSeverityFlagsEXT){VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}, + .messageType = (VkDebugUtilsMessageTypeFlagsEXT){VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT}, + .pfnUserCallback = CNFGDebugCallback + }; + CNFG_LOAD_FUNC( dbgmsg, vkCreateDebugUtilsMessengerEXT ); + dbgmsg( CNFGVkInstance, &msgInfo, NULL, &CNFGDebugMessenger ); +#endif + + CNFGCreateVkSurface( CNFGVkInstance, NULL, &CNFGVkSurface ); + + uint32_t devdqf, devpqf; + CNFGCreateLogicalDevice( &devdqf, &devpqf ); + CNFGCreateSwapchain(); + CNFGCreatePipelines(); + + VkCommandPoolCreateInfo cpci = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = NULL, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = devdqf + }; + vkCreateCommandPool( CNFGLogicalDevice, &cpci, NULL, &CNFGGraphicsPool ); + + VkCommandBufferAllocateInfo cbai = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, + .commandPool = CNFGGraphicsPool, .commandBufferCount = CNFGVK_FRAMES_IN_FLIGHT, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY + }; + vkAllocateCommandBuffers( CNFGLogicalDevice, &cbai, CNFGGraphicsCommands ); + cbai.commandBufferCount = 1; + vkAllocateCommandBuffers( CNFGLogicalDevice, &cbai, &CNFGBatchCommand ); + + CNFGCreateResources(); +} + +static void CNFGTransImageLayout( VkCommandBuffer cmd, VkImage img, VkImageLayout old, VkImageLayout new, VkAccessFlags2 srcf, VkAccessFlags2 dstf, VkPipelineStageFlags2 srcs, VkPipelineStageFlags2 dsts ) +{ + VkImageMemoryBarrier2 barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .pNext = NULL, + .srcStageMask = srcs, .dstStageMask = dsts, .srcAccessMask = srcf, .dstAccessMask = dstf, + .oldLayout = old, .newLayout = new, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = img, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .baseArrayLayer = 0, .layerCount = 1, .levelCount = 1 + } + }; + VkDependencyInfo dep = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .pNext = NULL, + .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier + }; + vkCmdPipelineBarrier2( cmd, &dep ); +} + +static void CNFGBeginCmd( VkCommandBuffer cmd ) +{ + VkCommandBufferBeginInfo begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = NULL, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; + vkResetCommandBuffer( cmd, 0 ); + vkBeginCommandBuffer( cmd, &begin ); +} + +static void CNFGEndCmd( VkCommandBuffer cmd, VkFence fence ) +{ + vkEndCommandBuffer( cmd ); + VkSubmitInfo submit = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .commandBufferCount = 1, .pCommandBuffers = &cmd }; + vkQueueSubmit( CNFGGraphicsQueue, 1, &submit, fence ); +} + +static void CNFGEndFrame() +{ + CNFGFlushRender(); + + CNFGBeginCmd( CNFGGraphicsCommands[CNFGCurFlight] ); + CNFGTransImageLayout( CNFGGraphicsCommands[CNFGCurFlight], CNFGSwapchainImages[CNFGCurSwapchainImage], + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 0, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT + ); + vkEndCommandBuffer( CNFGGraphicsCommands[CNFGCurFlight] ); + + vkResetFences( CNFGLogicalDevice, 1, &CNFGRenderFences[CNFGCurFlight] ); + + VkPipelineStageFlags wait = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo sub = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = NULL, + .waitSemaphoreCount = 1, .pWaitSemaphores = &CNFGPresentSemas[CNFGCurSema], .pWaitDstStageMask = &wait, + .commandBufferCount = 1, .pCommandBuffers = &CNFGGraphicsCommands[CNFGCurFlight], .signalSemaphoreCount = 1, + .pSignalSemaphores = &CNFGRenderSemas[CNFGCurSema] + }; + vkQueueSubmit( CNFGGraphicsQueue, 1, &sub, CNFGRenderFences[CNFGCurFlight] ); + + VkPresentInfoKHR present = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = NULL, + .waitSemaphoreCount = 1, .pWaitSemaphores = &CNFGRenderSemas[CNFGCurSema], + .swapchainCount = 1, .pSwapchains = &CNFGSwapchain, .pImageIndices = &CNFGCurSwapchainImage, .pResults = NULL + }; + vkQueuePresentKHR( CNFGPresentQueue, &present ); + + CNFGCurSwapchainImage = -1; + CNFGCurFlight = (CNFGCurFlight + 1) % CNFGVK_FRAMES_IN_FLIGHT; + CNFGCurSema = (CNFGCurSema + 1) % CNFGSwapchainImageCount; +} + +static void CNFGBeginRender( VkCommandBuffer cmd ) +{ + if ( CNFGCurSwapchainImage == -1 ) CNFGSwapBuffers(); + + VkRenderingAttachmentInfo attach = { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = CNFGSwapchainViews[CNFGCurSwapchainImage], + .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + }; + VkRenderingInfo rendInfo = { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea = {.offset={0}, .extent=CNFGSwapchainExtent}, + .colorAttachmentCount = 1, .layerCount = 1, .pColorAttachments = &attach + }; + + vkCmdBeginRendering( cmd, &rendInfo ); + vkCmdSetViewport( cmd, 0, 1, (VkViewport[]){{ .x=0, .y=0, .width=CNFGSwapchainExtent.width, .height=CNFGSwapchainExtent.height, 0, 1 }} ); + if ( CNFGScissors[0] >= 0 ) vkCmdSetScissor( cmd, 0, 1, (VkRect2D[]){{ {CNFGScissors[0], CNFGScissors[1]}, {CNFGScissors[2], CNFGScissors[3]} }} ); + else vkCmdSetScissor( cmd, 0, 1, (VkRect2D[]){{ {0}, CNFGSwapchainExtent }} ); + vkCmdBindDescriptorSets( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGPipelineLayout, 0, 1, &CNFGDescriptorSet, 0, NULL ); +} + +void CNFGInternalResize( short x, short y ) +{ + if ( CNFGCurSwapchainImage != (uint32_t)-1 ) + { + CNFGCurSwapchainImage = -1; + CNFGCurFlight = (CNFGCurFlight + 1) % CNFGVK_FRAMES_IN_FLIGHT; + CNFGCurSema = (CNFGCurSema + 1) % CNFGSwapchainImageCount; + } + vkDeviceWaitIdle( CNFGLogicalDevice ); + + CNFGDestroySwapchain(); + CNFGCreateSwapchain(); + + memcpy( CNFGBatchMap, (float[]){ 2.f/x, 2.f/y, -1.f, -1.f }, sizeof( float[4] ) ); +} + +static void CNFGWaitForBatchBuffer() +{ + vkWaitForFences( CNFGLogicalDevice, 1, &CNFGBatchFence, VK_FALSE, UINT64_MAX ); + vkResetFences( CNFGLogicalDevice, 1, &CNFGBatchFence ); +} + +void CNFGEmitBackendTriangles( const float * vertices, const uint32_t * colors, int num_vertices ) +{ + CNFGWaitForBatchBuffer(); + + CNFGBeginCmd( CNFGBatchCommand ); + CNFGBeginRender( CNFGBatchCommand ); + + memcpy( CNFGBatchMap + sizeof( float[4] ), vertices, num_vertices * sizeof( float[3] ) ); + memcpy( CNFGBatchMap + sizeof( CNFGVertDataV ) + sizeof( float[4] ), colors, sizeof( uint32_t ) * num_vertices ); + + vkCmdBindPipeline( CNFGBatchCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGBatchPipeline ); + vkCmdDraw( CNFGBatchCommand, num_vertices, 1, 0, 0 ); + + vkCmdEndRendering( CNFGBatchCommand ); + CNFGEndCmd( CNFGBatchCommand, CNFGBatchFence ); +} + +void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) +{ + CNFGFlushRender(); + CNFGWaitForBatchBuffer(); + + vkDestroyImageView( CNFGLogicalDevice, CNFGImageView, NULL ); + vkDestroyImage( CNFGLogicalDevice, CNFGImage, NULL ); + + VkImageCreateInfo imgci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .imageType = VK_IMAGE_TYPE_2D, .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = { w, h, 1 }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED + }; + vkCreateImage( CNFGLogicalDevice, &imgci, NULL, &CNFGImage); + vkBindImageMemory( CNFGLogicalDevice, CNFGImage, CNFGImageMemory, 0 ); + memcpy( CNFGImageMap, data, w*h*sizeof( uint32_t ) ); + + CNFGBeginCmd( CNFGBatchCommand ); + CNFGTransImageLayout( + CNFGBatchCommand, CNFGImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT + ); + + VkImageViewCreateInfo viewci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = CNFGImage, .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_R8G8B8A8_UNORM, .subresourceRange = { .aspectMask=VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + vkCreateImageView( CNFGLogicalDevice, &viewci, NULL, &CNFGImageView ); + + VkDescriptorImageInfo infi = {.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .sampler = CNFGSampler, .imageView = CNFGImageView }; + VkWriteDescriptorSet write = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 2, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &infi + }; + vkUpdateDescriptorSets( CNFGLogicalDevice, 1, &write, 0, NULL ); + + CNFGBeginRender( CNFGBatchCommand ); + + const float verts[] = { x, y, 0, x+w, y, 0, x+w, y+h, 0, x, y, 0, x+w, y+h, 0, x, y+h, 0 }; + const uint32_t uvs[] = { 0x00000000, 0xFF000000, 0xFFFF0000, 0x00000000, 0xFFFF0000, 0x00FF0000 }; + + memcpy( CNFGBatchMap + sizeof( float[4] ), verts, sizeof( verts ) ); + memcpy( CNFGBatchMap + sizeof( CNFGVertDataV ) + sizeof( float[4] ), uvs, sizeof( uvs ) ); + vkCmdBindPipeline( CNFGBatchCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGImagePipeline ); + vkCmdDraw( CNFGBatchCommand, 6, 1, 0, 0 ); + + vkCmdEndRendering( CNFGBatchCommand ); + CNFGEndCmd( CNFGBatchCommand, CNFGBatchFence ); +} + +// Could use vkCmdClearColorImage, but it doesn't respect scissors +void CNFGClearFrame() +{ + uint32_t temp = CNFGLastColor; + CNFGLastColor = CNFGBGColor; + CNFGEmitQuad( 0, 0, 0, CNFGSwapchainExtent.height, CNFGSwapchainExtent.width, 0, CNFGSwapchainExtent.width, CNFGSwapchainExtent.height ); + CNFGLastColor = temp; +} + +void CNFGSwapBuffers() +{ + if ( CNFGCurSwapchainImage != (uint32_t)-1 ) CNFGEndFrame(); + + vkWaitForFences( CNFGLogicalDevice, 1, &CNFGRenderFences[CNFGCurFlight], VK_TRUE, UINT64_MAX ); + vkAcquireNextImageKHR( CNFGLogicalDevice, CNFGSwapchain, UINT64_MAX, CNFGPresentSemas[CNFGCurSema], NULL, &CNFGCurSwapchainImage); + + CNFGBeginCmd( CNFGGraphicsCommands[CNFGCurFlight] ); + CNFGTransImageLayout( CNFGGraphicsCommands[CNFGCurFlight], CNFGSwapchainImages[CNFGCurSwapchainImage], + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 0, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT + ); + CNFGEndCmd( CNFGGraphicsCommands[CNFGCurFlight], NULL ); +} + +void CNFGSetVSync( int vson ) +{ + CNFGVSyncOn = vson; + CNFGInternalResize( CNFGSwapchainExtent.width, CNFGSwapchainExtent.height ); +} + +void CNFGSetScissors( int * xywh ) +{ + CNFGFlushRender(); + memcpy( CNFGScissors, xywh, sizeof(int)*4 ); +} + +void CNFGGetScissors( int * xywh ) +{ + memcpy( xywh, CNFGScissors, sizeof(int)*4 ); +} diff --git a/CNFGWinDriver.c b/CNFGWinDriver.c index 190ae50..0f1ef56 100644 --- a/CNFGWinDriver.c +++ b/CNFGWinDriver.c @@ -65,6 +65,19 @@ void CNFGSwapBuffers() } #endif +#ifdef CNFGVK +#include +#define CNFG_SURFACE_EXTENSION "VK_KHR_win32_surface", "VK_KHR_surface" +VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ) +{ + VkWin32SurfaceCreateInfoKHR sci = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, .hinstance = GetModuleHandle( NULL ), .hwnd = CNFGlsHWND + }; + return vkCreateWin32SurfaceKHR( inst, &sci, alloc, surface ); +} +#endif + CNFGCursorShape CNFGCurShape = CNFG_CURSOR_ARROW; void CNFGSetMousePosition( int x, int y ) { diff --git a/CNFGXDriver.c b/CNFGXDriver.c index 323eaa0..d69930c 100644 --- a/CNFGXDriver.c +++ b/CNFGXDriver.c @@ -96,6 +96,19 @@ void CNFGGLXSetup( ) #endif +#ifdef CNFGVK +#include +#define CNFG_SURFACE_EXTENSION "VK_KHR_xlib_surface", "VK_KHR_surface" +VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ) +{ + VkXlibSurfaceCreateInfoKHR sci = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, .dpy = CNFGDisplay, .window = CNFGWindow, + }; + return vkCreateXlibSurfaceKHR( inst, &sci, alloc, surface ); +} +#endif + int CNFGX11ForceNoDecoration; XImage *xi; diff --git a/Makefile b/Makefile index 244e20c..d5a881e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all : rawdraw simple rawdraw_sf.h +all : rawdraw_sf.h rawdraw simple #for X11 consider: xorg-dev #for X11, you will need: libx-dev @@ -34,6 +34,9 @@ simple : simple.c rawdraw : rawdraw.c gcc -o $@ $^ -lX11 -lpthread -lXinerama -lXext -lGL -g -lm -ldl +rawdraw_vk : rawdraw.c + gcc -o $@ $^ -lX11 -lpthread -lXinerama -lXext -g -lm -ldl -lvulkan -DCNFGVK -DCNFGVK_VALIDATION_LAYERS + rawdraw_ogl : rawdraw.c gcc -o $@ $^ -lX11 -lpthread -lXinerama -lXext -lGL -g -DCNFGOGL -lm -ldl @@ -58,12 +61,23 @@ ogltest.exe : ogltest.c CNFG.c tools/single_file_creator : tools/single_file_creator.c gcc -o $@ $^ -rawdraw_sf.h : tools/single_file_creator CNFG.h tools/rawdraw_http_page.h +vk/cnfgshader.h : tools/single_file_creator + -glslang -S vert -DVERT --target-env vulkan1.3 -o vk/verttemp -x vk/cnfg.glsl + -glslang -S frag -DBATCH --target-env vulkan1.3 -o vk/batchtemp -x vk/cnfg.glsl + -glslang -S frag -DIMG --target-env vulkan1.3 -o vk/imgtemp -x vk/cnfg.glsl + -./tools/single_file_creator vk/shadertemplate.h vk/verttemp vk/batchtemp vk/imgtemp > $@ + +rawdraw_sf.h : tools/single_file_creator CNFG.h tools/rawdraw_http_page.h vk/cnfgshader.h echo "//This file was automatically generated by Makefile at https://github.com/cntools/rawdraw" > $@ echo "//This single-file feature is still in early alpha testing." >> $@f echo "//Generated from files git hash $(shell git rev-parse HEAD) on $(shell date) (This is not the git hash of this file)" >> $@ - ./tools/single_file_creator CNFG.h CNFG.c CNFGWinDriver.c CNFGEGLLeanAndMean.c CNFGRasterizer.c CNFGEGLDriver.c CNFGWASMDriver.c CNFGXDriver.c CNFGFunctions.c CNFGOGL.c CNFG3D.c CNFGAndroid.h CNFGHTTP.c tools/rawdraw_http_page.h >> $@ + ./tools/single_file_creator CNFG.h CNFG.c CNFGWinDriver.c CNFGEGLLeanAndMean.c CNFGRasterizer.c CNFGEGLDriver.c CNFGWASMDriver.c CNFGXDriver.c CNFGFunctions.c CNFGOGL.c CNFG3D.c CNFGAndroid.h CNFGHTTP.c CNFGVK.c vk/cnfgshader.h tools/rawdraw_http_page.h >> $@ clean : - rm -rf *.o *~ simple simple.exe rawdraw.exe rawdrawogl.exe rawdraw rawdraw_ogl rawdraw_mac rawdraw_mac_soft rawdraw_mac_cg rawdraw_mac_ogl ogltest ogltest.exe rawdraw_egl rawdraw_http rawdraw_sf.h rawdraw_sf.hf tools/single_file_creator tools/binary_to_buffer tools/rawdraw_http_page.h + rm -rf *.o *~ simple simple.exe rawdraw.exe rawdrawogl.exe rawdraw rawdraw_ogl rawdraw_vk rawdraw_mac rawdraw_mac_soft rawdraw_mac_cg rawdraw_mac_ogl ogltest ogltest.exe rawdraw_egl rawdraw_http rawdraw_sf.h rawdraw_sf.hf tools/single_file_creator tools/binary_to_buffer tools/rawdraw_http_page.h +# Some people may not have glslang on their system, so have another clean target +# so they don't have to install it to properly regenerate rawdraw_sf +# (this is also why the shader compilation targets ignore errors and the compiled SPIR-V is in the tree) +cleanvkshader : clean + rm -rf vk/verttemp vk/batchtemp vk/imgtemp vk/cnfgshader.h diff --git a/README.md b/README.md index 6cfd9d3..107ee3d 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ platform. ## Platform statuses - * Windows, 100% Support for CNFGOGL and/or CNFGRASTERIZER, Native (GDI32) does not support alpha-blitting, or variable line width. - * Linux, 100% Support for CNFGOGL and/or CNFGRASTERIZER, Native (X11) does not support alpha-blitting, or variable line thickness + * Windows, 100% Support for CNFGOGL, CNFGVK, and/or CNFGRASTERIZER, Native (GDI32) does not support alpha-blitting, or variable line width. + * Linux, 100% Support for CNFGOGL, CNFGVK, and/or CNFGRASTERIZER, Native (X11) does not support alpha-blitting, or variable line thickness . * Android, 100% Support for CNFGOGL (It is forced on) CNFGRASTERIZER not allowed. **PLEASE** Only report android-related issues to [rawdrawandroid](https://github.com/cnlohr/rawdrawandroid) * WASM, 100% Support for CNFGOGL * Other EGL (Like Raspberry Pi Raw Metal) Platforms, same as Android, but fixed window size. * EGL, CNFGOGL represent OpenGL or OpenGL ES depending on platform support. - * Vulkan support in progress. + * Vulkan support is experimental * CNFG3D Support has been ported with fixed-precision numericals to ESP8266. * Mac/OSX Support currently unknown. Legacy files moved here: https://github.com/cntools/rawdrawtools/tree/main/attic @@ -183,6 +183,7 @@ CNFG Configuration options include: * `__android__` = build Android port * `WINDOWS`, `WIN32`, `WIN64` = Windows build * `CNFGOGL` = Make underlying functions use OpenGL if possible. +* `CNFGVK` = Make underlying functions use Vulkan if possible * `CNFGRASTERIZER` = Make the underlying graphics engine rasterized functions (software rendering) * `CNFG3D` = Include CNFG3D with this rawdraw build. This provides *rasterized* graphics functions. Only use this option with the rasterizer. diff --git a/rawdraw_sf.h b/rawdraw_sf.h index 4580ce1..7db9be4 100644 --- a/rawdraw_sf.h +++ b/rawdraw_sf.h @@ -1,5 +1,5 @@ //This file was automatically generated by Makefile at https://github.com/cntools/rawdraw -//Generated from files git hash 65771c7a8c6c970449f5c520874d3e54b585e7d0 on Wed Jul 30 10:52:38 AM EDT 2025 (This is not the git hash of this file) +//Generated from files git hash b7058e9533dadb24e589f3cdea4e193c420bb493 on Sat Aug 16 10:01:48 PM EDT 2025 (This is not the git hash of this file) // Copyright 2010-2021 <>< CNLohr, et. al. (Several other authors, many but not all mentioned) // Licensed under the MIT/x11 or NewBSD License you choose. // @@ -20,6 +20,9 @@ extern "C" { CNFG_USE_DOUBLE_FUNCTIONS -> Use double-precision floating point for CNFG3D. CNFGOGL -> Use an OpenGL Backend for all rawdraw functionality. ->Caveat->If using CNFG_HAS_XSHAPE, then, we do something realy wacky. + CNFGVK -> Use the experimental Vulkan backend + CNFGVK_VALIDATION_LAYERS -> Enable the validation layers of the batched renderer + CNFGVK_IMAGE_ALLOCATION -> Specify the amount of VRAM allocated towards images in the batched renderer CNFGRASTERIZER -> Software-rasterize the rawdraw calls, and, use CNFGUpdateScreenWithBitmap to send video to webpage. CNFGCONTEXTONLY -> Don't add any drawing functions, only opening a window to @@ -75,6 +78,15 @@ Usually tested combinations: #endif #endif +#ifdef CNFGVK + #define CNFG_BATCH 8192 + + #include + + // The drivers define the CNFG_SURFACE_EXTENSION macro for their required extensions + VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ); +#endif + typedef struct { short x, y; } RDPoint; @@ -113,6 +125,10 @@ void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ); void CNFGDeleteTex( unsigned int tex ); unsigned int CNFGTexImage( uint32_t *data, int w, int h ); void CNFGBlitTex( unsigned int tex, int x, int y, int w, int h ); +#endif + +#if defined( CNFGOGL ) || defined( CNFGVK ) +void CNFGSetVSync( int vson ); // Not supported on all systems void CNFGSetScissors( int * xywh ); void CNFGGetScissors( int * xywh ); #endif @@ -158,7 +174,6 @@ void CNFGInternalResize( short x, short y ); //don't call this. //Not available on all systems. Use The OGL portion with care. #ifdef CNFGOGL -void CNFGSetVSync( int vson ); void * CNFGGetExtension( const char * extname ); #endif @@ -3804,6 +3819,19 @@ void CNFGSwapBuffers() } #endif +#ifdef CNFGVK +#include +#define CNFG_SURFACE_EXTENSION "VK_KHR_win32_surface", "VK_KHR_surface" +VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ) +{ + VkWin32SurfaceCreateInfoKHR sci = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, .hinstance = GetModuleHandle( NULL ), .hwnd = CNFGlsHWND + }; + return vkCreateWin32SurfaceKHR( inst, &sci, alloc, surface ); +} +#endif + CNFGCursorShape CNFGCurShape = CNFG_CURSOR_ARROW; void CNFGSetMousePosition( int x, int y ) { @@ -5744,6 +5772,19 @@ void CNFGGLXSetup( ) #endif +#ifdef CNFGVK +#include +#define CNFG_SURFACE_EXTENSION "VK_KHR_xlib_surface", "VK_KHR_surface" +VkResult CNFGCreateVkSurface( VkInstance inst, const VkAllocationCallbacks* alloc, VkSurfaceKHR* surface ) +{ + VkXlibSurfaceCreateInfoKHR sci = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, .dpy = CNFGDisplay, .window = CNFGWindow, + }; + return vkCreateXlibSurfaceKHR( inst, &sci, alloc, surface ); +} +#endif + int CNFGX11ForceNoDecoration; XImage *xi; @@ -7025,7 +7066,7 @@ uint32_t CNFGVertDataC[CNFG_BATCH]; int CNFGVertPlace; static float wgl_last_width_over_2 = .5f; -static void EmitQuad( float cx0, float cy0, float cx1, float cy1, float cx2, float cy2, float cx3, float cy3 ) +void CNFGEmitQuad( float cx0, float cy0, float cx1, float cy1, float cx2, float cy2, float cx3, float cy3 ) { //Because quads are really useful, but it's best to keep them all triangles if possible. //This lets us draw arbitrary quads. @@ -7051,7 +7092,7 @@ void CNFGTackPixel( short x1, short y1 ) x1++; y1++; const float l2 = wgl_last_width_over_2; const float l2u = wgl_last_width_over_2+0.5f; - EmitQuad( x1-l2u, y1-l2u, x1+l2, y1-l2u, x1-l2u, y1+l2, x1+l2, y1+l2 ); + CNFGEmitQuad( x1-l2u, y1-l2u, x1+l2, y1-l2u, x1-l2u, y1+l2, x1+l2, y1+l2 ); } @@ -7076,7 +7117,7 @@ void CNFGTackSegment( short x1, short y1, short x2, short y2 ) iy1 -= dy/2 - 0.5f; //This logic is incorrect. XXX FIXME. - EmitQuad( (ix1 - orthox), (iy1 - orthoy), (ix1 + orthox), (iy1 + orthoy), (ix2 - orthox), (iy2 - orthoy), ( ix2 + orthox), ( iy2 + orthoy) ); + CNFGEmitQuad( (ix1 - orthox), (iy1 - orthoy), (ix1 + orthox), (iy1 + orthoy), (ix2 - orthox), (iy2 - orthoy), ( ix2 + orthox), ( iy2 + orthoy) ); } void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) @@ -7085,7 +7126,7 @@ void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) float iy1 = y1; float ix2 = x2; float iy2 = y2; - EmitQuad( ix1,iy1,ix2,iy1,ix1,iy2,ix2,iy2 ); + CNFGEmitQuad( ix1,iy1,ix2,iy1,ix1,iy2,ix2,iy2 ); } void CNFGTackPoly( RDPoint * points, int verts ) @@ -7198,6 +7239,44 @@ void CNFGFlushRender() { } #include #endif +#if defined(CNFGCONTEXTONLY) || defined(CNFGOGL_NEED_EXTENSION) +#ifdef CNFG_WINDOWS + +//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions +void * CNFGGetProcAddress(const char *name) +{ + void *p = (void *)wglGetProcAddress(name); + if(p == 0 || + (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || + (p == (void*)-1) ) + { + static HMODULE module; + if( !module ) module = LoadLibraryA("opengl32.dll"); + p = (void *)GetProcAddress(module, name); + } + // We were unable to load the required openGL function + if (!p) { + fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); + } + return p; +} + +#else +#include + + +void * CNFGGetProcAddress(const char *name) +{ + //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. + void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); + //printf( "%s = %p\n", name, v1 ); + if( !v1 ) v1 = dlsym( 0, name ); + return v1; +} + +#endif +#endif + #ifdef CNFGOGL_NEED_EXTENSION // If we are going to be defining our own function pointer call #ifdef CNFG_WINDOWS @@ -7216,6 +7295,7 @@ void CNFGFlushRender() { } ret name (__VA_ARGS__); #endif +#ifndef CNFGCONTEXTONLY #ifdef __cplusplus extern "C" { @@ -7273,41 +7353,6 @@ CHEWTYPEDEF( void, glActiveTexture, , (texture), GLenum texture ) #endif #ifdef CNFGOGL_NEED_EXTENSION -#ifdef CNFG_WINDOWS - -//From https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions -void * CNFGGetProcAddress(const char *name) -{ - void *p = (void *)wglGetProcAddress(name); - if(p == 0 || - (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || - (p == (void*)-1) ) - { - static HMODULE module; - if( !module ) module = LoadLibraryA("opengl32.dll"); - p = (void *)GetProcAddress(module, name); - } - // We were unable to load the required openGL function - if (!p) { - fprintf(stderr,"[rawdraw][warn]: Unable to load openGL extension \"%s\"\n", name); - } - return p; -} - -#else -#include - - -void * CNFGGetProcAddress(const char *name) -{ - //Tricky use RTLD_NEXT first so we don't accidentally link against ourselves. - void * v1 = dlsym( (void*)((intptr_t)-1) /*RTLD_NEXT = -1*/ /*RTLD_DEFAULT = 0*/, name ); - //printf( "%s = %p\n", name, v1 ); - if( !v1 ) v1 = dlsym( 0, name ); - return v1; -} - -#endif // Try and load openGL extension functions required for rawdraw static void CNFGLoadExtensionsInternal() @@ -7653,10 +7698,918 @@ void CNFGGetScissors( int * xywh ) glGetIntegerv( GL_SCISSOR_BOX, xywh ); } +#endif // CNFGCONTEXTONLY #endif // CNFG_WASM #endif +#ifdef CNFGVK +#ifndef CNFGCONTEXTONLY +//Copyright (c) 2010-2025 <>< Charles Lohr, and several others! +// Licensed under the MIT/x11 or NewBSD License you choose. +// +// Vulkan Batched Renderer + +#include +#include +#include +#include +#include + +// Compiled SPIR-V Shaders for the CNFG Batched Vulkan renderer +// To recreate, run "make vk/cnfgshader.h" (requires glslang) + +// These shaders are in the tree so contributers don't need +// glslang to properly recreate rawdraw_sf.h + +static const uint32_t CNFGVertShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x00000077,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000003d,0x00000040,0x00000057, + 0x0000005d,0x00000064,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00070005,0x0000000c,0x6f6c6f63,0x78654872,0x65566f54,0x75283463,0x00003b31, + 0x00030005,0x0000000b,0x00786568,0x00040005,0x0000000f,0x566c6f63,0x00006365,0x00030005, + 0x00000039,0x00736f70,0x00040005,0x0000003b,0x74726576,0x00000000,0x00040006,0x0000003b, + 0x00000000,0x00000078,0x00040006,0x0000003b,0x00000001,0x00000076,0x00030005,0x0000003d, + 0x00000000,0x00060005,0x00000040,0x565f6c67,0x65747265,0x646e4978,0x00007865,0x00030005, + 0x00000053,0x006c6f63,0x00040005,0x00000055,0x6f6c6f63,0x00000072,0x00040006,0x00000055, + 0x00000000,0x00000063,0x00030005,0x00000057,0x00000000,0x00040005,0x0000005d,0x6f635f66, + 0x00726f6c,0x00040005,0x0000005e,0x61726170,0x0000006d,0x00060005,0x00000062,0x505f6c67, + 0x65567265,0x78657472,0x00000000,0x00060006,0x00000062,0x00000000,0x505f6c67,0x7469736f, + 0x006e6f69,0x00070006,0x00000062,0x00000001,0x505f6c67,0x746e696f,0x657a6953,0x00000000, + 0x00070006,0x00000062,0x00000002,0x435f6c67,0x4470696c,0x61747369,0x0065636e,0x00070006, + 0x00000062,0x00000003,0x435f6c67,0x446c6c75,0x61747369,0x0065636e,0x00030005,0x00000064, + 0x00000000,0x00040047,0x0000003a,0x00000006,0x00000004,0x00030047,0x0000003b,0x00000002, + 0x00040048,0x0000003b,0x00000000,0x00000018,0x00050048,0x0000003b,0x00000000,0x00000023, + 0x00000000,0x00040048,0x0000003b,0x00000001,0x00000018,0x00050048,0x0000003b,0x00000001, + 0x00000023,0x00000010,0x00030047,0x0000003d,0x00000018,0x00040047,0x0000003d,0x00000021, + 0x00000000,0x00040047,0x0000003d,0x00000022,0x00000000,0x00040047,0x00000040,0x0000000b, + 0x0000002a,0x00040047,0x00000054,0x00000006,0x00000004,0x00030047,0x00000055,0x00000002, + 0x00040048,0x00000055,0x00000000,0x00000018,0x00050048,0x00000055,0x00000000,0x00000023, + 0x00000000,0x00030047,0x00000057,0x00000018,0x00040047,0x00000057,0x00000021,0x00000001, + 0x00040047,0x00000057,0x00000022,0x00000000,0x00040047,0x0000005d,0x0000001e,0x00000000, + 0x00030047,0x00000062,0x00000002,0x00050048,0x00000062,0x00000000,0x0000000b,0x00000000, + 0x00050048,0x00000062,0x00000001,0x0000000b,0x00000001,0x00050048,0x00000062,0x00000002, + 0x0000000b,0x00000003,0x00050048,0x00000062,0x00000003,0x0000000b,0x00000004,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000, + 0x00040020,0x00000007,0x00000007,0x00000006,0x00030016,0x00000008,0x00000020,0x00040017, + 0x00000009,0x00000008,0x00000004,0x00040021,0x0000000a,0x00000009,0x00000007,0x00040020, + 0x0000000e,0x00000007,0x00000009,0x00040015,0x00000011,0x00000020,0x00000001,0x0004002b, + 0x00000011,0x00000012,0x00000018,0x0004002b,0x00000006,0x00000014,0x000000ff,0x0004002b, + 0x00000008,0x00000017,0x437f0000,0x0004002b,0x00000006,0x00000019,0x00000000,0x00040020, + 0x0000001a,0x00000007,0x00000008,0x0004002b,0x00000011,0x0000001d,0x00000010,0x0004002b, + 0x00000006,0x00000022,0x00000001,0x0004002b,0x00000011,0x00000025,0x00000008,0x0004002b, + 0x00000006,0x0000002a,0x00000002,0x0004002b,0x00000011,0x0000002d,0x00000000,0x0004002b, + 0x00000006,0x00000032,0x00000003,0x00040017,0x00000037,0x00000008,0x00000003,0x00040020, + 0x00000038,0x00000007,0x00000037,0x0003001d,0x0000003a,0x00000008,0x0004001e,0x0000003b, + 0x00000009,0x0000003a,0x00040020,0x0000003c,0x0000000c,0x0000003b,0x0004003b,0x0000003c, + 0x0000003d,0x0000000c,0x0004002b,0x00000011,0x0000003e,0x00000001,0x00040020,0x0000003f, + 0x00000001,0x00000011,0x0004003b,0x0000003f,0x00000040,0x00000001,0x0004002b,0x00000011, + 0x00000042,0x00000003,0x00040020,0x00000044,0x0000000c,0x00000008,0x0004002b,0x00000011, + 0x0000004e,0x00000002,0x0003001d,0x00000054,0x00000006,0x0003001e,0x00000055,0x00000054, + 0x00040020,0x00000056,0x0000000c,0x00000055,0x0004003b,0x00000056,0x00000057,0x0000000c, + 0x00040020,0x00000059,0x0000000c,0x00000006,0x00040020,0x0000005c,0x00000003,0x00000009, + 0x0004003b,0x0000005c,0x0000005d,0x00000003,0x0004001c,0x00000061,0x00000008,0x00000022, + 0x0006001e,0x00000062,0x00000009,0x00000008,0x00000061,0x00000061,0x00040020,0x00000063, + 0x00000003,0x00000062,0x0004003b,0x00000063,0x00000064,0x00000003,0x00040017,0x00000065, + 0x00000008,0x00000002,0x00040020,0x00000068,0x0000000c,0x00000009,0x0004002b,0x00000008, + 0x00000071,0x00000000,0x0004002b,0x00000008,0x00000072,0x3f800000,0x00050036,0x00000002, + 0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000038,0x00000039, + 0x00000007,0x0004003b,0x00000007,0x00000053,0x00000007,0x0004003b,0x00000007,0x0000005e, + 0x00000007,0x0004003d,0x00000011,0x00000041,0x00000040,0x00050084,0x00000011,0x00000043, + 0x00000041,0x00000042,0x00060041,0x00000044,0x00000045,0x0000003d,0x0000003e,0x00000043, + 0x0004003d,0x00000008,0x00000046,0x00000045,0x0004003d,0x00000011,0x00000047,0x00000040, + 0x00050084,0x00000011,0x00000048,0x00000047,0x00000042,0x00050080,0x00000011,0x00000049, + 0x00000048,0x0000003e,0x00060041,0x00000044,0x0000004a,0x0000003d,0x0000003e,0x00000049, + 0x0004003d,0x00000008,0x0000004b,0x0000004a,0x0004003d,0x00000011,0x0000004c,0x00000040, + 0x00050084,0x00000011,0x0000004d,0x0000004c,0x00000042,0x00050080,0x00000011,0x0000004f, + 0x0000004d,0x0000004e,0x00060041,0x00000044,0x00000050,0x0000003d,0x0000003e,0x0000004f, + 0x0004003d,0x00000008,0x00000051,0x00000050,0x00060050,0x00000037,0x00000052,0x00000046, + 0x0000004b,0x00000051,0x0003003e,0x00000039,0x00000052,0x0004003d,0x00000011,0x00000058, + 0x00000040,0x00060041,0x00000059,0x0000005a,0x00000057,0x0000002d,0x00000058,0x0004003d, + 0x00000006,0x0000005b,0x0000005a,0x0003003e,0x00000053,0x0000005b,0x0004003d,0x00000006, + 0x0000005f,0x00000053,0x0003003e,0x0000005e,0x0000005f,0x00050039,0x00000009,0x00000060, + 0x0000000c,0x0000005e,0x0003003e,0x0000005d,0x00000060,0x0004003d,0x00000037,0x00000066, + 0x00000039,0x0007004f,0x00000065,0x00000067,0x00000066,0x00000066,0x00000000,0x00000001, + 0x00050041,0x00000068,0x00000069,0x0000003d,0x0000002d,0x0004003d,0x00000009,0x0000006a, + 0x00000069,0x0007004f,0x00000065,0x0000006b,0x0000006a,0x0000006a,0x00000000,0x00000001, + 0x00050085,0x00000065,0x0000006c,0x00000067,0x0000006b,0x00050041,0x00000068,0x0000006d, + 0x0000003d,0x0000002d,0x0004003d,0x00000009,0x0000006e,0x0000006d,0x0007004f,0x00000065, + 0x0000006f,0x0000006e,0x0000006e,0x00000002,0x00000003,0x00050081,0x00000065,0x00000070, + 0x0000006c,0x0000006f,0x00050051,0x00000008,0x00000073,0x00000070,0x00000000,0x00050051, + 0x00000008,0x00000074,0x00000070,0x00000001,0x00070050,0x00000009,0x00000075,0x00000073, + 0x00000074,0x00000071,0x00000072,0x00050041,0x0000005c,0x00000076,0x00000064,0x0000002d, + 0x0003003e,0x00000076,0x00000075,0x000100fd,0x00010038,0x00050036,0x00000009,0x0000000c, + 0x00000000,0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8,0x0000000d,0x0004003b, + 0x0000000e,0x0000000f,0x00000007,0x0004003d,0x00000006,0x00000010,0x0000000b,0x000500c2, + 0x00000006,0x00000013,0x00000010,0x00000012,0x000500c7,0x00000006,0x00000015,0x00000013, + 0x00000014,0x00040070,0x00000008,0x00000016,0x00000015,0x00050088,0x00000008,0x00000018, + 0x00000016,0x00000017,0x00050041,0x0000001a,0x0000001b,0x0000000f,0x00000019,0x0003003e, + 0x0000001b,0x00000018,0x0004003d,0x00000006,0x0000001c,0x0000000b,0x000500c2,0x00000006, + 0x0000001e,0x0000001c,0x0000001d,0x000500c7,0x00000006,0x0000001f,0x0000001e,0x00000014, + 0x00040070,0x00000008,0x00000020,0x0000001f,0x00050088,0x00000008,0x00000021,0x00000020, + 0x00000017,0x00050041,0x0000001a,0x00000023,0x0000000f,0x00000022,0x0003003e,0x00000023, + 0x00000021,0x0004003d,0x00000006,0x00000024,0x0000000b,0x000500c2,0x00000006,0x00000026, + 0x00000024,0x00000025,0x000500c7,0x00000006,0x00000027,0x00000026,0x00000014,0x00040070, + 0x00000008,0x00000028,0x00000027,0x00050088,0x00000008,0x00000029,0x00000028,0x00000017, + 0x00050041,0x0000001a,0x0000002b,0x0000000f,0x0000002a,0x0003003e,0x0000002b,0x00000029, + 0x0004003d,0x00000006,0x0000002c,0x0000000b,0x000500c2,0x00000006,0x0000002e,0x0000002c, + 0x0000002d,0x000500c7,0x00000006,0x0000002f,0x0000002e,0x00000014,0x00040070,0x00000008, + 0x00000030,0x0000002f,0x00050088,0x00000008,0x00000031,0x00000030,0x00000017,0x00050041, + 0x0000001a,0x00000033,0x0000000f,0x00000032,0x0003003e,0x00000033,0x00000031,0x0004003d, + 0x00000009,0x00000034,0x0000000f,0x000200fe,0x00000034,0x00010038 + +}; + +static const uint32_t CNFGBatchShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x0000000d,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000b,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00040005,0x00000009,0x6f635f69,0x00726f6c,0x00040005,0x0000000b,0x6f635f66, + 0x00726f6c,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000b,0x0000001e, + 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, + 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040020,0x0000000a,0x00000001, + 0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000007,0x0000000c,0x0000000b, + 0x0003003e,0x00000009,0x0000000c,0x000100fd,0x00010038 + +}; + +static const uint32_t CNFGImageShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x00000016,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00000010, + 0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00040005,0x00000009,0x6f635f69,0x00726f6c,0x00040005,0x0000000d, + 0x65745f66,0x00000078,0x00040005,0x00000010,0x6f635f66,0x00726f6c,0x00040047,0x00000009, + 0x0000001e,0x00000000,0x00040047,0x0000000d,0x00000021,0x00000002,0x00040047,0x0000000d, + 0x00000022,0x00000000,0x00040047,0x00000010,0x0000001e,0x00000000,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007, + 0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008, + 0x00000009,0x00000003,0x00090019,0x0000000a,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a,0x00040020,0x0000000c, + 0x00000000,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000f, + 0x00000001,0x00000007,0x0004003b,0x0000000f,0x00000010,0x00000001,0x00040017,0x00000011, + 0x00000006,0x00000002,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, + 0x00000005,0x0004003d,0x0000000b,0x0000000e,0x0000000d,0x0004003d,0x00000007,0x00000012, + 0x00000010,0x0007004f,0x00000011,0x00000013,0x00000012,0x00000012,0x00000000,0x00000001, + 0x00050057,0x00000007,0x00000014,0x0000000e,0x00000013,0x0009004f,0x00000007,0x00000015, + 0x00000014,0x00000014,0x00000003,0x00000002,0x00000001,0x00000000,0x0003003e,0x00000009, + 0x00000015,0x000100fd,0x00010038 + +}; + + + +#ifndef CNFGVK +#define CNFGVK +#define CNFG_BATCH 8192 +#define CNFG_SURFACE_EXTENSION "" +#define CNFGVK_VALIDATION_LAYERS + +#endif + +#ifndef CNFGVK_FRAMES_IN_FLIGHT +#define CNFGVK_FRAMES_IN_FLIGHT 3 +#endif + +#ifndef CNFGVK_IMAGE_ALLOCATION +// Enough memory for a 4k framebuffer. As this is a huge upper limit, it can be redefined +#define CNFGVK_IMAGE_ALLOCATION 32*1024*1024 +#endif + +#define CNFGVK_BATCH_SIZE ( sizeof( CNFGVertDataC ) + sizeof( CNFGVertDataV ) + sizeof( float[4] ) ) +#define CNFG_LOAD_FUNC( var, name ) PFN_##name var = (PFN_##name)vkGetInstanceProcAddr( CNFGVkInstance, #name ) + +static VkInstance CNFGVkInstance = NULL; +static VkPhysicalDevice CNFGPhysicalDevice = NULL; +static VkDevice CNFGLogicalDevice = NULL; +static VkQueue CNFGGraphicsQueue = NULL; +static VkQueue CNFGPresentQueue = NULL; +static VkSurfaceKHR CNFGVkSurface = NULL; + +static VkSwapchainKHR CNFGSwapchain = NULL; +static VkExtent2D CNFGSwapchainExtent = { 0 }; +static VkImage* CNFGSwapchainImages = NULL; +static VkImageView* CNFGSwapchainViews = NULL; +static uint32_t CNFGSwapchainImageCount = 0; +static VkFormat CNFGSwapchainFormat = 0; + +static VkPipelineLayout CNFGPipelineLayout = NULL; +static VkPipeline CNFGBatchPipeline = NULL; +static VkPipeline CNFGImagePipeline = NULL; +static VkCommandPool CNFGGraphicsPool = NULL; +static VkCommandBuffer CNFGGraphicsCommands[CNFGVK_FRAMES_IN_FLIGHT] = { NULL }; + +static VkSemaphore* CNFGPresentSemas = NULL; +static VkSemaphore* CNFGRenderSemas = NULL; +static VkFence CNFGRenderFences[CNFGVK_FRAMES_IN_FLIGHT] = { NULL }; + +static VkDescriptorSetLayout CNFGDescriptorSetLayout = NULL; +static VkDescriptorPool CNFGDescriptorPool = NULL; +static VkDescriptorSet CNFGDescriptorSet = NULL; + +static VkBuffer CNFGBatchBuffer = NULL; +static VkCommandBuffer CNFGBatchCommand = NULL; +static VkFence CNFGBatchFence = NULL; +static VkImage CNFGImage = NULL; +static VkImageView CNFGImageView = NULL; +static VkDeviceMemory CNFGBatchMemory = NULL; +static void* CNFGBatchMap = NULL; + +static VkDeviceMemory CNFGImageMemory = NULL; +static void* CNFGImageMap = NULL; +static VkSampler CNFGSampler = NULL; + +static uint32_t CNFGCurSwapchainImage = -1; +static int CNFGCurFlight = 0; +static int CNFGCurSema = 0; +static int CNFGScissors[4] = { -1 }; +static int CNFGVSyncOn = 1; + +static const char * CNFGInstanceExtensions[] = { +#ifdef CNFGVK_VALIDATION_LAYERS + "VK_EXT_debug_utils", +#endif + CNFG_SURFACE_EXTENSION +}; +#define CNFG_NUM_INSTANCE_EXT sizeof(CNFGInstanceExtensions)/sizeof(*CNFGInstanceExtensions) + +static const char * CNFGDeviceExtensions[] = { "VK_KHR_swapchain" }; +#define CNFG_NUM_DEVICE_EXT sizeof(CNFGDeviceExtensions)/sizeof(*CNFGDeviceExtensions) + +#ifdef CNFGVK_VALIDATION_LAYERS +static const char * CNFGInstanceLayers[] = { "VK_LAYER_KHRONOS_validation" }; +#define CNFG_NUM_INSTANCE_LAYER sizeof(CNFGInstanceLayers)/sizeof(*CNFGInstanceLayers) + +static VkDebugUtilsMessengerEXT CNFGDebugMessenger = NULL; +static VkBool32 VKAPI_CALL CNFGDebugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData, + void* pUserData +) +{ + // Change the color of the terminal to reflect the severity of the message + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ) printf( "\x1B[2;44m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ) printf( "\x1B[40m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) printf( "\x1B[43m" ); + if ( messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ) printf( "\x1B[41;30m" ); + + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT ) printf( "GENERAL: " ); + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT ) printf( "VALIDATION: " ); + if ( messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ) printf( "PERFORMANCE: " ); + + printf( "%s\x1B[0m\n", pCallbackData->pMessage ); + + return VK_FALSE; +} + +#endif + +static int CNFGScorePhysicalDevice( VkPhysicalDevice dev, uint32_t * didx, uint32_t * pidx ) +{ + VkPhysicalDeviceProperties prop; + vkGetPhysicalDeviceProperties( dev, &prop ); + + uint32_t score = 0, api = prop.apiVersion; + printf( "Device Name: %s, API Version: %i.%i.%i\n", prop.deviceName, VK_VERSION_MAJOR( api ), VK_VERSION_MINOR( api ), VK_VERSION_PATCH( api ) ); + if ( api < VK_VERSION_1_3 ) return -100000; + if ( prop.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ) score += 5000; + + VkQueueFamilyProperties* qfp = NULL; + uint32_t qfc = 0; + vkGetPhysicalDeviceQueueFamilyProperties( dev, &qfc, NULL ); + qfp = alloca( qfc * sizeof(VkQueueFamilyProperties) ); + vkGetPhysicalDeviceQueueFamilyProperties( dev, &qfc, qfp ); + for ( int i = 0; i < qfc; i++ ) + { + VkBool32 support = VK_FALSE; + if ( qfp[i].queueFlags & VK_QUEUE_GRAPHICS_BIT ) + { + *didx = i; + } + vkGetPhysicalDeviceSurfaceSupportKHR( dev, i, CNFGVkSurface, &support ); + if ( support ) *pidx = i; + if ( *didx != -1 && *pidx != -1 ) break; + } + + if ( *didx == *pidx ) score += 1000; + if ( *pidx == -1 ) return -100001; + + return score; +} + +#define CREATE_MODULE(var, name) \ + VkShaderModuleCreateInfo CI_##var = { \ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .pNext = NULL, \ + .codeSize = sizeof( name ), .pCode = name \ + }; \ + vkCreateShaderModule( CNFGLogicalDevice, &CI_##var, NULL, &var ); + +static void CNFGCreatePipelines() +{ + VkShaderModule vert, batch, img; + CREATE_MODULE( vert, CNFGVertShader ); + CREATE_MODULE( batch, CNFGBatchShader ); + CREATE_MODULE( img, CNFGImageShader ); + + VkPipelineShaderStageCreateInfo psci[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, + .stage = VK_SHADER_STAGE_VERTEX_BIT, .module = vert, .pName = "main" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = NULL, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, .module = batch, .pName = "main" + } + }; + + static const VkDynamicState dynstates[] = { + VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineDynamicStateCreateInfo dynamic = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .pNext = NULL, + .pDynamicStates = dynstates, .dynamicStateCount = sizeof( dynstates ) / sizeof( *dynstates ) + }; + VkPipelineVertexInputStateCreateInfo vinp = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .pNext = NULL + }; + VkPipelineInputAssemblyStateCreateInfo inpasm = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = NULL, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST + }; + VkPipelineViewportStateCreateInfo vp = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = NULL, + .pViewports = NULL, .pScissors = NULL, .scissorCount = 1, .viewportCount = 1 + }; + VkPipelineRasterizationStateCreateInfo rast = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = NULL, + .polygonMode = VK_POLYGON_MODE_FILL, .lineWidth = 1 + }; + VkPipelineMultisampleStateCreateInfo msaa = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = NULL, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, .sampleShadingEnable = VK_FALSE + }; + VkPipelineColorBlendAttachmentState batt = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_TRUE, .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA + }; + VkPipelineColorBlendStateCreateInfo blend = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .pNext = NULL, + .logicOpEnable = VK_FALSE, .logicOp = VK_LOGIC_OP_COPY, .attachmentCount = 1, .pAttachments = &batt + }; + + VkDescriptorSetLayoutBinding desc[] = { + { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT }, + { .binding = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT }, + { .binding = 2, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT } + }; + + VkDescriptorSetLayoutCreateInfo dci = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = sizeof(desc)/sizeof(*desc), .pBindings = desc + }; + + vkCreateDescriptorSetLayout( CNFGLogicalDevice, &dci, NULL, &CNFGDescriptorSetLayout ); + + VkPipelineLayoutCreateInfo lci = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 1, .pSetLayouts = &CNFGDescriptorSetLayout }; + vkCreatePipelineLayout( CNFGLogicalDevice, &lci, NULL, &CNFGPipelineLayout ); + + VkPipelineRenderingCreateInfo rend = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, .pNext = NULL, + .colorAttachmentCount = 1, .pColorAttachmentFormats = &CNFGSwapchainFormat + }; + VkGraphicsPipelineCreateInfo batci = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = &rend, + .stageCount = 2, .pStages = psci, .pVertexInputState = &vinp, .pInputAssemblyState = &inpasm, + .pViewportState = &vp, .pRasterizationState = &rast, .pMultisampleState = &msaa, + .pColorBlendState = &blend, .pDynamicState = &dynamic, .layout = CNFGPipelineLayout, + .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = -1, + }; + vkCreateGraphicsPipelines( CNFGLogicalDevice, NULL, 1, &batci, NULL, &CNFGBatchPipeline ); + + psci[1].module = img; + vkCreateGraphicsPipelines( CNFGLogicalDevice, NULL, 1, &batci, NULL, &CNFGImagePipeline ); +} + +static void CNFGDestroySwapchain() +{ + vkDeviceWaitIdle( CNFGLogicalDevice ); + for (int i = 0; i < CNFGSwapchainImageCount; i++ ) + { + vkDestroyImageView( CNFGLogicalDevice, CNFGSwapchainViews[i], NULL ); + vkDestroySemaphore( CNFGLogicalDevice, CNFGRenderSemas[i], NULL ); + vkDestroySemaphore( CNFGLogicalDevice, CNFGPresentSemas[i], NULL ); + } + vkDestroySwapchainKHR( CNFGLogicalDevice, CNFGSwapchain, NULL ); + free( CNFGSwapchainImages ); + free( CNFGSwapchainViews ); +} + +static void CNFGCreateSwapchain() +{ + VkSurfaceCapabilitiesKHR sc = { 0 }; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR( CNFGPhysicalDevice, CNFGVkSurface, &sc ); + + VkSurfaceFormatKHR formats[256] = {0}; + uint32_t numFormat = 256; + VkPresentModeKHR presentModes[256] = {0}; + uint32_t numPresent = 256; + int fmtIdx = 0; + VkPresentModeKHR present = -1; + vkGetPhysicalDeviceSurfaceFormatsKHR( CNFGPhysicalDevice, CNFGVkSurface, &numFormat, formats ); + vkGetPhysicalDeviceSurfacePresentModesKHR( CNFGPhysicalDevice, CNFGVkSurface, &numPresent, presentModes ); + for (int i = 0; i < numFormat; i++) + { + if ( formats[i].format == VK_FORMAT_B8G8R8A8_UNORM && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ) fmtIdx = i; + } + for (int i = 0; i < numPresent; i++) + { + if ( presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR ) present = presentModes[i]; + else if ( presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR && present == -1 ) present = presentModes[i]; + } + if ( CNFGVSyncOn || (present == -1) ) present = VK_PRESENT_MODE_FIFO_KHR; + + uint32_t minImg = sc.minImageCount > 3 ? sc.minImageCount : 3; + uint32_t imgCount = sc.minImageCount + 1; + if ( sc.maxImageCount > 0 && imgCount > sc.maxImageCount ) imgCount = sc.maxImageCount; + if ( sc.maxImageCount > 0 && minImg > sc.maxImageCount ) minImg = sc.maxImageCount; + + CNFGSwapchainFormat = formats[fmtIdx].format; + CNFGSwapchainExtent = sc.currentExtent; + if ( CNFGScissors[2] > CNFGSwapchainExtent.width ) CNFGScissors[2] = CNFGSwapchainExtent.width; + if ( CNFGScissors[3] > CNFGSwapchainExtent.height ) CNFGScissors[3] = CNFGSwapchainExtent.height; + + VkSwapchainCreateInfoKHR scci = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = NULL, + .flags = 0, .surface = CNFGVkSurface, .minImageCount = minImg, + .imageFormat = CNFGSwapchainFormat, .imageColorSpace = formats[fmtIdx].colorSpace, + .imageExtent = sc.currentExtent, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .preTransform = sc.currentTransform, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present, .clipped = VK_TRUE, .oldSwapchain = NULL + }; + + if ( CNFGGraphicsQueue != CNFGPresentQueue ) + { + uint32_t devdqf, devpqf; + CNFGScorePhysicalDevice( CNFGPhysicalDevice, &devdqf, &devpqf ); + uint32_t qfis[] = { devdqf, devpqf }; + + scci.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + scci.queueFamilyIndexCount = 2; + scci.pQueueFamilyIndices = qfis; + } + + vkCreateSwapchainKHR( CNFGLogicalDevice, &scci, NULL, &CNFGSwapchain ); + vkGetSwapchainImagesKHR( CNFGLogicalDevice, CNFGSwapchain, &CNFGSwapchainImageCount, NULL); + CNFGSwapchainImages = malloc( sizeof( VkImage ) * CNFGSwapchainImageCount ); + CNFGSwapchainViews = malloc( sizeof( VkImageView ) * CNFGSwapchainImageCount ); + CNFGPresentSemas = malloc( sizeof(VkSemaphore) * CNFGSwapchainImageCount ); + CNFGRenderSemas = malloc( sizeof(VkSemaphore) * CNFGSwapchainImageCount ); + vkGetSwapchainImagesKHR( CNFGLogicalDevice, CNFGSwapchain, &CNFGSwapchainImageCount, CNFGSwapchainImages); + + VkImageViewCreateInfo ivci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = NULL, + .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = CNFGSwapchainFormat, + .subresourceRange.levelCount = 1, .subresourceRange.layerCount = 1, + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT + }; + + for ( int i = 0; i < CNFGSwapchainImageCount; i++ ) + { + VkSemaphoreCreateInfo sema = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + vkCreateSemaphore( CNFGLogicalDevice, &sema, NULL, &CNFGPresentSemas[i] ); + vkCreateSemaphore( CNFGLogicalDevice, &sema, NULL, &CNFGRenderSemas[i] ); + + ivci.image = CNFGSwapchainImages[i]; + vkCreateImageView( CNFGLogicalDevice, &ivci, NULL, &CNFGSwapchainViews[i] ); + } +} + +static void CNFGCreateLogicalDevice( uint32_t * o_dqf, uint32_t * o_pqf ) +{ + uint32_t numDev = 0; + VkPhysicalDevice * dev; + vkEnumeratePhysicalDevices( CNFGVkInstance, &numDev, NULL ); + dev = alloca( sizeof(VkPhysicalDevice) * numDev ); + vkEnumeratePhysicalDevices( CNFGVkInstance, &numDev, dev ); + + int devIdx = -1, devScore = -1; + uint32_t devdqf = -1, devpqf = -1; + + for ( int i = 0; i < numDev; i++ ) + { + uint32_t newdqf = -1, newpqf = -1; + int newScore = CNFGScorePhysicalDevice( dev[i], &newdqf, &newpqf ); + if ( newScore > devScore ) + { + devIdx = i; + devScore = newScore; + devdqf = newdqf; + devpqf = newpqf; + } + } + + CNFGPhysicalDevice = dev[devIdx]; + float prio = 0; + VkDeviceQueueCreateInfo dqci = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = NULL, + .queueFamilyIndex = devdqf, + .queueCount = 1, + .pQueuePriorities = &prio + }; + + VkPhysicalDeviceVulkan13Features v13 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .pNext = NULL, + .dynamicRendering = VK_TRUE, + .synchronization2 = VK_TRUE + }; + VkPhysicalDeviceFeatures2 pdf = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .features = { 0 }, .pNext = &v13 }; + VkDeviceCreateInfo dci = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &pdf, + .pQueueCreateInfos = &dqci, .queueCreateInfoCount = 1, .ppEnabledExtensionNames = CNFGDeviceExtensions, .enabledExtensionCount = CNFG_NUM_DEVICE_EXT + }; + vkCreateDevice( CNFGPhysicalDevice, &dci, NULL, &CNFGLogicalDevice ); + vkGetDeviceQueue( CNFGLogicalDevice, devdqf, 0, &CNFGGraphicsQueue ); + vkGetDeviceQueue( CNFGLogicalDevice, devpqf, 0, &CNFGPresentQueue ); + + *o_dqf = devdqf; + *o_pqf = devpqf; +} + +static void CNFGAllocateMemory( uint64_t size, uint32_t bits, VkMemoryPropertyFlags props, VkDeviceMemory* outMem ) +{ + VkPhysicalDeviceMemoryProperties mem = { 0 }; + vkGetPhysicalDeviceMemoryProperties( CNFGPhysicalDevice, &mem ); + int memType = -1; + for ( int i = 0; i < mem.memoryTypeCount; i++ ) + { + if (( bits & ( 1 << i )) && ( mem.memoryTypes[i].propertyFlags & props ) == props ) + { + memType = i; + break; + } + } + + VkMemoryAllocateInfo alloc = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .allocationSize = size, .memoryTypeIndex = memType }; + vkAllocateMemory( CNFGLogicalDevice, &alloc, NULL, outMem ); +} + +static void CNFGCreateResources() +{ + VkBufferCreateInfo bbinfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = NULL, .size = CNFGVK_BATCH_SIZE, + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + vkCreateBuffer( CNFGLogicalDevice, &bbinfo, NULL, &CNFGBatchBuffer ); + VkMemoryRequirements memReq = { 0 }; + vkGetBufferMemoryRequirements( CNFGLogicalDevice, CNFGBatchBuffer, &memReq ); + CNFGAllocateMemory( memReq.size, memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &CNFGBatchMemory ); + vkBindBufferMemory( CNFGLogicalDevice, CNFGBatchBuffer, CNFGBatchMemory, 0 ); + + CNFGAllocateMemory( CNFGVK_IMAGE_ALLOCATION, 0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &CNFGImageMemory ); + + vkMapMemory( CNFGLogicalDevice, CNFGBatchMemory, 0, CNFGVK_BATCH_SIZE, 0, &CNFGBatchMap); + vkMapMemory( CNFGLogicalDevice, CNFGImageMemory, 0, CNFGVK_IMAGE_ALLOCATION, 0, &CNFGImageMap ); + + VkDescriptorPoolSize poolsize[] = { + { .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 2 }, + { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1 } + }; + VkDescriptorPoolCreateInfo poolci = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .maxSets = 1, .poolSizeCount = 2, .pPoolSizes = poolsize }; + vkCreateDescriptorPool( CNFGLogicalDevice, &poolci, NULL, &CNFGDescriptorPool ); + + VkDescriptorSetAllocateInfo setalloc = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, .descriptorPool = CNFGDescriptorPool, + .descriptorSetCount = 1, .pSetLayouts = &CNFGDescriptorSetLayout + }; + + VkSamplerCreateInfo sampci = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .minFilter = VK_FILTER_NEAREST, .magFilter = VK_FILTER_NEAREST, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE + }; + vkCreateSampler( CNFGLogicalDevice, &sampci, NULL, &CNFGSampler ); + + VkFenceCreateInfo fci = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; + vkAllocateDescriptorSets( CNFGLogicalDevice, &setalloc, &CNFGDescriptorSet ); + VkDescriptorBufferInfo infv = { .buffer = CNFGBatchBuffer, .offset = 0, .range = sizeof( CNFGVertDataV )+sizeof( float[4] ) }; + VkDescriptorBufferInfo infc = { .buffer = CNFGBatchBuffer, .offset = sizeof( CNFGVertDataV )+sizeof( float[4] ), .range = sizeof( CNFGVertDataC ) }; + + VkWriteDescriptorSet write[] = {{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 0, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .pBufferInfo = &infv + }, { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 1, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .pBufferInfo = &infc + }}; + vkUpdateDescriptorSets( CNFGLogicalDevice, 2, write, 0, NULL); + + vkCreateFence( CNFGLogicalDevice, &fci, NULL, &CNFGBatchFence ); + + for ( int i = 0; i < CNFGVK_FRAMES_IN_FLIGHT; i++ ) + { + VkFenceCreateInfo fence = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT }; + vkCreateFence( CNFGLogicalDevice, &fence, NULL, &CNFGRenderFences[i] ); + } +} + +void CNFGSetupBatchInternal() +{ + VkApplicationInfo app = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = "CNFG", + .pEngineName = "CNFG", + .applicationVersion = VK_MAKE_VERSION( 0, 9, 5 ), + .engineVersion = VK_MAKE_VERSION( 0, 9, 5 ), + .apiVersion = VK_API_VERSION_1_3 + }; + + VkInstanceCreateInfo instInf = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = NULL, + .pApplicationInfo = &app, + +#ifdef CNFGVK_VALIDATION_LAYERS + .ppEnabledLayerNames = CNFGInstanceLayers, + .enabledLayerCount = CNFG_NUM_INSTANCE_LAYER, +#endif + + .ppEnabledExtensionNames = CNFGInstanceExtensions, + .enabledExtensionCount = CNFG_NUM_INSTANCE_EXT + }; + + VkResult res = vkCreateInstance( &instInf, NULL, (VkInstance*)&CNFGVkInstance ); + if (res != VK_SUCCESS) { + fprintf( stderr, "Unable to create Vulkan instance with code %i\n", res ); + exit( -1 ); + } + +#ifdef CNFGVK_VALIDATION_LAYERS + VkDebugUtilsMessengerCreateInfoEXT msgInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = NULL, + .messageSeverity = (VkDebugUtilsMessageSeverityFlagsEXT){VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT}, + .messageType = (VkDebugUtilsMessageTypeFlagsEXT){VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT}, + .pfnUserCallback = CNFGDebugCallback + }; + CNFG_LOAD_FUNC( dbgmsg, vkCreateDebugUtilsMessengerEXT ); + dbgmsg( CNFGVkInstance, &msgInfo, NULL, &CNFGDebugMessenger ); +#endif + + CNFGCreateVkSurface( CNFGVkInstance, NULL, &CNFGVkSurface ); + + uint32_t devdqf, devpqf; + CNFGCreateLogicalDevice( &devdqf, &devpqf ); + CNFGCreateSwapchain(); + CNFGCreatePipelines(); + + VkCommandPoolCreateInfo cpci = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = NULL, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = devdqf + }; + vkCreateCommandPool( CNFGLogicalDevice, &cpci, NULL, &CNFGGraphicsPool ); + + VkCommandBufferAllocateInfo cbai = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, + .commandPool = CNFGGraphicsPool, .commandBufferCount = CNFGVK_FRAMES_IN_FLIGHT, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY + }; + vkAllocateCommandBuffers( CNFGLogicalDevice, &cbai, CNFGGraphicsCommands ); + cbai.commandBufferCount = 1; + vkAllocateCommandBuffers( CNFGLogicalDevice, &cbai, &CNFGBatchCommand ); + + CNFGCreateResources(); +} + +static void CNFGTransImageLayout( VkCommandBuffer cmd, VkImage img, VkImageLayout old, VkImageLayout new, VkAccessFlags2 srcf, VkAccessFlags2 dstf, VkPipelineStageFlags2 srcs, VkPipelineStageFlags2 dsts ) +{ + VkImageMemoryBarrier2 barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .pNext = NULL, + .srcStageMask = srcs, .dstStageMask = dsts, .srcAccessMask = srcf, .dstAccessMask = dstf, + .oldLayout = old, .newLayout = new, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = img, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .baseArrayLayer = 0, .layerCount = 1, .levelCount = 1 + } + }; + VkDependencyInfo dep = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .pNext = NULL, + .imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier + }; + vkCmdPipelineBarrier2( cmd, &dep ); +} + +static void CNFGBeginCmd( VkCommandBuffer cmd ) +{ + VkCommandBufferBeginInfo begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .pNext = NULL, .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT }; + vkResetCommandBuffer( cmd, 0 ); + vkBeginCommandBuffer( cmd, &begin ); +} + +static void CNFGEndCmd( VkCommandBuffer cmd, VkFence fence ) +{ + vkEndCommandBuffer( cmd ); + VkSubmitInfo submit = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .commandBufferCount = 1, .pCommandBuffers = &cmd }; + vkQueueSubmit( CNFGGraphicsQueue, 1, &submit, fence ); +} + +static void CNFGEndFrame() +{ + CNFGFlushRender(); + + CNFGBeginCmd( CNFGGraphicsCommands[CNFGCurFlight] ); + CNFGTransImageLayout( CNFGGraphicsCommands[CNFGCurFlight], CNFGSwapchainImages[CNFGCurSwapchainImage], + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 0, + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT + ); + vkEndCommandBuffer( CNFGGraphicsCommands[CNFGCurFlight] ); + + vkResetFences( CNFGLogicalDevice, 1, &CNFGRenderFences[CNFGCurFlight] ); + + VkPipelineStageFlags wait = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo sub = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = NULL, + .waitSemaphoreCount = 1, .pWaitSemaphores = &CNFGPresentSemas[CNFGCurSema], .pWaitDstStageMask = &wait, + .commandBufferCount = 1, .pCommandBuffers = &CNFGGraphicsCommands[CNFGCurFlight], .signalSemaphoreCount = 1, + .pSignalSemaphores = &CNFGRenderSemas[CNFGCurSema] + }; + vkQueueSubmit( CNFGGraphicsQueue, 1, &sub, CNFGRenderFences[CNFGCurFlight] ); + + VkPresentInfoKHR present = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = NULL, + .waitSemaphoreCount = 1, .pWaitSemaphores = &CNFGRenderSemas[CNFGCurSema], + .swapchainCount = 1, .pSwapchains = &CNFGSwapchain, .pImageIndices = &CNFGCurSwapchainImage, .pResults = NULL + }; + vkQueuePresentKHR( CNFGPresentQueue, &present ); + + CNFGCurSwapchainImage = -1; + CNFGCurFlight = (CNFGCurFlight + 1) % CNFGVK_FRAMES_IN_FLIGHT; + CNFGCurSema = (CNFGCurSema + 1) % CNFGSwapchainImageCount; +} + +static void CNFGBeginRender( VkCommandBuffer cmd ) +{ + if ( CNFGCurSwapchainImage == -1 ) CNFGSwapBuffers(); + + VkRenderingAttachmentInfo attach = { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = CNFGSwapchainViews[CNFGCurSwapchainImage], + .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + }; + VkRenderingInfo rendInfo = { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea = {.offset={0}, .extent=CNFGSwapchainExtent}, + .colorAttachmentCount = 1, .layerCount = 1, .pColorAttachments = &attach + }; + + vkCmdBeginRendering( cmd, &rendInfo ); + vkCmdSetViewport( cmd, 0, 1, (VkViewport[]){{ .x=0, .y=0, .width=CNFGSwapchainExtent.width, .height=CNFGSwapchainExtent.height, 0, 1 }} ); + if ( CNFGScissors[0] >= 0 ) vkCmdSetScissor( cmd, 0, 1, (VkRect2D[]){{ {CNFGScissors[0], CNFGScissors[1]}, {CNFGScissors[2], CNFGScissors[3]} }} ); + else vkCmdSetScissor( cmd, 0, 1, (VkRect2D[]){{ {0}, CNFGSwapchainExtent }} ); + vkCmdBindDescriptorSets( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGPipelineLayout, 0, 1, &CNFGDescriptorSet, 0, NULL ); +} + +void CNFGInternalResize( short x, short y ) +{ + if ( CNFGCurSwapchainImage != (uint32_t)-1 ) + { + CNFGCurSwapchainImage = -1; + CNFGCurFlight = (CNFGCurFlight + 1) % CNFGVK_FRAMES_IN_FLIGHT; + CNFGCurSema = (CNFGCurSema + 1) % CNFGSwapchainImageCount; + } + vkDeviceWaitIdle( CNFGLogicalDevice ); + + CNFGDestroySwapchain(); + CNFGCreateSwapchain(); + + memcpy( CNFGBatchMap, (float[]){ 2.f/x, 2.f/y, -1.f, -1.f }, sizeof( float[4] ) ); +} + +static void CNFGWaitForBatchBuffer() +{ + vkWaitForFences( CNFGLogicalDevice, 1, &CNFGBatchFence, VK_FALSE, UINT64_MAX ); + vkResetFences( CNFGLogicalDevice, 1, &CNFGBatchFence ); +} + +void CNFGEmitBackendTriangles( const float * vertices, const uint32_t * colors, int num_vertices ) +{ + CNFGWaitForBatchBuffer(); + + CNFGBeginCmd( CNFGBatchCommand ); + CNFGBeginRender( CNFGBatchCommand ); + + memcpy( CNFGBatchMap + sizeof( float[4] ), vertices, num_vertices * sizeof( float[3] ) ); + memcpy( CNFGBatchMap + sizeof( CNFGVertDataV ) + sizeof( float[4] ), colors, sizeof( uint32_t ) * num_vertices ); + + vkCmdBindPipeline( CNFGBatchCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGBatchPipeline ); + vkCmdDraw( CNFGBatchCommand, num_vertices, 1, 0, 0 ); + + vkCmdEndRendering( CNFGBatchCommand ); + CNFGEndCmd( CNFGBatchCommand, CNFGBatchFence ); +} + +void CNFGBlitImage( uint32_t * data, int x, int y, int w, int h ) +{ + CNFGFlushRender(); + CNFGWaitForBatchBuffer(); + + vkDestroyImageView( CNFGLogicalDevice, CNFGImageView, NULL ); + vkDestroyImage( CNFGLogicalDevice, CNFGImage, NULL ); + + VkImageCreateInfo imgci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .imageType = VK_IMAGE_TYPE_2D, .format = VK_FORMAT_R8G8B8A8_UNORM, + .extent = { w, h, 1 }, .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED + }; + vkCreateImage( CNFGLogicalDevice, &imgci, NULL, &CNFGImage); + vkBindImageMemory( CNFGLogicalDevice, CNFGImage, CNFGImageMemory, 0 ); + memcpy( CNFGImageMap, data, w*h*sizeof( uint32_t ) ); + + CNFGBeginCmd( CNFGBatchCommand ); + CNFGTransImageLayout( + CNFGBatchCommand, CNFGImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT + ); + + VkImageViewCreateInfo viewci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = CNFGImage, .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_R8G8B8A8_UNORM, .subresourceRange = { .aspectMask=VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + vkCreateImageView( CNFGLogicalDevice, &viewci, NULL, &CNFGImageView ); + + VkDescriptorImageInfo infi = {.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .sampler = CNFGSampler, .imageView = CNFGImageView }; + VkWriteDescriptorSet write = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = CNFGDescriptorSet, .dstBinding = 2, + .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &infi + }; + vkUpdateDescriptorSets( CNFGLogicalDevice, 1, &write, 0, NULL ); + + CNFGBeginRender( CNFGBatchCommand ); + + const float verts[] = { x, y, 0, x+w, y, 0, x+w, y+h, 0, x, y, 0, x+w, y+h, 0, x, y+h, 0 }; + const uint32_t uvs[] = { 0x00000000, 0xFF000000, 0xFFFF0000, 0x00000000, 0xFFFF0000, 0x00FF0000 }; + + memcpy( CNFGBatchMap + sizeof( float[4] ), verts, sizeof( verts ) ); + memcpy( CNFGBatchMap + sizeof( CNFGVertDataV ) + sizeof( float[4] ), uvs, sizeof( uvs ) ); + vkCmdBindPipeline( CNFGBatchCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, CNFGImagePipeline ); + vkCmdDraw( CNFGBatchCommand, 6, 1, 0, 0 ); + + vkCmdEndRendering( CNFGBatchCommand ); + CNFGEndCmd( CNFGBatchCommand, CNFGBatchFence ); +} + +// Could use vkCmdClearColorImage, but it doesn't respect scissors +void CNFGClearFrame() +{ + uint32_t temp = CNFGLastColor; + CNFGLastColor = CNFGBGColor; + CNFGEmitQuad( 0, 0, 0, CNFGSwapchainExtent.height, CNFGSwapchainExtent.width, 0, CNFGSwapchainExtent.width, CNFGSwapchainExtent.height ); + CNFGLastColor = temp; +} + +void CNFGSwapBuffers() +{ + if ( CNFGCurSwapchainImage != (uint32_t)-1 ) CNFGEndFrame(); + + vkWaitForFences( CNFGLogicalDevice, 1, &CNFGRenderFences[CNFGCurFlight], VK_TRUE, UINT64_MAX ); + vkAcquireNextImageKHR( CNFGLogicalDevice, CNFGSwapchain, UINT64_MAX, CNFGPresentSemas[CNFGCurSema], NULL, &CNFGCurSwapchainImage); + + CNFGBeginCmd( CNFGGraphicsCommands[CNFGCurFlight] ); + CNFGTransImageLayout( CNFGGraphicsCommands[CNFGCurFlight], CNFGSwapchainImages[CNFGCurSwapchainImage], + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 0, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT + ); + CNFGEndCmd( CNFGGraphicsCommands[CNFGCurFlight], NULL ); +} + +void CNFGSetVSync( int vson ) +{ + CNFGVSyncOn = vson; + CNFGInternalResize( CNFGSwapchainExtent.width, CNFGSwapchainExtent.height ); +} + +void CNFGSetScissors( int * xywh ) +{ + CNFGFlushRender(); + memcpy( CNFGScissors, xywh, sizeof(int)*4 ); +} + +void CNFGGetScissors( int * xywh ) +{ + memcpy( xywh, CNFGScissors, sizeof(int)*4 ); +} + +#endif +#endif + #ifdef CNFG3D //Copyright 2012-2017 <>< Charles Lohr //You may license this file under the MIT/x11, NewBSD, or any GPL license. diff --git a/vk/cnfg.glsl b/vk/cnfg.glsl new file mode 100644 index 0000000..a26a829 --- /dev/null +++ b/vk/cnfg.glsl @@ -0,0 +1,62 @@ +#version 460 + +#ifdef VERT +#define PASS out +#endif +#ifdef BATCH +#define PASS in +#endif +#ifdef IMG +#define PASS in +#endif + +layout (location = 0) PASS vec4 f_color; +#ifdef VERT +// Vertex Shader + +layout (set = 0, binding = 0) readonly buffer vert { + vec4 x; + float v[]; +}; + +layout (set = 0, binding = 1) readonly buffer color { + uint c[]; +}; + +vec4 colorHexToVec4(uint hex) { + vec4 colVec; + colVec.r = ((hex >> 24) & 0xFF)/255.0f; + colVec.g = ((hex >> 16) & 0xFF)/255.0f; + colVec.b = ((hex >> 8) & 0xFF)/255.0f; + colVec.a = ((hex >> 0) & 0xFF)/255.0f; + return colVec; +} + +void main() { + vec3 pos = vec3(v[gl_VertexIndex*3], v[gl_VertexIndex*3+1], v[gl_VertexIndex*3+2]); + uint col = c[gl_VertexIndex]; + f_color = colorHexToVec4(col); + gl_Position = vec4(pos.xy * x.xy + x.zw, 0, 1); +} + +#endif +#ifdef BATCH +// Fragment Shader (Batch) + +layout (location = 0) out vec4 i_color; + +void main() { + i_color = f_color; +} + +#endif +#ifdef IMG + +layout (location = 0) out vec4 i_color; +layout (set = 0, binding = 2) uniform sampler2D f_tex; + +void main() { + i_color = texture(f_tex, f_color.rg).abgr; +} + +#endif \ No newline at end of file diff --git a/vk/cnfgshader.h b/vk/cnfgshader.h new file mode 100644 index 0000000..6a4ea2e --- /dev/null +++ b/vk/cnfgshader.h @@ -0,0 +1,148 @@ +// Compiled SPIR-V Shaders for the CNFG Batched Vulkan renderer +// To recreate, run "make vk/cnfgshader.h" (requires glslang) + +// These shaders are in the tree so contributers don't need +// glslang to properly recreate rawdraw_sf.h + +static const uint32_t CNFGVertShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x00000077,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000003d,0x00000040,0x00000057, + 0x0000005d,0x00000064,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00070005,0x0000000c,0x6f6c6f63,0x78654872,0x65566f54,0x75283463,0x00003b31, + 0x00030005,0x0000000b,0x00786568,0x00040005,0x0000000f,0x566c6f63,0x00006365,0x00030005, + 0x00000039,0x00736f70,0x00040005,0x0000003b,0x74726576,0x00000000,0x00040006,0x0000003b, + 0x00000000,0x00000078,0x00040006,0x0000003b,0x00000001,0x00000076,0x00030005,0x0000003d, + 0x00000000,0x00060005,0x00000040,0x565f6c67,0x65747265,0x646e4978,0x00007865,0x00030005, + 0x00000053,0x006c6f63,0x00040005,0x00000055,0x6f6c6f63,0x00000072,0x00040006,0x00000055, + 0x00000000,0x00000063,0x00030005,0x00000057,0x00000000,0x00040005,0x0000005d,0x6f635f66, + 0x00726f6c,0x00040005,0x0000005e,0x61726170,0x0000006d,0x00060005,0x00000062,0x505f6c67, + 0x65567265,0x78657472,0x00000000,0x00060006,0x00000062,0x00000000,0x505f6c67,0x7469736f, + 0x006e6f69,0x00070006,0x00000062,0x00000001,0x505f6c67,0x746e696f,0x657a6953,0x00000000, + 0x00070006,0x00000062,0x00000002,0x435f6c67,0x4470696c,0x61747369,0x0065636e,0x00070006, + 0x00000062,0x00000003,0x435f6c67,0x446c6c75,0x61747369,0x0065636e,0x00030005,0x00000064, + 0x00000000,0x00040047,0x0000003a,0x00000006,0x00000004,0x00030047,0x0000003b,0x00000002, + 0x00040048,0x0000003b,0x00000000,0x00000018,0x00050048,0x0000003b,0x00000000,0x00000023, + 0x00000000,0x00040048,0x0000003b,0x00000001,0x00000018,0x00050048,0x0000003b,0x00000001, + 0x00000023,0x00000010,0x00030047,0x0000003d,0x00000018,0x00040047,0x0000003d,0x00000021, + 0x00000000,0x00040047,0x0000003d,0x00000022,0x00000000,0x00040047,0x00000040,0x0000000b, + 0x0000002a,0x00040047,0x00000054,0x00000006,0x00000004,0x00030047,0x00000055,0x00000002, + 0x00040048,0x00000055,0x00000000,0x00000018,0x00050048,0x00000055,0x00000000,0x00000023, + 0x00000000,0x00030047,0x00000057,0x00000018,0x00040047,0x00000057,0x00000021,0x00000001, + 0x00040047,0x00000057,0x00000022,0x00000000,0x00040047,0x0000005d,0x0000001e,0x00000000, + 0x00030047,0x00000062,0x00000002,0x00050048,0x00000062,0x00000000,0x0000000b,0x00000000, + 0x00050048,0x00000062,0x00000001,0x0000000b,0x00000001,0x00050048,0x00000062,0x00000002, + 0x0000000b,0x00000003,0x00050048,0x00000062,0x00000003,0x0000000b,0x00000004,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000, + 0x00040020,0x00000007,0x00000007,0x00000006,0x00030016,0x00000008,0x00000020,0x00040017, + 0x00000009,0x00000008,0x00000004,0x00040021,0x0000000a,0x00000009,0x00000007,0x00040020, + 0x0000000e,0x00000007,0x00000009,0x00040015,0x00000011,0x00000020,0x00000001,0x0004002b, + 0x00000011,0x00000012,0x00000018,0x0004002b,0x00000006,0x00000014,0x000000ff,0x0004002b, + 0x00000008,0x00000017,0x437f0000,0x0004002b,0x00000006,0x00000019,0x00000000,0x00040020, + 0x0000001a,0x00000007,0x00000008,0x0004002b,0x00000011,0x0000001d,0x00000010,0x0004002b, + 0x00000006,0x00000022,0x00000001,0x0004002b,0x00000011,0x00000025,0x00000008,0x0004002b, + 0x00000006,0x0000002a,0x00000002,0x0004002b,0x00000011,0x0000002d,0x00000000,0x0004002b, + 0x00000006,0x00000032,0x00000003,0x00040017,0x00000037,0x00000008,0x00000003,0x00040020, + 0x00000038,0x00000007,0x00000037,0x0003001d,0x0000003a,0x00000008,0x0004001e,0x0000003b, + 0x00000009,0x0000003a,0x00040020,0x0000003c,0x0000000c,0x0000003b,0x0004003b,0x0000003c, + 0x0000003d,0x0000000c,0x0004002b,0x00000011,0x0000003e,0x00000001,0x00040020,0x0000003f, + 0x00000001,0x00000011,0x0004003b,0x0000003f,0x00000040,0x00000001,0x0004002b,0x00000011, + 0x00000042,0x00000003,0x00040020,0x00000044,0x0000000c,0x00000008,0x0004002b,0x00000011, + 0x0000004e,0x00000002,0x0003001d,0x00000054,0x00000006,0x0003001e,0x00000055,0x00000054, + 0x00040020,0x00000056,0x0000000c,0x00000055,0x0004003b,0x00000056,0x00000057,0x0000000c, + 0x00040020,0x00000059,0x0000000c,0x00000006,0x00040020,0x0000005c,0x00000003,0x00000009, + 0x0004003b,0x0000005c,0x0000005d,0x00000003,0x0004001c,0x00000061,0x00000008,0x00000022, + 0x0006001e,0x00000062,0x00000009,0x00000008,0x00000061,0x00000061,0x00040020,0x00000063, + 0x00000003,0x00000062,0x0004003b,0x00000063,0x00000064,0x00000003,0x00040017,0x00000065, + 0x00000008,0x00000002,0x00040020,0x00000068,0x0000000c,0x00000009,0x0004002b,0x00000008, + 0x00000071,0x00000000,0x0004002b,0x00000008,0x00000072,0x3f800000,0x00050036,0x00000002, + 0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000038,0x00000039, + 0x00000007,0x0004003b,0x00000007,0x00000053,0x00000007,0x0004003b,0x00000007,0x0000005e, + 0x00000007,0x0004003d,0x00000011,0x00000041,0x00000040,0x00050084,0x00000011,0x00000043, + 0x00000041,0x00000042,0x00060041,0x00000044,0x00000045,0x0000003d,0x0000003e,0x00000043, + 0x0004003d,0x00000008,0x00000046,0x00000045,0x0004003d,0x00000011,0x00000047,0x00000040, + 0x00050084,0x00000011,0x00000048,0x00000047,0x00000042,0x00050080,0x00000011,0x00000049, + 0x00000048,0x0000003e,0x00060041,0x00000044,0x0000004a,0x0000003d,0x0000003e,0x00000049, + 0x0004003d,0x00000008,0x0000004b,0x0000004a,0x0004003d,0x00000011,0x0000004c,0x00000040, + 0x00050084,0x00000011,0x0000004d,0x0000004c,0x00000042,0x00050080,0x00000011,0x0000004f, + 0x0000004d,0x0000004e,0x00060041,0x00000044,0x00000050,0x0000003d,0x0000003e,0x0000004f, + 0x0004003d,0x00000008,0x00000051,0x00000050,0x00060050,0x00000037,0x00000052,0x00000046, + 0x0000004b,0x00000051,0x0003003e,0x00000039,0x00000052,0x0004003d,0x00000011,0x00000058, + 0x00000040,0x00060041,0x00000059,0x0000005a,0x00000057,0x0000002d,0x00000058,0x0004003d, + 0x00000006,0x0000005b,0x0000005a,0x0003003e,0x00000053,0x0000005b,0x0004003d,0x00000006, + 0x0000005f,0x00000053,0x0003003e,0x0000005e,0x0000005f,0x00050039,0x00000009,0x00000060, + 0x0000000c,0x0000005e,0x0003003e,0x0000005d,0x00000060,0x0004003d,0x00000037,0x00000066, + 0x00000039,0x0007004f,0x00000065,0x00000067,0x00000066,0x00000066,0x00000000,0x00000001, + 0x00050041,0x00000068,0x00000069,0x0000003d,0x0000002d,0x0004003d,0x00000009,0x0000006a, + 0x00000069,0x0007004f,0x00000065,0x0000006b,0x0000006a,0x0000006a,0x00000000,0x00000001, + 0x00050085,0x00000065,0x0000006c,0x00000067,0x0000006b,0x00050041,0x00000068,0x0000006d, + 0x0000003d,0x0000002d,0x0004003d,0x00000009,0x0000006e,0x0000006d,0x0007004f,0x00000065, + 0x0000006f,0x0000006e,0x0000006e,0x00000002,0x00000003,0x00050081,0x00000065,0x00000070, + 0x0000006c,0x0000006f,0x00050051,0x00000008,0x00000073,0x00000070,0x00000000,0x00050051, + 0x00000008,0x00000074,0x00000070,0x00000001,0x00070050,0x00000009,0x00000075,0x00000073, + 0x00000074,0x00000071,0x00000072,0x00050041,0x0000005c,0x00000076,0x00000064,0x0000002d, + 0x0003003e,0x00000076,0x00000075,0x000100fd,0x00010038,0x00050036,0x00000009,0x0000000c, + 0x00000000,0x0000000a,0x00030037,0x00000007,0x0000000b,0x000200f8,0x0000000d,0x0004003b, + 0x0000000e,0x0000000f,0x00000007,0x0004003d,0x00000006,0x00000010,0x0000000b,0x000500c2, + 0x00000006,0x00000013,0x00000010,0x00000012,0x000500c7,0x00000006,0x00000015,0x00000013, + 0x00000014,0x00040070,0x00000008,0x00000016,0x00000015,0x00050088,0x00000008,0x00000018, + 0x00000016,0x00000017,0x00050041,0x0000001a,0x0000001b,0x0000000f,0x00000019,0x0003003e, + 0x0000001b,0x00000018,0x0004003d,0x00000006,0x0000001c,0x0000000b,0x000500c2,0x00000006, + 0x0000001e,0x0000001c,0x0000001d,0x000500c7,0x00000006,0x0000001f,0x0000001e,0x00000014, + 0x00040070,0x00000008,0x00000020,0x0000001f,0x00050088,0x00000008,0x00000021,0x00000020, + 0x00000017,0x00050041,0x0000001a,0x00000023,0x0000000f,0x00000022,0x0003003e,0x00000023, + 0x00000021,0x0004003d,0x00000006,0x00000024,0x0000000b,0x000500c2,0x00000006,0x00000026, + 0x00000024,0x00000025,0x000500c7,0x00000006,0x00000027,0x00000026,0x00000014,0x00040070, + 0x00000008,0x00000028,0x00000027,0x00050088,0x00000008,0x00000029,0x00000028,0x00000017, + 0x00050041,0x0000001a,0x0000002b,0x0000000f,0x0000002a,0x0003003e,0x0000002b,0x00000029, + 0x0004003d,0x00000006,0x0000002c,0x0000000b,0x000500c2,0x00000006,0x0000002e,0x0000002c, + 0x0000002d,0x000500c7,0x00000006,0x0000002f,0x0000002e,0x00000014,0x00040070,0x00000008, + 0x00000030,0x0000002f,0x00050088,0x00000008,0x00000031,0x00000030,0x00000017,0x00050041, + 0x0000001a,0x00000033,0x0000000f,0x00000032,0x0003003e,0x00000033,0x00000031,0x0004003d, + 0x00000009,0x00000034,0x0000000f,0x000200fe,0x00000034,0x00010038 + +}; + +static const uint32_t CNFGBatchShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x0000000d,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000b,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00040005,0x00000009,0x6f635f69,0x00726f6c,0x00040005,0x0000000b,0x6f635f66, + 0x00726f6c,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000b,0x0000001e, + 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, + 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040020,0x0000000a,0x00000001, + 0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000007,0x0000000c,0x0000000b, + 0x0003003e,0x00000009,0x0000000c,0x000100fd,0x00010038 + +}; + +static const uint32_t CNFGImageShader[] = { + // 1115.4.0 + 0x07230203,0x00010600,0x0008000b,0x00000016,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0008000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00000010, + 0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001cc,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00040005,0x00000009,0x6f635f69,0x00726f6c,0x00040005,0x0000000d, + 0x65745f66,0x00000078,0x00040005,0x00000010,0x6f635f66,0x00726f6c,0x00040047,0x00000009, + 0x0000001e,0x00000000,0x00040047,0x0000000d,0x00000021,0x00000002,0x00040047,0x0000000d, + 0x00000022,0x00000000,0x00040047,0x00000010,0x0000001e,0x00000000,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007, + 0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008, + 0x00000009,0x00000003,0x00090019,0x0000000a,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a,0x00040020,0x0000000c, + 0x00000000,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000f, + 0x00000001,0x00000007,0x0004003b,0x0000000f,0x00000010,0x00000001,0x00040017,0x00000011, + 0x00000006,0x00000002,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, + 0x00000005,0x0004003d,0x0000000b,0x0000000e,0x0000000d,0x0004003d,0x00000007,0x00000012, + 0x00000010,0x0007004f,0x00000011,0x00000013,0x00000012,0x00000012,0x00000000,0x00000001, + 0x00050057,0x00000007,0x00000014,0x0000000e,0x00000013,0x0009004f,0x00000007,0x00000015, + 0x00000014,0x00000014,0x00000003,0x00000002,0x00000001,0x00000000,0x0003003e,0x00000009, + 0x00000015,0x000100fd,0x00010038 + +}; + diff --git a/vk/shadertemplate.h b/vk/shadertemplate.h new file mode 100644 index 0000000..dfa3589 --- /dev/null +++ b/vk/shadertemplate.h @@ -0,0 +1,17 @@ +// Compiled SPIR-V Shaders for the CNFG Batched Vulkan renderer +// To recreate, modify "cnfg.glsl" and run "make vk/cnfgshader.h" (requires glslang) + +// These shaders are in the tree so contributers don't need +// glslang to properly recreate rawdraw_sf.h + +static const uint32_t CNFGVertShader[] = { +#include "vk/verttemp" +}; + +static const uint32_t CNFGBatchShader[] = { +#include "vk/batchtemp" +}; + +static const uint32_t CNFGImageShader[] = { +#include "vk/imgtemp" +};