mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
[vulkan] Add support for building and loading shaders
Shaders can be built as spv files and installed into $libdir/quakeforge/shaders or as spvc files and compiled into the engine. Loading supports $builtin/name to access builtin shaders, $shader/path to access external standard shaders and quake filesystem access for all other paths.
This commit is contained in:
parent
f1848bb5b7
commit
7fb335a215
9 changed files with 296 additions and 9 deletions
22
Makefile.am
22
Makefile.am
|
@ -107,6 +107,27 @@ qcautodep = $(join $(addsuffix $(DEPDIR)/,$(dir $(basename $(1)))),$(addsuffix .
|
|||
r_depfiles_remade=
|
||||
pas_depfiles_remade=
|
||||
|
||||
V_GLSLANG = $(V_GLSLANG_@AM_V@)
|
||||
V_GLSLANG_ = $(V_GLSLANG_@AM_DEFAULT_V@)
|
||||
V_GLSLANG_0 = @echo " GLSLANG " $@;
|
||||
V_GLSLANG_1 =
|
||||
|
||||
V_XXD = $(V_XXD_@AM_V@)
|
||||
V_XXD_ = $(V_XXD_@AM_DEFAULT_V@)
|
||||
V_XXD_0 = @echo " XXD " $@;
|
||||
V_XXD_1 =
|
||||
|
||||
%.spv: %
|
||||
@$(mkdir_p) $(builddir)/`dirname $@`
|
||||
$(V_GLSLANG)$(GLSLANGVALIDATOR) -V $< -o $@ > /dev/null
|
||||
|
||||
%.spvc: %
|
||||
@$(mkdir_p) $(builddir)/`dirname $@`
|
||||
$(V_GLSLANG)$(GLSLANGVALIDATOR) --vn `basename $< | tr . _` -V $< -o $@ > /dev/null
|
||||
|
||||
shaderdir = @shaderdir@
|
||||
shader_DATA =
|
||||
|
||||
include doc/Makemodule.am
|
||||
include RPM/Makemodule.am
|
||||
include debian/Makemodule.am
|
||||
|
@ -122,6 +143,7 @@ include tools/Makemodule.am
|
|||
include ruamoko/Makemodule.am
|
||||
|
||||
DISTCLEANFILES += $(r_depfiles_remade) $(pas_depfiles_remade)
|
||||
CLEANFILES += $(shader_DATA)
|
||||
|
||||
$(r_depfiles_remade):
|
||||
$(MKDIR_P) $(@D)
|
||||
|
|
|
@ -98,6 +98,19 @@ eval expanded_plugindir="$expanded_plugindir"
|
|||
AC_DEFINE_UNQUOTED(FS_PLUGINPATH, "$expanded_plugindir", [Define this to the path from which to load plugins])
|
||||
AC_SUBST(plugindir)
|
||||
|
||||
SHADERDIR="\${libdir}/quakeforge/shaders"
|
||||
if test "x$shaderdir" = "xauto" -o "x$shaderdir" = "xyes" -o "x$shaderdir" = "x"; then
|
||||
shaderdir="$SHADERDIR"
|
||||
elif test "x$shaderdir" = xno; then
|
||||
shaderdir="."
|
||||
else
|
||||
SHADERDIR="$shaderdir"
|
||||
fi
|
||||
eval expanded_shaderdir="$shaderdir"
|
||||
eval expanded_shaderdir="$expanded_shaderdir"
|
||||
AC_DEFINE_UNQUOTED(FS_SHADERPATH, "$expanded_shaderdir", [Define this to the path from which to load shaders])
|
||||
AC_SUBST(plugindir)
|
||||
|
||||
AC_ARG_WITH(gl-driver,
|
||||
[ --with-gl-driver=NAME Name of OpenGL driver DLL/DSO],
|
||||
gl_driver=$withval,
|
||||
|
|
|
@ -16,5 +16,6 @@ if test "x$HAVE_VULKAN" = xyes; then
|
|||
AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs])
|
||||
fi
|
||||
AC_SUBST(VULKAN_LIBS)
|
||||
AC_SUBST(GLSLANGVALIDATOR, [$glslangvalidator])
|
||||
|
||||
AM_CONDITIONAL(X11_VULKAN, test "x$HAVE_VULKAN" = "xyes")
|
||||
|
|
13
include/QF/Vulkan/shader.h
Normal file
13
include/QF/Vulkan/shader.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __QF_Vulkan_shader_h
|
||||
#define __QF_Vulkan_shader_h
|
||||
|
||||
struct qfv_device_s;
|
||||
struct vulkan_ctx_s;
|
||||
|
||||
VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device,
|
||||
const char *path);
|
||||
void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name,
|
||||
VkShaderModule module);
|
||||
void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name);
|
||||
|
||||
#endif//__QF_Vulkan_shader_h
|
|
@ -44,6 +44,8 @@ typedef struct vulkan_ctx_s {
|
|||
VkSampleCountFlagBits msaaSamples; // FIXME not here?
|
||||
struct hashlink_s *hashlinks; //FIXME want per thread
|
||||
VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain
|
||||
struct hashtab_s *shadermodules;
|
||||
struct shadermodule_s *shadermodule_freelist;
|
||||
|
||||
VkCommandPool cmdpool;
|
||||
VkCommandBuffer cmdbuffer;
|
||||
|
|
|
@ -78,7 +78,7 @@ V_SED_ = $(V_SED_@AM_DEFAULT_V@)
|
|||
V_SED_0 = @echo " SED " $@;
|
||||
V_SED_1 =
|
||||
|
||||
SUFFICES=.frag .vert .fc .vc .slc .glsl .plist .plc
|
||||
SUFFICES=.frag .vert .spv .spvc .fc .vc .slc .glsl .plist .plc
|
||||
.glsl.slc:
|
||||
$(V_SED)sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\
|
||||
$(am__mv) $@.t $@
|
||||
|
@ -224,6 +224,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \
|
|||
libs/video/renderer/vulkan/namehack.h \
|
||||
libs/video/renderer/vulkan/pipeline.c \
|
||||
libs/video/renderer/vulkan/renderpass.c \
|
||||
libs/video/renderer/vulkan/shader.c \
|
||||
libs/video/renderer/vulkan/swapchain.c \
|
||||
libs/video/renderer/vulkan/util.c \
|
||||
libs/video/renderer/vulkan/util.h \
|
||||
|
@ -233,29 +234,44 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \
|
|||
|
||||
libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src)
|
||||
|
||||
libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c ${vkparse_src} $(pipeline_gen)
|
||||
libs/video/renderer/vulkan/shader.lo: libs/video/renderer/vulkan/shader.c $(vkshader_c)
|
||||
|
||||
libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen)
|
||||
|
||||
|
||||
qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT)
|
||||
vkparse_cinc = libs/video/renderer/vulkan/vkparse.cinc
|
||||
vkparse_hinc = libs/video/renderer/vulkan/vkparse.hinc
|
||||
vkparse_src = \
|
||||
${vkparse_cinc} \
|
||||
${vkparse_hinc}
|
||||
$(vkparse_cinc) \
|
||||
$(vkparse_hinc)
|
||||
vkparse_plist = \
|
||||
$(srcdir)/libs/video/renderer/vulkan/vkparse.plist
|
||||
|
||||
passthrough_src = libs/video/renderer/vulkan/passthrough.vert
|
||||
passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc
|
||||
pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag
|
||||
pushcolor_c = libs/video/renderer/vulkan/pushcolor.frag.spvc
|
||||
|
||||
$(passthrough_c): $(passthrough_src)
|
||||
|
||||
$(pushcolor_c): $(pushcolor_src)
|
||||
|
||||
vkshader_c = \
|
||||
$(passthrough_c) \
|
||||
$(pushcolor_c)
|
||||
|
||||
V_VKGEN = $(V_VKGEN_@AM_V@)
|
||||
V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@)
|
||||
V_VKGEN_0 = @echo " VKGEN " $@;
|
||||
V_VKGEN_1 =
|
||||
|
||||
${vkparse_cinc}: $(vkgen) $(qwaq_curses) $(vkparse_plist)
|
||||
$(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) ${vkparse_cinc}.t ${vkparse_hinc}.t &&\
|
||||
$(am__mv) ${vkparse_cinc}.t ${vkparse_cinc} &&\
|
||||
$(am__mv) ${vkparse_hinc}.t ${vkparse_hinc}
|
||||
$(vkparse_cinc): $(vkgen) $(qwaq_curses) $(vkparse_plist)
|
||||
$(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) $(vkparse_cinc).t $(vkparse_hinc).t &&\
|
||||
$(am__mv) $(vkparse_cinc).t $(vkparse_cinc) &&\
|
||||
$(am__mv) $(vkparse_hinc).t $(vkparse_hinc)
|
||||
|
||||
${vkparse_hinc}: ${vkparse_cinc}
|
||||
$(vkparse_hinc): $(vkparse_cinc)
|
||||
# do nothing: hinc generated at the same time as cinc
|
||||
|
||||
CLEANFILES += \
|
||||
|
@ -263,7 +279,15 @@ CLEANFILES += \
|
|||
libs/video/renderer/glsl/*.fc \
|
||||
libs/video/renderer/glsl/*.slc \
|
||||
libs/video/renderer/vulkan/*.plc \
|
||||
libs/video/renderer/vulkan/*.spv \
|
||||
libs/video/renderer/vulkan/*.spvc \
|
||||
libs/video/renderer/vulkan/vkgen.sym \
|
||||
$(vkparse_src)
|
||||
|
||||
BUILT_SOURCES += $(shader_gen)
|
||||
|
||||
#shader_DATA += \
|
||||
# libs/video/renderer/vulkan/passthrough.vert.spv \
|
||||
# libs/video/renderer/vulkan/pushcolor.frag.spv
|
||||
|
||||
EXTRA_DIST += $(shader_DATA:.spv=)
|
||||
|
|
8
libs/video/renderer/vulkan/passthrough.vert
Normal file
8
libs/video/renderer/vulkan/passthrough.vert
Normal file
|
@ -0,0 +1,8 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec4 app_position;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = app_position;
|
||||
}
|
12
libs/video/renderer/vulkan/pushcolor.frag
Normal file
12
libs/video/renderer/vulkan/pushcolor.frag
Normal file
|
@ -0,0 +1,12 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
layout (push_constant) uniform ColorBlock {
|
||||
vec4 Color;
|
||||
} PushConstant;
|
||||
|
||||
void main()
|
||||
{
|
||||
frag_color = PushConstant.Color;
|
||||
}
|
192
libs/video/renderer/vulkan/shader.c
Normal file
192
libs/video/renderer/vulkan/shader.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
shader.c
|
||||
|
||||
Vulkan shader manager
|
||||
|
||||
Copyright (C) 2020 Bill Currie <bill@taniwha.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MATH_H
|
||||
# include <math.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "QF/alloc.h"
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/Vulkan/qf_vid.h"
|
||||
#include "QF/Vulkan/device.h"
|
||||
#include "QF/Vulkan/image.h"
|
||||
#include "QF/Vulkan/instance.h"
|
||||
#include "QF/Vulkan/renderpass.h"
|
||||
#include "QF/Vulkan/shader.h"
|
||||
|
||||
#include "vid_vulkan.h"
|
||||
|
||||
static
|
||||
#include "libs/video/renderer/vulkan/passthrough.vert.spvc"
|
||||
static
|
||||
#include "libs/video/renderer/vulkan/pushcolor.frag.spvc"
|
||||
|
||||
typedef struct shaderdata_s {
|
||||
const char *name;
|
||||
const uint32_t *data;
|
||||
size_t size;
|
||||
} shaderdata_t;
|
||||
|
||||
typedef struct shadermodule_s {
|
||||
char *name;
|
||||
union {
|
||||
VkShaderModule module;
|
||||
struct shadermodule_s *next;
|
||||
};
|
||||
} shadermodule_t;
|
||||
|
||||
static shaderdata_t builtin_shaders[] = {
|
||||
{ "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) },
|
||||
{ "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) },
|
||||
{}
|
||||
};
|
||||
|
||||
#define BUILTIN "$builtin/"
|
||||
#define BUILTIN_SIZE (sizeof (BUILTIN) - 1)
|
||||
#define SHADER "$shader/"
|
||||
#define SHADER_SIZE (sizeof (SHADER) - 1)
|
||||
|
||||
VkShaderModule
|
||||
QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path)
|
||||
{
|
||||
VkDevice dev = device->dev;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
|
||||
shaderdata_t _data = {};
|
||||
shaderdata_t *data = 0;
|
||||
dstring_t *path = 0;
|
||||
QFile *file;
|
||||
VkShaderModule shader = 0;
|
||||
|
||||
if (strncmp (shader_path, BUILTIN, BUILTIN_SIZE) == 0) {
|
||||
const char *name = shader_path + BUILTIN_SIZE;
|
||||
|
||||
for (int i = 0; builtin_shaders[i].name; i++) {
|
||||
if (strcmp (builtin_shaders[i].name, name) == 0) {
|
||||
data = &builtin_shaders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (strncmp (shader_path, SHADER, SHADER_SIZE)) {
|
||||
path = dstring_new ();
|
||||
dsprintf (path, "%s/%s", FS_SHADERPATH, shader_path + SHADER_SIZE);
|
||||
file = Qopen (path->str, "rbz");
|
||||
} else {
|
||||
file = QFS_FOpenFile (shader_path);
|
||||
}
|
||||
|
||||
if (file) {
|
||||
_data.size = Qfilesize (file);
|
||||
_data.data = malloc (_data.size);
|
||||
Qread (file, (void *) _data.data, _data.size);
|
||||
Qclose (file);
|
||||
data = &_data;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
VkShaderModuleCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0,
|
||||
0, data->size, data->data
|
||||
};
|
||||
|
||||
dfunc->vkCreateShaderModule (dev, &createInfo, 0, &shader);
|
||||
} else {
|
||||
Sys_MaskPrintf (SYS_VULKAN,
|
||||
"QFV_CreateShaderModule: could not find shader %s\n",
|
||||
shader_path);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
dstring_delete (path);
|
||||
}
|
||||
if (_data.data) {
|
||||
free ((void *) _data.data);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
static shadermodule_t *
|
||||
new_module (vulkan_ctx_t *ctx)
|
||||
{
|
||||
shadermodule_t *shadermodule;
|
||||
ALLOC (128, shadermodule_t, ctx->shadermodule, shadermodule);
|
||||
return shadermodule;
|
||||
}
|
||||
|
||||
static void
|
||||
del_module (shadermodule_t *shadermodule, vulkan_ctx_t *ctx)
|
||||
{
|
||||
free (shadermodule->name);
|
||||
FREE (ctx->shadermodule, shadermodule);
|
||||
}
|
||||
|
||||
static const char *
|
||||
sm_getkey (const void *sm, void *unused)
|
||||
{
|
||||
return ((shadermodule_t *) sm)->name;
|
||||
}
|
||||
|
||||
static void
|
||||
sm_free (void *sm, void *ctx)
|
||||
{
|
||||
del_module (sm, ctx);
|
||||
}
|
||||
|
||||
void
|
||||
QFV_RegisterShaderModule (vulkan_ctx_t *ctx, const char *name,
|
||||
VkShaderModule module)
|
||||
{
|
||||
if (!ctx->shadermodules) {
|
||||
ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0);
|
||||
}
|
||||
shadermodule_t *shadermodule = new_module (ctx);
|
||||
shadermodule->name = strdup (name);
|
||||
shadermodule->module = module;
|
||||
Hash_Add (ctx->shadermodules, shadermodule);
|
||||
}
|
||||
|
||||
void
|
||||
QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name)
|
||||
{
|
||||
if (!ctx->shadermodules) {
|
||||
return;
|
||||
}
|
||||
Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name));
|
||||
}
|
Loading…
Reference in a new issue