From ee7544eba868f3e8849b1ffeb7f5da2fbb4ca44d Mon Sep 17 00:00:00 2001 From: bjorn Date: Tue, 8 Jan 2019 09:14:10 -0800 Subject: [PATCH] ShaderBlock:getValue; Shader:send vector fixes; Allows you to read back values from a ShaderBlock. - This is also probably useful for Shaders. - This creates SO MANY tables. It feels so bad to expose this. But also it's the only way to read values back from a compute operation, so it's pretty indispensable. In the future there could be a Blob variant. --- src/api/graphics.c | 7 ++++- src/api/types/shader.c | 11 +++++--- src/api/types/shaderBlock.c | 51 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/api/graphics.c b/src/api/graphics.c index ea770251..6a75ea2d 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -936,6 +936,7 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) { BlockType type = BLOCK_UNIFORM; BufferUsage usage = USAGE_DYNAMIC; + bool readable = false; if (lua_istable(L, 2)) { lua_getfield(L, 2, "usage"); @@ -945,11 +946,15 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) { lua_getfield(L, 2, "writable"); type = lua_toboolean(L, -1) ? BLOCK_STORAGE : BLOCK_UNIFORM; lua_pop(L, 1); + + lua_getfield(L, 2, "readable"); + readable = lua_toboolean(L, -1); + lua_pop(L, 1); } lovrAssert(type != BLOCK_STORAGE || lovrGraphicsGetSupported()->computeShaders, "Writable ShaderBlocks are not supported on this system"); size_t size = lovrShaderComputeUniformLayout(&uniforms); - Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_STORAGE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, false); + Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_STORAGE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, readable); ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms); luax_pushobject(L, block); vec_deinit(&uniforms); diff --git a/src/api/types/shader.c b/src/api/types/shader.c index 79cf3b1d..2961fdb8 100644 --- a/src/api/types/shader.c +++ b/src/api/types/shader.c @@ -86,10 +86,13 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des } } } else { - luaL_checktype(L, index, LUA_TTABLE); - lua_rawgeti(L, index, 1); - bool wrappedTable = !lua_isnumber(L, -1); - lua_pop(L, 1); + bool wrappedTable = false; + + if (lua_istable(L, index)) { + lua_rawgeti(L, index, 1); + wrappedTable = !lua_isnumber(L, -1); + lua_pop(L, 1); + } if (wrappedTable) { int length = lua_objlen(L, index); diff --git a/src/api/types/shaderBlock.c b/src/api/types/shaderBlock.c index 62fffe40..c1f2017a 100644 --- a/src/api/types/shaderBlock.c +++ b/src/api/types/shaderBlock.c @@ -47,6 +47,56 @@ int l_lovrShaderBlockSend(lua_State* L) { } } +int l_lovrShaderBlockGetValue(lua_State* L) { + ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); + const char* name = luaL_checkstring(L, 2); + const Uniform* uniform = lovrShaderBlockGetUniform(block, name); + lovrAssert(uniform, "Unknown uniform for ShaderBlock '%s'", name); + Buffer* buffer = lovrShaderBlockGetBuffer(block); + lovrAssert(lovrBufferIsReadable(buffer), "ShaderBlock:getValue requires the ShaderBlock to be created with the readable flag"); + union { float* floats; int* ints; } data = { .floats = lovrBufferMap(buffer, uniform->offset) }; + int components = uniform->components; + + if (uniform->type == UNIFORM_MATRIX) { + components *= components; + } + + lua_createtable(L, uniform->count, 0); + for (int i = 0; i < uniform->count; i++) { + if (components == 1) { + switch (uniform->type) { + case UNIFORM_FLOAT: + lua_pushnumber(L, data.floats[i]); + lua_rawseti(L, -2, i + 1); + break; + case UNIFORM_INT: + lua_pushinteger(L, data.ints[i]); + lua_rawseti(L, -2, i + 1); + break; + default: break; + } + } else { + lua_createtable(L, components, 0); + for (int j = 0; j < components; j++) { + switch (uniform->type) { + case UNIFORM_FLOAT: + case UNIFORM_MATRIX: + lua_pushnumber(L, data.floats[i * components + j]); + lua_rawseti(L, -2, j + 1); + break; + case UNIFORM_INT: + lua_pushinteger(L, data.ints[i * components + j]); + lua_rawseti(L, -2, j + 1); + break; + default: break; + } + } + lua_rawseti(L, -2, i + 1); + } + } + return 1; +} + int l_lovrShaderBlockGetShaderCode(lua_State* L) { ShaderBlock* block = luax_checktype(L, 1, ShaderBlock); const char* blockName = luaL_checkstring(L, 2); @@ -61,6 +111,7 @@ const luaL_Reg lovrShaderBlock[] = { { "getSize", l_lovrShaderBlockGetSize }, { "getOffset", l_lovrShaderBlockGetOffset }, { "send", l_lovrShaderBlockSend }, + { "getValue", l_lovrShaderBlockGetValue }, { "getShaderCode", l_lovrShaderBlockGetShaderCode }, { NULL, NULL } };