diff --git a/src/api/types/shader.c b/src/api/types/shader.c index a5cccf24..01edb4fe 100644 --- a/src/api/types/shader.c +++ b/src/api/types/shader.c @@ -37,7 +37,7 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des memcpy(dest, blob->data, elements * sizeof(int)); break; - case UNIFORM_SAMPLER: + case UNIFORM_TEXTURE: lovrThrow("Texture uniform '%s' can not be updated with a Blob", debug); } @@ -54,7 +54,7 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des switch (uniform->type) { case UNIFORM_FLOAT: *((float*) dest + i) = luaL_checknumber(L, -1); break; case UNIFORM_INT: *((int*) dest + i) = luaL_checkinteger(L, -1); break; - case UNIFORM_SAMPLER: *((Texture**) dest + i) = luax_checktype(L, -1, Texture); break; + case UNIFORM_TEXTURE: *((Texture**) dest + i) = luax_checktype(L, -1, Texture); break; default: break; } lua_pop(L, 1); @@ -64,7 +64,7 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des switch (uniform->type) { case UNIFORM_FLOAT: *((float*) dest + i) = luaL_checknumber(L, index + i); break; case UNIFORM_INT: *((int*) dest + i) = luaL_checkinteger(L, index + i); break; - case UNIFORM_SAMPLER: *((Texture**) dest + i) = luax_checktype(L, index + i, Texture); break; + case UNIFORM_TEXTURE: *((Texture**) dest + i) = luax_checktype(L, index + i, Texture); break; default: break; } } @@ -98,7 +98,7 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des *((int*) dest + i * components + j) = luaL_checkinteger(L, -1); break; - case UNIFORM_SAMPLER: lovrThrow("Unreachable"); + case UNIFORM_TEXTURE: lovrThrow("Unreachable"); } lua_pop(L, 1); } @@ -125,7 +125,7 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des *((float*) dest + i * components + j) = luaL_checknumber(L, -1); break; - case UNIFORM_SAMPLER: lovrThrow("Unreachable"); + case UNIFORM_TEXTURE: lovrThrow("Unreachable"); } } } @@ -193,7 +193,7 @@ int l_lovrShaderSend(lua_State* L) { case UNIFORM_FLOAT: lovrShaderSetFloat(shader, uniform->name, tempData.data, uniform->count * uniform->components); break; case UNIFORM_INT: lovrShaderSetInt(shader, uniform->name, tempData.data, uniform->count * uniform->components); break; case UNIFORM_MATRIX: lovrShaderSetMatrix(shader, uniform->name, tempData.data, uniform->count * uniform->components * uniform->components); break; - case UNIFORM_SAMPLER: lovrShaderSetTexture(shader, uniform->name, tempData.data, uniform->count); break; + case UNIFORM_TEXTURE: lovrShaderSetTexture(shader, uniform->name, tempData.data, uniform->count); break; } return 0; } diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 64d1e5b3..ad185954 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -247,6 +247,4 @@ void lovrGpuClear(Canvas** canvas, int canvasCount, Color* color, float* depth, void lovrGpuDraw(DrawCommand* command); void lovrGpuCompute(Shader* shader, int x, int y, int z); void lovrGpuPresent(); - -void lovrGpuBindTexture(Texture* texture, int slot); void lovrGpuDirtyTexture(int slot); diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c index 29921303..6fc0c2e2 100644 --- a/src/graphics/opengl.c +++ b/src/graphics/opengl.c @@ -23,6 +23,7 @@ // Types #define MAX_TEXTURES 16 +#define MAX_IMAGES 8 #define MAX_BLOCK_BUFFERS 8 #define LOVR_SHADER_POSITION 0 @@ -54,6 +55,7 @@ static struct { uint32_t indexBuffer; uint32_t program; Texture* textures[MAX_TEXTURES]; + Texture* images[MAX_IMAGES]; uint32_t blockBuffers[2][MAX_BLOCK_BUFFERS]; uint32_t vertexArray; uint32_t vertexBuffer; @@ -288,7 +290,13 @@ static UniformType getUniformType(GLenum type, const char* debug) { case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: - return UNIFORM_SAMPLER; +#ifdef GL_ARB_shader_image_load_store + case GL_IMAGE_2D: + case GL_IMAGE_3D: + case GL_IMAGE_CUBE: + case GL_IMAGE_2D_ARRAY: +#endif + return UNIFORM_TEXTURE; default: lovrThrow("Unsupported uniform type for uniform '%s'", debug); return UNIFORM_FLOAT; @@ -297,13 +305,6 @@ static UniformType getUniformType(GLenum type, const char* debug) { static int getUniformComponents(GLenum type) { switch (type) { - case GL_FLOAT: - case GL_INT: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_2D_ARRAY: - return 1; case GL_FLOAT_VEC2: case GL_INT_VEC2: case GL_FLOAT_MAT2: @@ -373,6 +374,16 @@ static const char* getUniformTypeName(const Uniform* uniform) { return ""; } +static Texture* lovrGpuGetDefaultTexture() { + if (!state.defaultTexture) { + TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA); + state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, false); + lovrRelease(textureData); + } + + return state.defaultTexture; +} + // GPU static void lovrGpuBindFramebuffer(uint32_t framebuffer) { @@ -389,25 +400,16 @@ static void lovrGpuBindIndexBuffer(uint32_t indexBuffer) { } } -void lovrGpuBindTexture(Texture* texture, int slot) { +static void lovrGpuBindTexture(Texture* texture, int slot) { lovrAssert(slot >= 0 && slot < MAX_TEXTURES, "Invalid texture slot %d", slot); - - if (!texture) { - if (!state.defaultTexture) { - TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA); - state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, false); - lovrRelease(textureData); - } - - texture = state.defaultTexture; - } + texture = texture ? texture : lovrGpuGetDefaultTexture(); if (texture != state.textures[slot]) { lovrRetain(texture); lovrRelease(state.textures[slot]); state.textures[slot] = texture; glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(texture->target, lovrTextureGetId(texture)); + glBindTexture(texture->target, texture->id); } } @@ -416,6 +418,20 @@ void lovrGpuDirtyTexture(int slot) { state.textures[slot] = NULL; } +static void lovrGpuBindImage(Texture* texture, int slot) { +#ifndef EMSCRIPTEN + lovrAssert(slot >= 0 && slot < MAX_IMAGES, "Invalid image slot %d", slot); + texture = texture ? texture : lovrGpuGetDefaultTexture(); + + if (texture != state.images[slot]) { + lovrRetain(texture); + lovrRelease(state.textures[slot]); + state.images[slot] = texture; + glBindImageTexture(slot, texture->id, 0, false, 0, GL_READ_WRITE, texture->slices[0]->format); + } +#endif +} + static void lovrGpuBindBlockBuffer(BlockType type, uint32_t buffer, int slot) { if (state.blockBuffers[type][slot] != buffer) { state.blockBuffers[type][slot] = buffer; @@ -1390,7 +1406,8 @@ static void lovrShaderSetupUniforms(Shader* shader) { uniform.location = glGetUniformLocation(program, uniform.name); uniform.type = getUniformType(glType, uniform.name); uniform.components = getUniformComponents(glType); - uniform.baseTextureSlot = (uniform.type == UNIFORM_SAMPLER) ? textureSlot : -1; + uniform.baseTextureSlot = uniform.type == UNIFORM_TEXTURE ? textureSlot : -1; + uniform.image = glType == GL_IMAGE_2D || glType == GL_IMAGE_3D || glType == GL_IMAGE_CUBE || glType == GL_IMAGE_2D_ARRAY; int blockIndex; glGetActiveUniformsiv(program, 1, &i, GL_UNIFORM_BLOCK_INDEX, &blockIndex); @@ -1432,7 +1449,7 @@ static void lovrShaderSetupUniforms(Shader* shader) { uniform.value.data = calloc(1, uniform.size); break; - case UNIFORM_SAMPLER: + case UNIFORM_TEXTURE: uniform.size = uniform.components * uniform.count * MAX(sizeof(Texture*), sizeof(int)); uniform.value.data = calloc(1, uniform.size); @@ -1477,7 +1494,7 @@ static void lovrShaderSetupUniforms(Shader* shader) { map_set(&shader->uniformMap, uniform.name, shader->uniforms.length); vec_push(&shader->uniforms, uniform); - textureSlot += (uniform.type == UNIFORM_SAMPLER) ? uniform.count : 0; + textureSlot += uniform.type == UNIFORM_TEXTURE ? uniform.count : 0; } } @@ -1598,7 +1615,7 @@ void lovrShaderBind(Shader* shader) { int i; Uniform* uniform; vec_foreach_ptr(&shader->uniforms, uniform, i) { - if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) { + if (uniform->type != UNIFORM_TEXTURE && !uniform->dirty) { continue; } @@ -1633,9 +1650,13 @@ void lovrShaderBind(Shader* shader) { } break; - case UNIFORM_SAMPLER: + case UNIFORM_TEXTURE: for (int i = 0; i < count; i++) { - lovrGpuBindTexture(uniform->value.textures[i], uniform->baseTextureSlot + i); + if (uniform->image) { + //lovrGpuBindImage(uniform->value.textures[i], uniform->baseTextureSlot + i); + } else { + lovrGpuBindTexture(uniform->value.textures[i], uniform->baseTextureSlot + i); + } } break; } @@ -1714,7 +1735,7 @@ void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int coun } void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int count) { - lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, count, sizeof(Texture*), "texture"); + lovrShaderSetUniform(shader, name, UNIFORM_TEXTURE, data, count, sizeof(Texture*), "texture"); } ShaderBlock* lovrShaderGetBlock(Shader* shader, const char* name) { diff --git a/src/graphics/shader.h b/src/graphics/shader.h index dff4ee77..e1bd7e80 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -23,7 +23,7 @@ typedef enum { UNIFORM_FLOAT, UNIFORM_MATRIX, UNIFORM_INT, - UNIFORM_SAMPLER + UNIFORM_TEXTURE } UniformType; typedef enum { @@ -55,6 +55,7 @@ typedef struct { Texture** textures; } value; int baseTextureSlot; + bool image; bool dirty; } Uniform;