mirror of https://github.com/bjornbytes/lovr.git
Compare commits
5 Commits
159352770f
...
72dd7ee0f2
Author | SHA1 | Date |
---|---|---|
bjorn | 72dd7ee0f2 | |
bjorn | 8e89026678 | |
bjorn | 886bfe18c1 | |
bjorn | c7f4e11b0b | |
bjorn | e8a5f02e7b |
|
@ -62,7 +62,9 @@ layout(location = 0) out vec4 PixelColors[1];
|
|||
layout(location = 10) out vec3 Normal;
|
||||
layout(location = 11) out vec4 Color;
|
||||
layout(location = 12) out vec2 UV;
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef GL_FRAGMENT_SHADER
|
||||
layout(location = 10) in vec3 Normal;
|
||||
layout(location = 11) in vec4 Color;
|
||||
layout(location = 12) in vec2 UV;
|
||||
|
|
|
@ -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 }
|
||||
|
@ -684,6 +685,17 @@ static int l_lovrGraphicsGetLimits(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsGetStats(lua_State* L) {
|
||||
GraphicsStats stats;
|
||||
lovrGraphicsGetStats(&stats);
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushinteger(L, stats.pipelineSwitches), lua_setfield(L, -2, "pipelineSwitches");
|
||||
lua_pushinteger(L, stats.bundleSwitches), lua_setfield(L, -2, "bundleSwitches");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsIsFormatSupported(lua_State* L) {
|
||||
TextureFormat format = luax_checkenum(L, 1, TextureFormat, NULL);
|
||||
uint32_t features = 0;
|
||||
|
@ -1000,58 +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);
|
||||
lovrAssert(code, "Could not compile shader");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1084,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;
|
||||
}
|
||||
|
||||
|
@ -1335,6 +1366,7 @@ static const luaL_Reg lovrGraphics[] = {
|
|||
{ "getDevice", l_lovrGraphicsGetDevice },
|
||||
{ "getFeatures", l_lovrGraphicsGetFeatures },
|
||||
{ "getLimits", l_lovrGraphicsGetLimits },
|
||||
{ "getStats", l_lovrGraphicsGetStats },
|
||||
{ "isFormatSupported", l_lovrGraphicsIsFormatSupported },
|
||||
{ "getBackground", l_lovrGraphicsGetBackground },
|
||||
{ "setBackground", l_lovrGraphicsSetBackground },
|
||||
|
|
|
@ -64,10 +64,27 @@ static int l_lovrShaderHasAttribute(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrShaderGetLocalWorkgroupSize(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
|
||||
if (!lovrShaderHasStage(shader, STAGE_COMPUTE)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t size[3];
|
||||
lovrShaderGetLocalWorkgroupSize(shader, size);
|
||||
lua_pushinteger(L, size[0]);
|
||||
lua_pushinteger(L, size[1]);
|
||||
lua_pushinteger(L, size[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrShader[] = {
|
||||
{ "clone", l_lovrShaderClone },
|
||||
{ "getType", l_lovrShaderGetType },
|
||||
{ "hasStage", l_lovrShaderHasStage },
|
||||
{ "hasAttribute", l_lovrShaderHasAttribute },
|
||||
{ "getLocalWorkgroupSize", l_lovrShaderGetLocalWorkgroupSize },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
#define OP_LENGTH(op) (op[0] >> 16)
|
||||
|
||||
static spv_result spv_parse_capability(spv_context* spv, const uint32_t* op, spv_info* info);
|
||||
static spv_result spv_parse_execution_mode(spv_context* spv, const uint32_t* op, spv_info* info);
|
||||
static spv_result spv_parse_name(spv_context* spv, const uint32_t* op, spv_info* info);
|
||||
static spv_result spv_parse_decoration(spv_context* spv, const uint32_t* op, spv_info* info);
|
||||
static spv_result spv_parse_type(spv_context* spv, const uint32_t* op, spv_info* info);
|
||||
|
@ -104,6 +105,8 @@ spv_result spv_parse(const void* source, uint32_t size, spv_info* info) {
|
|||
case 17: // OpCapability
|
||||
result = spv_parse_capability(&spv, op, info);
|
||||
break;
|
||||
case 16: // OpExecutionMode
|
||||
result = spv_parse_execution_mode(&spv, op, info);
|
||||
case 5: // OpName
|
||||
result = spv_parse_name(&spv, op, info);
|
||||
break;
|
||||
|
@ -179,6 +182,17 @@ static spv_result spv_parse_capability(spv_context* spv, const uint32_t* op, spv
|
|||
return SPV_OK;
|
||||
}
|
||||
|
||||
static spv_result spv_parse_execution_mode(spv_context* spv, const uint32_t* op, spv_info* info) {
|
||||
if (OP_LENGTH(op) != 6 || op[2] != 17) { // LocalSize
|
||||
return SPV_OK;
|
||||
}
|
||||
|
||||
info->localWorkgroupSize[0] = op[3];
|
||||
info->localWorkgroupSize[1] = op[4];
|
||||
info->localWorkgroupSize[2] = op[5];
|
||||
return SPV_OK;
|
||||
}
|
||||
|
||||
static spv_result spv_parse_name(spv_context* spv, const uint32_t* op, spv_info* info) {
|
||||
if (OP_LENGTH(op) < 3 || op[1] > spv->bound) {
|
||||
return SPV_INVALID;
|
||||
|
|
|
@ -56,6 +56,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t localWorkgroupSize[3];
|
||||
uint32_t featureCount;
|
||||
uint32_t specConstantCount;
|
||||
uint32_t pushConstantCount;
|
||||
|
|
|
@ -105,6 +105,7 @@ struct Shader {
|
|||
ShaderInfo info;
|
||||
uint32_t layout;
|
||||
uint32_t computePipeline;
|
||||
uint32_t localWorkgroupSize[3];
|
||||
uint32_t bufferMask;
|
||||
uint32_t textureMask;
|
||||
uint32_t samplerMask;
|
||||
|
@ -334,6 +335,7 @@ static struct {
|
|||
gpu_device_info device;
|
||||
gpu_features features;
|
||||
gpu_limits limits;
|
||||
GraphicsStats stats;
|
||||
float background[4];
|
||||
Texture* window;
|
||||
Font* defaultFont;
|
||||
|
@ -676,6 +678,10 @@ void lovrGraphicsGetLimits(GraphicsLimits* limits) {
|
|||
limits->pointSize = state.limits.pointSize;
|
||||
}
|
||||
|
||||
void lovrGraphicsGetStats(GraphicsStats* stats) {
|
||||
*stats = state.stats;
|
||||
}
|
||||
|
||||
bool lovrGraphicsIsFormatSupported(uint32_t format, uint32_t features) {
|
||||
uint8_t supports = state.features.formats[format];
|
||||
if (!features) return supports;
|
||||
|
@ -900,6 +906,9 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
|
|||
cleanupPasses();
|
||||
arr_clear(&state.passes);
|
||||
|
||||
state.stats.pipelineSwitches = 0;
|
||||
state.stats.bundleSwitches = 0;
|
||||
|
||||
if (present) {
|
||||
state.window->gpu = NULL;
|
||||
state.window->renderView = NULL;
|
||||
|
@ -1281,11 +1290,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
|
||||
|
@ -1313,21 +1322,23 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
|
|||
"Normal = normalize(NormalMatrix * VertexNormal);"
|
||||
"UV = VertexUV;"
|
||||
"Position = lovrmain();"
|
||||
"}\n#line 0\n",
|
||||
[STAGE_FRAGMENT] = "void main() { PixelColors[0] = lovrmain(); }\n#line 0\n",
|
||||
[STAGE_COMPUTE] = "void main() { lovrmain(); }\n#line 0\n"
|
||||
"}",
|
||||
[STAGE_FRAGMENT] = "void main() { PixelColors[0] = lovrmain(); }",
|
||||
[STAGE_COMPUTE] = "void main() { lovrmain(); }"
|
||||
};
|
||||
|
||||
const char* strings[] = {
|
||||
prefix,
|
||||
(const char*) etc_shaders_lovr_glsl,
|
||||
source->data,
|
||||
"#line 1\n",
|
||||
source->code,
|
||||
suffixes[stage]
|
||||
};
|
||||
|
||||
int lengths[] = {
|
||||
-1,
|
||||
etc_shaders_lovr_glsl_len,
|
||||
-1,
|
||||
source->size,
|
||||
-1
|
||||
};
|
||||
|
@ -1352,38 +1363,39 @@ Blob* lovrGraphicsCompileShader(ShaderStage stage, Blob* source) {
|
|||
glslang_shader_t* shader = glslang_shader_create(&input);
|
||||
|
||||
if (!glslang_shader_preprocess(shader, &input)) {
|
||||
lovrLog(LOG_INFO, "GFX", "Could not preprocess %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
|
||||
return NULL;
|
||||
lovrThrow("Could not preprocess %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
|
||||
return (ShaderSource) { NULL, 0 };
|
||||
}
|
||||
|
||||
if (!glslang_shader_parse(shader, &input)) {
|
||||
lovrLog(LOG_INFO, "GFX", "Could not parse %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
|
||||
return NULL;
|
||||
lovrThrow("Could not parse %s shader:\n%s", stageNames[stage], glslang_shader_get_info_log(shader));
|
||||
return (ShaderSource) { NULL, 0 };
|
||||
}
|
||||
|
||||
glslang_program_t* program = glslang_program_create();
|
||||
glslang_program_add_shader(program, shader);
|
||||
|
||||
if (!glslang_program_link(program, 0)) {
|
||||
lovrLog(LOG_INFO, "GFX", "Could not link shader:\n%s", glslang_program_get_info_log(program));
|
||||
return NULL;
|
||||
lovrThrow("Could not link shader:\n%s", glslang_program_get_info_log(program));
|
||||
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
|
||||
return NULL;
|
||||
lovrThrow("Could not compile shader: No shader compiler available");
|
||||
return (ShaderSource) { NULL, 0 };
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1437,39 +1449,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) {
|
||||
|
@ -1483,7 +1490,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)");
|
||||
|
||||
|
@ -1493,12 +1500,16 @@ 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);
|
||||
}
|
||||
|
||||
if (info->type == SHADER_COMPUTE) {
|
||||
memcpy(shader->localWorkgroupSize, spv[0].localWorkgroupSize, 3 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint32_t constantStage = spv[0].pushConstantSize > spv[1].pushConstantSize ? 0 : 1;
|
||||
uint32_t maxFlags = spv[0].specConstantCount + spv[1].specConstantCount;
|
||||
shader->constantCount = spv[constantStage].pushConstantCount;
|
||||
|
@ -1671,13 +1682,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) {
|
||||
|
@ -1758,6 +1769,10 @@ bool lovrShaderHasAttribute(Shader* shader, const char* name, uint32_t location)
|
|||
return false;
|
||||
}
|
||||
|
||||
void lovrShaderGetLocalWorkgroupSize(Shader* shader, uint32_t size[3]) {
|
||||
memcpy(size, shader->localWorkgroupSize, 3 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Material
|
||||
|
||||
Material* lovrMaterialCreate(MaterialInfo* info) {
|
||||
|
@ -2598,15 +2613,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];
|
||||
|
@ -2650,6 +2662,8 @@ static void lovrModelReskin(Model* model) {
|
|||
gpu_compute(state.stream, (skin->vertexCount + subgroupSize - 1) / subgroupSize, 1, 1);
|
||||
gpu_compute_end(state.stream);
|
||||
baseVertex += skin->vertexCount;
|
||||
state.stats.pipelineSwitches++;
|
||||
state.stats.bundleSwitches++;
|
||||
}
|
||||
|
||||
state.hasReskin = true;
|
||||
|
@ -3461,6 +3475,7 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
}
|
||||
|
||||
gpu_bind_pipeline(pass->stream, state.pipelines.data[index], false);
|
||||
state.stats.pipelineSwitches++;
|
||||
pipeline->dirty = false;
|
||||
}
|
||||
|
||||
|
@ -3492,6 +3507,7 @@ static void flushBindings(Pass* pass, Shader* shader) {
|
|||
gpu_bundle* bundle = getBundle(shader->layout);
|
||||
gpu_bundle_write(&bundle, &info, 1);
|
||||
gpu_bind_bundle(pass->stream, shader->gpu, set, bundle, NULL, 0);
|
||||
state.stats.bundleSwitches++;
|
||||
}
|
||||
|
||||
static void flushBuiltins(Pass* pass, Draw* draw, Shader* shader) {
|
||||
|
@ -3534,6 +3550,7 @@ static void flushBuiltins(Pass* pass, Draw* draw, Shader* shader) {
|
|||
gpu_bundle* bundle = getBundle(state.builtinLayout);
|
||||
gpu_bundle_write(&bundle, &bundleInfo, 1);
|
||||
gpu_bind_bundle(pass->stream, shader->gpu, 0, bundle, NULL, 0);
|
||||
state.stats.bundleSwitches++;
|
||||
}
|
||||
|
||||
float m[16];
|
||||
|
@ -3557,9 +3574,11 @@ static void flushBuiltins(Pass* pass, Draw* draw, Shader* shader) {
|
|||
static void flushMaterial(Pass* pass, Draw* draw, Shader* shader) {
|
||||
if (draw->material && draw->material != pass->pipeline->material) {
|
||||
gpu_bind_bundle(pass->stream, shader->gpu, 1, draw->material->bundle, NULL, 0);
|
||||
state.stats.bundleSwitches++;
|
||||
pass->materialDirty = true;
|
||||
} else if (pass->materialDirty) {
|
||||
gpu_bind_bundle(pass->stream, shader->gpu, 1, pass->pipeline->material->bundle, NULL, 0);
|
||||
state.stats.bundleSwitches++;
|
||||
pass->materialDirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -4466,6 +4485,7 @@ void lovrPassCompute(Pass* pass, uint32_t x, uint32_t y, uint32_t z, Buffer* ind
|
|||
|
||||
if (pass->pipeline->dirty) {
|
||||
gpu_bind_pipeline(pass->stream, pipeline, true);
|
||||
state.stats.pipelineSwitches++;
|
||||
pass->pipeline->dirty = false;
|
||||
}
|
||||
|
||||
|
@ -4550,14 +4570,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];
|
||||
|
@ -4586,6 +4603,8 @@ void lovrPassCopyTallyToBuffer(Pass* pass, Tally* tally, Buffer* buffer, uint32_
|
|||
gpu_push_constants(pass->stream, shader, &constants, sizeof(constants));
|
||||
gpu_compute(pass->stream, (count + 31) / 32, 1, 1);
|
||||
gpu_compute_end(pass->stream);
|
||||
state.stats.pipelineSwitches++;
|
||||
state.stats.bundleSwitches++;
|
||||
|
||||
trackBuffer(pass, buffer, GPU_PHASE_SHADER_COMPUTE, GPU_CACHE_STORAGE_WRITE);
|
||||
} else {
|
||||
|
|
|
@ -72,6 +72,11 @@ typedef struct {
|
|||
float pointSize;
|
||||
} GraphicsLimits;
|
||||
|
||||
typedef struct {
|
||||
uint32_t pipelineSwitches;
|
||||
uint32_t bundleSwitches;
|
||||
} GraphicsStats;
|
||||
|
||||
enum {
|
||||
TEXTURE_FEATURE_SAMPLE = (1 << 0),
|
||||
TEXTURE_FEATURE_FILTER = (1 << 1),
|
||||
|
@ -89,6 +94,7 @@ void lovrGraphicsDestroy(void);
|
|||
void lovrGraphicsGetDevice(GraphicsDevice* device);
|
||||
void lovrGraphicsGetFeatures(GraphicsFeatures* features);
|
||||
void lovrGraphicsGetLimits(GraphicsLimits* limits);
|
||||
void lovrGraphicsGetStats(GraphicsStats* stats);
|
||||
bool lovrGraphicsIsFormatSupported(uint32_t format, uint32_t features);
|
||||
|
||||
void lovrGraphicsGetBackground(float background[4]);
|
||||
|
@ -271,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;
|
||||
|
@ -279,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);
|
||||
|
@ -293,6 +304,7 @@ void lovrShaderDestroy(void* ref);
|
|||
const ShaderInfo* lovrShaderGetInfo(Shader* shader);
|
||||
bool lovrShaderHasStage(Shader* shader, ShaderStage stage);
|
||||
bool lovrShaderHasAttribute(Shader* shader, const char* name, uint32_t location);
|
||||
void lovrShaderGetLocalWorkgroupSize(Shader* shader, uint32_t size[3]);
|
||||
|
||||
// Material
|
||||
|
||||
|
|
Loading…
Reference in New Issue