Texture API;

Except newTexture because it's hard or something
This commit is contained in:
bjorn 2022-04-29 20:56:23 -07:00
parent c60116ad61
commit e80d254dc6
6 changed files with 190 additions and 7 deletions

View File

@ -422,6 +422,7 @@ if(LOVR_ENABLE_GRAPHICS)
src/modules/graphics/graphics.c
src/api/l_graphics.c
src/api/l_graphics_buffer.c
src/api/l_graphics_texture.c
)
if(LOVR_USE_VULKAN)

View File

@ -56,6 +56,7 @@ extern StringEntry lovrStencilAction[];
extern StringEntry lovrTextureFeature[];
extern StringEntry lovrTextureFormat[];
extern StringEntry lovrTextureType[];
extern StringEntry lovrTextureUsage[];
extern StringEntry lovrTimeUnit[];
extern StringEntry lovrUniformAccess[];
extern StringEntry lovrVerticalAlign[];

View File

@ -62,6 +62,22 @@ StringEntry lovrTextureFeature[] = {
{ 0 }
};
StringEntry lovrTextureType[] = {
[TEXTURE_2D] = ENTRY("2d"),
[TEXTURE_3D] = ENTRY("3d"),
[TEXTURE_CUBE] = ENTRY("cube"),
[TEXTURE_ARRAY] = ENTRY("array"),
{ 0 }
};
StringEntry lovrTextureUsage[] = {
[0] = ENTRY("sample"),
[1] = ENTRY("render"),
[2] = ENTRY("storage"),
[3] = ENTRY("copy"),
{ 0 }
};
static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[] = {
[FIELD_I8x4] = { 4, 1, 4, 4 },
[FIELD_U8x4] = { 4, 1, 4, 4 },
@ -429,10 +445,12 @@ static const luaL_Reg lovrGraphics[] = {
};
extern const luaL_Reg lovrBuffer[];
extern const luaL_Reg lovrTexture[];
int luaopen_lovr_graphics(lua_State* L) {
lua_newtable(L);
luax_register(L, lovrGraphics);
luax_registertype(L, Buffer);
luax_registertype(L, Texture);
return 1;
}

View File

@ -0,0 +1,117 @@
#include "api.h"
#include "util.h"
#include "graphics/graphics.h"
#include <lua.h>
#include <lauxlib.h>
static int l_lovrTextureNewView(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
TextureViewInfo info = { .parent = texture };
info.type = luax_checkenum(L, 2, TextureType, NULL);
info.layerIndex = luaL_optinteger(L, 3, 1) - 1;
info.layerCount = luaL_optinteger(L, 4, 1);
info.levelIndex = luaL_optinteger(L, 5, 1) - 1;
info.levelCount = luaL_optinteger(L, 6, 0);
Texture* view = lovrTextureCreateView(&info);
luax_pushtype(L, Texture, view);
lovrRelease(view, lovrTextureDestroy);
return 1;
}
static int l_lovrTextureIsView(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
lua_pushboolean(L, !!lovrTextureGetInfo(texture)->parent);
return 1;
}
static int l_lovrTextureGetParent(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
luax_pushtype(L, Texture, info->parent);
return 1;
}
static int l_lovrTextureGetType(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
luax_pushenum(L, TextureType, info->type);
return 1;
}
static int l_lovrTextureGetFormat(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
luax_pushenum(L, TextureFormat, info->format);
return 1;
}
static int l_lovrTextureGetWidth(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->width);
return 1;
}
static int l_lovrTextureGetHeight(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->height);
return 1;
}
static int l_lovrTextureGetDepth(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->depth);
return 1;
}
static int l_lovrTextureGetDimensions(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->width);
lua_pushinteger(L, info->height);
lua_pushinteger(L, info->depth);
return 3;
}
static int l_lovrTextureGetMipmapCount(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->mipmaps);
return 1;
}
static int l_lovrTextureGetSampleCount(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
lua_pushinteger(L, info->samples);
return 1;
}
static int l_lovrTextureHasUsage(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture);
const TextureInfo* info = lovrTextureGetInfo(texture);
luaL_checkany(L, 2);
int top = lua_gettop(L);
for (int i = 2; i <= top; i++) {
int bit = luax_checkenum(L, i, TextureUsage, NULL);
if (~info->usage & (1 << bit)) {
lua_pushboolean(L, false);
}
}
lua_pushboolean(L, true);
return 1;
}
const luaL_Reg lovrTexture[] = {
{ "getType", l_lovrTextureGetType },
{ "getFormat", l_lovrTextureGetFormat },
{ "getWidth", l_lovrTextureGetWidth },
{ "getHeight", l_lovrTextureGetHeight },
{ "getDepth", l_lovrTextureGetDepth },
{ "getDimensions", l_lovrTextureGetDimensions },
{ "getMipmapCount", l_lovrTextureGetMipmapCount },
{ "getSampleCount", l_lovrTextureGetSampleCount },
{ NULL, NULL }
};

