Shader "improvements";

This commit is contained in:
bjorn 2022-07-09 23:09:02 -07:00
parent c7f4e11b0b
commit 886bfe18c1
3 changed files with 89 additions and 74 deletions

View File

@ -61,6 +61,7 @@ StringEntry lovrCullMode[] = {
StringEntry lovrDefaultShader[] = {
[SHADER_UNLIT] = ENTRY("unlit"),
[SHADER_CUBE] = ENTRY("cube"),
[SHADER_PANO] = ENTRY("pano"),
[SHADER_FILL] = ENTRY("fill"),
[SHADER_FONT] = ENTRY("font"),
{ 0 }
@ -1011,57 +1012,77 @@ static int l_lovrGraphicsNewSampler(lua_State* L) {
return 1;
}
static Blob* luax_checkshadercode(lua_State* L, int index, ShaderStage stage) {
Blob* source;
size_t length;
const char* string = lua_tolstring(L, index, &length);
if (string && memchr(string, '\n', MIN(256, length))) {
void* data = malloc(length);
lovrAssert(data, "Out of memory");
memcpy(data, string, length);
source = lovrBlobCreate(data, length, "Shader code");
static ShaderSource luax_checkshadercode(lua_State* L, int index, ShaderStage stage, bool* allocated) {
ShaderSource source;
if (lua_isstring(L, index)) {
size_t length;
const char* string = lua_tolstring(L, index, &length);
if (memchr(string, '\n', MIN(256, length))) {
source.code = string;
source.size = length;
*allocated = false;
} else {
source.code = luax_readfile(string, &source.size);
lovrAssert(source.code, "Could not read shader code from %s", string);
*allocated = true;
}
} else if (lua_istable(L, index)) {
int length = luax_len(L, index);
size_t size = length * 4;
uint32_t* words = malloc(size);
source.size = length * sizeof(uint32_t);
uint32_t* words = malloc(source.size);
lovrAssert(words, "Out of memory");
source = lovrBlobCreate(words, size, "SPIR-V code");
source.code = words;
*allocated = true;
for (int i = 0; i < length; i++) {
lua_rawgeti(L, index, i + 1);
words[i] = lua_tointeger(L, -1);
words[i] = luax_checku32(L, -1);
lua_pop(L, 1);
}
} else {
source = luax_readblob(L, index, "Shader");
} else if (lua_isuserdata(L, index)) {
Blob* blob = luax_checktype(L, index, Blob);
source.code = blob->data;
source.size = blob->size;
*allocated = false;
}
Blob* code = lovrGraphicsCompileShader(stage, source);
lovrRelease(source, lovrBlobDestroy);
return code;
ShaderSource bytecode = lovrGraphicsCompileShader(stage, &source);
if (bytecode.code != source.code) {
if (*allocated) free((void*) source.code);
*allocated = true;
return bytecode;
}
return source;
}
static int l_lovrGraphicsCompileShader(lua_State* L) {
ShaderStage stage = luax_checkenum(L, 1, ShaderStage, NULL);
Blob* source = luax_checkshadercode(L, 2, stage);
Blob* output = lovrGraphicsCompileShader(stage, source);
luax_pushtype(L, Blob, output);
lovrRelease(output, lovrBlobDestroy);
lovrRelease(source, lovrBlobDestroy);
bool allocated;
ShaderSource spirv = luax_checkshadercode(L, 2, stage, &allocated);
if (!allocated) {
lua_settop(L, 2);
return 1;
} else {
Blob* blob = lovrBlobCreate((void*) spirv.code, spirv.size, "Compiled Shader Code");
luax_pushtype(L, Blob, blob);
}
return 1;
}
static int l_lovrGraphicsNewShader(lua_State* L) {
ShaderInfo info = { 0 };
bool allocated[2];
int index;
if (lua_gettop(L) == 1 || (lua_istable(L, 2) && luax_len(L, 2) == 0)) {
info.type = SHADER_COMPUTE;
info.stages[0] = luax_checkshadercode(L, 1, STAGE_COMPUTE);
info.source[0] = luax_checkshadercode(L, 1, STAGE_COMPUTE, &allocated[0]);
index = 2;
} else {
info.type = SHADER_GRAPHICS;
info.stages[0] = luax_checkshadercode(L, 1, STAGE_VERTEX);
info.stages[1] = luax_checkshadercode(L, 2, STAGE_FRAGMENT);
info.source[0] = luax_checkshadercode(L, 1, STAGE_VERTEX, &allocated[0]);
info.source[1] = luax_checkshadercode(L, 2, STAGE_FRAGMENT, &allocated[1]);
index = 3;
}
@ -1094,13 +1115,13 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
info.flags = flags.data;
info.flagCount = flags.length;
Shader* shader = lovrShaderCreate(&info);
lovrRelease(info.stages[0], lovrBlobDestroy);
lovrRelease(info.stages[1], lovrBlobDestroy);
arr_free(&flags);
Shader* shader = lovrShaderCreate(&info);
luax_pushtype(L, Shader, shader);
lovrRelease(shader, lovrShaderDestroy);
if (allocated[0]) free((void*) info.source[0].code);
if (allocated[1]) free((void*) info.source[1].code);
arr_free(&flags);
return 1;
}

View File

@ -1289,11 +1289,11 @@ const SamplerInfo* lovrSamplerGetInfo(Sampler* sampler) {
// Shader
Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
uint32_t spirv = 0x07230203;
ShaderSource lovrGraphicsCompileShader(ShaderStage stage, ShaderSource* source) {
uint32_t magic = 0x07230203;
if (source->size % 4 == 0 && source->size >= 4 && !memcmp(source->data, &spirv, 4)) {
return lovrRetain(source), source;
if (source->size % 4 == 0 && source->size >= 4 && !memcmp(source->code, &magic, 4)) {
return *source;
}
#ifdef LOVR_USE_GLSLANG
@ -1330,7 +1330,7 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
prefix,
(const char*) etc_shaders_lovr_glsl,
"#line 1\n",
source->data,
source->code,
suffixes[stage]
};
@ -1363,12 +1363,12 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
if (!glslang_shader_preprocess(shader, &input)) {
lovrThrow("Could not preprocess %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
return NULL;
return (ShaderSource) { NULL, 0 };
}
if (!glslang_shader_parse(shader, &input)) {
lovrThrow("Could not parse %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
return NULL;
return (ShaderSource) { NULL, 0 };
}
glslang_program_t* program = glslang_program_create();
@ -1376,25 +1376,25 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
if (!glslang_program_link(program, 0)) {
lovrThrow("Could not link shader:\n%s", glslang_program_get_info_log(program));
return NULL;
return (ShaderSource) { NULL, 0 };
}
glslang_program_SPIRV_generate(program, stages[stage]);
void* words = glslang_program_SPIRV_get_ptr(program);
size_t size = glslang_program_SPIRV_get_size(program) * 4;
void* data = malloc(size);
lovrAssert(data, "Out of memory");
memcpy(data, words, size);
Blob* blob = lovrBlobCreate(data, size, "SPIRV");
glslang_program_delete(program);
glslang_shader_delete(shader);
return blob;
return (ShaderSource) { data, size };
#else
lovrThrow("Could not compile shader: No shader compiler available");
return NULL;
return (ShaderSource) { NULL, 0 };
#endif
}
@ -1448,39 +1448,34 @@ Shader* lovrGraphicsGetDefaultShader(DefaultShader type) {
switch (type) {
case SHADER_UNLIT:
info.stages[0] = lovrBlobCreate((void*) lovr_shader_unlit_vert, sizeof(lovr_shader_unlit_vert), "Unlit Vertex Shader");
info.stages[1] = lovrBlobCreate((void*) lovr_shader_unlit_frag, sizeof(lovr_shader_unlit_frag), "Unlit Fragment Shader");
info.source[0] = (ShaderSource) { lovr_shader_unlit_vert, sizeof(lovr_shader_unlit_vert) };
info.source[1] = (ShaderSource) { lovr_shader_unlit_frag, sizeof(lovr_shader_unlit_frag) };
info.label = "unlit";
break;
case SHADER_CUBE:
info.stages[0] = lovrBlobCreate((void*) lovr_shader_cubemap_vert, sizeof(lovr_shader_cubemap_vert), "Cubemap Vertex Shader");
info.stages[1] = lovrBlobCreate((void*) lovr_shader_cubemap_frag, sizeof(lovr_shader_cubemap_frag), "Cubemap Fragment Shader");
info.source[0] = (ShaderSource) { lovr_shader_cubemap_vert, sizeof(lovr_shader_cubemap_vert) };
info.source[1] = (ShaderSource) { lovr_shader_cubemap_frag, sizeof(lovr_shader_cubemap_frag) };
info.label = "cubemap";
break;
case SHADER_PANO:
info.stages[0] = lovrBlobCreate((void*) lovr_shader_cubemap_vert, sizeof(lovr_shader_cubemap_vert), "Cubemap Vertex Shader");
info.stages[1] = lovrBlobCreate((void*) lovr_shader_equirect_frag, sizeof(lovr_shader_equirect_frag), "Equirect Fragment Shader");
info.source[0] = (ShaderSource) { lovr_shader_cubemap_vert, sizeof(lovr_shader_cubemap_vert) };
info.source[1] = (ShaderSource) { lovr_shader_equirect_frag, sizeof(lovr_shader_equirect_frag) };
info.label = "equirect";
break;
case SHADER_FILL:
info.stages[0] = lovrBlobCreate((void*) lovr_shader_fill_vert, sizeof(lovr_shader_fill_vert), "Fill Vertex Shader");
info.stages[1] = lovrBlobCreate((void*) lovr_shader_unlit_frag, sizeof(lovr_shader_unlit_frag), "Unlit Fragment Shader");
info.source[0] = (ShaderSource) { lovr_shader_fill_vert, sizeof(lovr_shader_fill_vert) };
info.source[1] = (ShaderSource) { lovr_shader_unlit_frag, sizeof(lovr_shader_unlit_frag) };
info.label = "fill";
break;
case SHADER_FONT:
info.stages[0] = lovrBlobCreate((void*) lovr_shader_unlit_vert, sizeof(lovr_shader_unlit_vert), "Unlit Vertex Shader");
info.stages[1] = lovrBlobCreate((void*) lovr_shader_font_frag, sizeof(lovr_shader_font_frag), "Font Fragment Shader");
info.source[0] = (ShaderSource) { lovr_shader_unlit_vert, sizeof(lovr_shader_unlit_vert) };
info.source[1] = (ShaderSource) { lovr_shader_font_frag, sizeof(lovr_shader_font_frag) };
info.label = "font";
break;
default: lovrUnreachable();
}
state.defaultShaders[type] = lovrShaderCreate(&info);
info.stages[0]->data = NULL;
info.stages[1]->data = NULL;
lovrRelease(info.stages[0], lovrBlobDestroy);
lovrRelease(info.stages[1], lovrBlobDestroy);
return state.defaultShaders[type];
return state.defaultShaders[type] = lovrShaderCreate(&info);
}
Shader* lovrShaderCreate(ShaderInfo* info) {
@ -1494,7 +1489,7 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
spv_result result;
spv_info spv[2] = { 0 };
for (uint32_t i = 0; i < stageCount; i++) {
result = spv_parse(info->stages[i]->data, info->stages[i]->size, &spv[i]);
result = spv_parse(info->source[i].code, info->source[i].size, &spv[i]);
lovrCheck(result == SPV_OK, "Failed to load Shader: %s\n", spv_result_to_string(result));
lovrCheck(spv[i].version <= 0x00010300, "Invalid SPIR-V version (up to 1.3 is supported)");
@ -1504,7 +1499,7 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
spv[i].attributes = tempAlloc(spv[i].attributeCount * sizeof(spv_attribute));
spv[i].resources = tempAlloc(spv[i].resourceCount * sizeof(spv_resource));
result = spv_parse(info->stages[i]->data, info->stages[i]->size, &spv[i]);
result = spv_parse(info->source[i].code, info->source[i].size, &spv[i]);
lovrCheck(result == SPV_OK, "Failed to load Shader: %s\n", spv_result_to_string(result));
checkShaderFeatures(spv[i].features, spv[i].featureCount);
@ -1682,13 +1677,13 @@ Shader* lovrShaderCreate(ShaderInfo* info) {
shader->layout = getLayout(slots, shader->resourceCount);
gpu_shader_info gpu = {
.stages[0] = { info->stages[0]->data, info->stages[0]->size },
.stages[0] = { info->source[0].code, info->source[0].size },
.pushConstantSize = shader->constantSize,
.label = info->label
};
if (info->stages[1]) {
gpu.stages[1] = (gpu_shader_stage) { info->stages[1]->data, info->stages[1]->size };
if (info->source[1].code) {
gpu.stages[1] = (gpu_shader_stage) { info->source[1].code, info->source[1].size };
}
if (info->type == SHADER_GRAPHICS) {
@ -2609,15 +2604,12 @@ static void lovrModelReskin(Model* model) {
}
if (!state.animator) {
Blob* source = lovrBlobCreate((void*) lovr_shader_animator_comp, sizeof(lovr_shader_animator_comp), NULL);
state.animator = lovrShaderCreate(&(ShaderInfo) {
.type = SHADER_COMPUTE,
.stages[0] = source,
.source[0] = { lovr_shader_animator_comp, sizeof(lovr_shader_animator_comp) },
.flags = &(ShaderFlag) { "local_size_x_id", 0, state.device.subgroupSize },
.label = "Animator"
.label = "animator"
});
source->data = NULL;
lovrRelease(source, lovrBlobDestroy);
}
gpu_pipeline* pipeline = state.pipelines.data[state.animator->computePipeline];
@ -4569,14 +4561,11 @@ void lovrPassCopyTallyToBuffer(Pass* pass, Tally* tally, Buffer* buffer, uint32_
}, 1);
if (!state.timeWizard) {
Blob* source = lovrBlobCreate((void*) lovr_shader_timewizard_comp, sizeof(lovr_shader_timewizard_comp), NULL);
state.timeWizard = lovrShaderCreate(&(ShaderInfo) {
.type = SHADER_COMPUTE,
.stages[0] = source,
.label = "Chronophage"
.source[0] = { lovr_shader_timewizard_comp, sizeof(lovr_shader_timewizard_comp) },
.label = "timewizard"
});
source->data = NULL;
lovrRelease(source, lovrBlobDestroy);
}
gpu_pipeline* pipeline = state.pipelines.data[state.timeWizard->computePipeline];

View File

@ -277,6 +277,11 @@ typedef enum {
STAGE_COMPUTE
} ShaderStage;
typedef struct {
const void* code;
size_t size;
} ShaderSource;
typedef struct {
const char* name;
uint32_t id;
@ -285,13 +290,13 @@ typedef struct {
typedef struct {
ShaderType type;
struct Blob* stages[2];
ShaderSource source[2];
uint32_t flagCount;
ShaderFlag* flags;
const char* label;
} ShaderInfo;
struct Blob* lovrGraphicsCompileShader(ShaderStage stage, struct Blob* source);
ShaderSource lovrGraphicsCompileShader(ShaderStage stage, ShaderSource* source);
Shader* lovrGraphicsGetDefaultShader(DefaultShader type);
Shader* lovrShaderCreate(ShaderInfo* info);
Shader* lovrShaderClone(Shader* parent, ShaderFlag* flags, uint32_t count);