mirror of https://github.com/bjornbytes/lovr.git
Shader "improvements";
This commit is contained in:
parent
c7f4e11b0b
commit
886bfe18c1
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue