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.
This commit is contained in:
bjorn 2019-01-08 09:14:10 -08:00 committed by Bjorn Swenson
parent 3d2488a577
commit ee7544eba8
3 changed files with 64 additions and 5 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 }
};