View File

@ -286,13 +286,13 @@ void lovrBufferClear(Buffer* buffer, uint32_t offset, uint32_t size) {
Texture* lovrTextureCreate(TextureInfo* info) {
uint32_t limits[] = {
[TEXTURE_2D] = state.limits.textureSize2D,
[TEXTURE_3D] = state.limits.textureSize3D,
[TEXTURE_CUBE] = state.limits.textureSizeCube,
[TEXTURE_ARRAY] = state.limits.textureSize2D,
[TEXTURE_VOLUME] = state.limits.textureSize3D
[TEXTURE_ARRAY] = state.limits.textureSize2D
};
uint32_t limit = limits[info->type];
uint32_t mips = log2(MAX(MAX(info->width, info->height), (info->type == TEXTURE_VOLUME ? info->depth : 1))) + 1;
uint32_t mips = log2(MAX(MAX(info->width, info->height), (info->type == TEXTURE_3D ? info->depth : 1))) + 1;
uint8_t supports = state.features.formats[info->format];
lovrCheck(info->width > 0, "Texture width must be greater than zero");
@ -300,7 +300,7 @@ Texture* lovrTextureCreate(TextureInfo* info) {
lovrCheck(info->depth > 0, "Texture depth must be greater than zero");
lovrCheck(info->width <= limit, "Texture %s exceeds the limit for this texture type (%d)", "width", limit);
lovrCheck(info->height <= limit, "Texture %s exceeds the limit for this texture type (%d)", "height", limit);
lovrCheck(info->depth <= limit || info->type != TEXTURE_VOLUME, "Texture %s exceeds the limit for this texture type (%d)", "depth", limit);
lovrCheck(info->depth <= limit || info->type != TEXTURE_3D, "Texture %s exceeds the limit for this texture type (%d)", "depth", limit);
lovrCheck(info->depth <= state.limits.textureLayers || info->type != TEXTURE_ARRAY, "Texture %s exceeds the limit for this texture type (%d)", "depth", limit);
lovrCheck(info->depth == 1 || info->type != TEXTURE_2D, "2D textures must have a depth of 1");
lovrCheck(info->depth == 6 || info->type != TEXTURE_CUBE, "Cubemaps must have a depth of 6");
@ -308,7 +308,7 @@ Texture* lovrTextureCreate(TextureInfo* info) {
lovrCheck(measureTexture(info->format, info->width, info->height, info->depth) < 1 << 30, "Memory for a Texture can not exceed 1GB");
lovrCheck(info->samples == 1 || info->samples == 4, "Currently, Texture multisample count must be 1 or 4");
lovrCheck(info->samples == 1 || info->type != TEXTURE_CUBE, "Cubemaps can not be multisampled");
lovrCheck(info->samples == 1 || info->type != TEXTURE_VOLUME, "Volume textures can not be multisampled");
lovrCheck(info->samples == 1 || info->type != TEXTURE_3D, "Volume textures can not be multisampled");
lovrCheck(info->samples == 1 || ~info->usage & TEXTURE_STORAGE, "Currently, Textures with the 'storage' flag can not be multisampled");
lovrCheck(info->samples == 1 || info->mipmaps == 1, "Multisampled textures can only have 1 mipmap");
lovrCheck(~info->usage & TEXTURE_SAMPLE || (supports & GPU_FEATURE_SAMPLE), "GPU does not support the 'sample' flag for this format");
@ -344,7 +344,7 @@ Texture* lovrTextureCreate(TextureInfo* info) {
});
// Automatically create a renderable view for renderable non-volume textures
if (info->usage & TEXTURE_RENDER && info->type != TEXTURE_VOLUME && info->depth <= state.limits.renderSize[2]) {
if (info->usage & TEXTURE_RENDER && info->type != TEXTURE_3D && info->depth <= state.limits.renderSize[2]) {
if (info->mipmaps == 1) {
texture->renderView = texture->gpu;
} else {
@ -364,6 +364,48 @@ Texture* lovrTextureCreate(TextureInfo* info) {
return texture;
}
Texture* lovrTextureCreateView(TextureViewInfo* view) {
const TextureInfo* info = &view->parent->info;
uint32_t maxDepth = info->type == TEXTURE_3D ? MAX(info->depth >> view->levelIndex, 1) : info->depth;
lovrCheck(!info->parent, "Can't nest texture views");
lovrCheck(view->type != TEXTURE_3D, "Texture views may not be volume textures");
lovrCheck(view->layerCount > 0, "Texture view must have at least one layer");
lovrCheck(view->levelCount > 0, "Texture view must have at least one mipmap");
lovrCheck(view->layerIndex + view->layerCount <= maxDepth, "Texture view layer range exceeds depth of parent texture");
lovrCheck(view->levelIndex + view->levelCount <= info->mipmaps, "Texture view mipmap range exceeds mipmap count of parent texture");
lovrCheck(view->layerCount == 1 || view->type != TEXTURE_2D, "2D texture can only have a single layer");
lovrCheck(view->levelCount == 1 || info->type != TEXTURE_3D, "Views of volume textures may only have a single mipmap level");
lovrCheck(view->layerCount == 6 || view->type != TEXTURE_CUBE, "Cubemaps can only have a six layers");
Texture* texture = calloc(1, sizeof(Texture) + gpu_sizeof_texture());
lovrAssert(texture, "Out of memory");
texture->ref = 1;
texture->gpu = (gpu_texture*) (texture + 1);
texture->info = *info;
texture->info.parent = view->parent;
texture->info.mipmaps = view->levelCount;
texture->info.width = MAX(info->width >> view->levelIndex, 1);
texture->info.height = MAX(info->height >> view->levelIndex, 1);
texture->info.depth = view->layerCount;
gpu_texture_init_view(texture->gpu, &(gpu_texture_view_info) {
.source = view->parent->gpu,
.type = (gpu_texture_type) view->type,
.layerIndex = view->layerIndex,
.layerCount = view->layerCount,
.levelIndex = view->levelIndex,
.levelCount = view->levelCount
});
if (view->levelCount == 1 && view->type != TEXTURE_3D && view->layerCount <= 6) {
texture->renderView = texture->gpu;
}
lovrRetain(view->parent);
return texture;
}
void lovrTextureDestroy(void* ref) {
Texture* texture = ref;
lovrRelease(texture->info.parent, lovrTextureDestroy);
@ -372,6 +414,10 @@ void lovrTextureDestroy(void* ref) {
free(texture);
}
const TextureInfo* lovrTextureGetInfo(Texture* texture) {
return &texture->info;
}
// Pass
Pass* lovrGraphicsGetPass(PassInfo* info) {

View File

@ -149,7 +149,7 @@ void lovrBufferClear(Buffer* buffer, uint32_t offset, uint32_t size);
typedef enum {
TEXTURE_2D,
TEXTURE_VOLUME,
TEXTURE_3D,
TEXTURE_CUBE,
TEXTURE_ARRAY
} TextureType;