This commit is contained in:
bjorn 2022-05-01 15:47:17 -07:00
parent 203a60c63a
commit 22e15513f9
6 changed files with 265 additions and 0 deletions

View File

@ -423,6 +423,7 @@ if(LOVR_ENABLE_GRAPHICS)
src/api/l_graphics.c
src/api/l_graphics_buffer.c
src/api/l_graphics_texture.c
src/api/l_graphics_sampler.c
src/api/l_graphics_pass.c
)

View File

@ -15,6 +15,17 @@ StringEntry lovrBufferLayout[] = {
{ 0 }
};
StringEntry lovrCompareMode[] = {
[COMPARE_NONE] = ENTRY("none"),
[COMPARE_EQUAL] = ENTRY("equal"),
[COMPARE_NEQUAL] = ENTRY("notequal"),
[COMPARE_LESS] = ENTRY("less"),
[COMPARE_LEQUAL] = ENTRY("lequal"),
[COMPARE_GREATER] = ENTRY("greater"),
[COMPARE_GEQUAL] = ENTRY("gequal"),
{ 0 }
};
StringEntry lovrFieldType[] = {
[FIELD_I8x4] = ENTRY("i8x4"),
[FIELD_U8x4] = ENTRY("u8x4"),
@ -51,6 +62,12 @@ StringEntry lovrFieldType[] = {
{ 0 }
};
StringEntry lovrFilterMode[] = {
[FILTER_NEAREST] = ENTRY("nearest"),
[FILTER_LINEAR] = ENTRY("linear"),
{ 0 }
};
StringEntry lovrPassType[] = {
[PASS_RENDER] = ENTRY("render"),
[PASS_COMPUTE] = ENTRY("compute"),
@ -86,6 +103,12 @@ StringEntry lovrTextureUsage[] = {
{ 0 }
};
StringEntry lovrWrapMode[] = {
[WRAP_CLAMP] = ENTRY("clamp"),
[WRAP_REPEAT] = ENTRY("repeat"),
{ 0 }
};
static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[] = {
[FIELD_I8x4] = { 4, 1, 4, 4 },
[FIELD_U8x4] = { 4, 1, 4, 4 },
@ -705,6 +728,74 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
return 1;
}
static int l_lovrGraphicsNewSampler(lua_State* L) {
SamplerInfo info = {
.min = FILTER_LINEAR,
.mag = FILTER_LINEAR,
.mip = FILTER_LINEAR,
.wrap = { WRAP_REPEAT, WRAP_REPEAT, WRAP_REPEAT },
.range = { 0.f, -1.f }
};
luaL_checktype(L, 1, LUA_TTABLE);
lua_getfield(L, 1, "filter");
if (lua_isstring(L, -1)) {
info.min = info.mag = info.mip = luax_checkenum(L, -1, FilterMode, NULL);
} else if (lua_istable(L, -1)) {
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
info.min = luax_checkenum(L, -3, FilterMode, NULL);
info.mag = luax_checkenum(L, -2, FilterMode, NULL);
info.mip = luax_checkenum(L, -1, FilterMode, NULL);
lua_pop(L, 3);
} else if (!lua_isnil(L, -1)) {
lovrThrow("Expected string or table for Sampler filter");
}
lua_pop(L, 1);
lua_getfield(L, 1, "wrap");
if (lua_isstring(L, -1)) {
info.wrap[0] = info.wrap[1] = info.wrap[2] = luax_checkenum(L, -1, WrapMode, NULL);
} else if (lua_istable(L, -1)) {
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
info.wrap[0] = luax_checkenum(L, -3, WrapMode, NULL);
info.wrap[1] = luax_checkenum(L, -2, WrapMode, NULL);
info.wrap[2] = luax_checkenum(L, -1, WrapMode, NULL);
lua_pop(L, 3);
} else if (!lua_isnil(L, -1)) {
lovrThrow("Expected string or table for Sampler wrap");
}
lua_pop(L, 1);
lua_getfield(L, 1, "compare");
info.compare = luax_checkenum(L, -1, CompareMode, "none");
lua_pop(L, 1);
lua_getfield(L, 1, "anisotropy");
info.anisotropy = luax_optfloat(L, -1, 0.f);
lua_pop(L, 1);
lua_getfield(L, 1, "mipmaprange");
if (!lua_isnil(L, -1)) {
lovrAssert(lua_istable(L, -1), "Sampler mipmap range must be nil or a table");
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
info.range[0] = luax_checkfloat(L, -2);
info.range[1] = luax_checkfloat(L, -1);
lua_pop(L, 2);
}
lua_pop(L, 1);
Sampler* sampler = lovrSamplerCreate(&info);
luax_pushtype(L, Sampler, sampler);
lovrRelease(sampler, lovrSamplerDestroy);
return 1;
}
static const luaL_Reg lovrGraphics[] = {
{ "init", l_lovrGraphicsInit },
{ "submit", l_lovrGraphicsSubmit },
@ -716,6 +807,7 @@ static const luaL_Reg lovrGraphics[] = {
{ "buffer", l_lovrGraphicsBuffer },
{ "newBuffer", l_lovrGraphicsNewBuffer },
{ "newTexture", l_lovrGraphicsNewTexture },
{ "newSampler", l_lovrGraphicsNewSampler },
{ "pass", l_lovrGraphicsPass },
{ NULL, NULL }
};

View File

@ -4,10 +4,12 @@
typedef struct gpu_buffer gpu_buffer;
typedef struct gpu_texture gpu_texture;
typedef struct gpu_sampler gpu_sampler;
typedef struct gpu_stream gpu_stream;
size_t gpu_sizeof_buffer(void);
size_t gpu_sizeof_texture(void);
size_t gpu_sizeof_sampler(void);
// Buffer
@ -132,6 +134,35 @@ typedef enum {
GPU_FILTER_LINEAR
} gpu_filter;
typedef enum {
GPU_WRAP_CLAMP,
GPU_WRAP_REPEAT,
GPU_WRAP_MIRROR
} gpu_wrap;
typedef enum {
GPU_COMPARE_NONE,
GPU_COMPARE_EQUAL,
GPU_COMPARE_NEQUAL,
GPU_COMPARE_LESS,
GPU_COMPARE_LEQUAL,
GPU_COMPARE_GREATER,
GPU_COMPARE_GEQUAL
} gpu_compare_mode;
typedef struct {
gpu_filter min;
gpu_filter mag;
gpu_filter mip;
gpu_wrap wrap[3];
gpu_compare_mode compare;
float anisotropy;
float lodClamp[2];
} gpu_sampler_info;
bool gpu_sampler_init(gpu_sampler* sampler, gpu_sampler_info* info);
void gpu_sampler_destroy(gpu_sampler* sampler);
// Stream
gpu_stream* gpu_stream_begin(const char* label);

View File

@ -27,12 +27,17 @@ struct gpu_texture {
bool layered;
};
struct gpu_sampler {
VkSampler handle;
};
struct gpu_stream {
VkCommandBuffer commands;
};
size_t gpu_sizeof_buffer() { return sizeof(gpu_buffer); }
size_t gpu_sizeof_texture() { return sizeof(gpu_texture); }
size_t gpu_sizeof_sampler() { return sizeof(gpu_sampler); }
// Internals
@ -617,6 +622,62 @@ void gpu_texture_destroy(gpu_texture* texture) {
gpu_release(state.memory + texture->memory);
}
// Sampler
bool gpu_sampler_init(gpu_sampler* sampler, gpu_sampler_info* info) {
static const VkFilter filters[] = {
[GPU_FILTER_NEAREST] = VK_FILTER_NEAREST,
[GPU_FILTER_LINEAR] = VK_FILTER_LINEAR
};
static const VkSamplerMipmapMode mipFilters[] = {
[GPU_FILTER_NEAREST] = VK_SAMPLER_MIPMAP_MODE_NEAREST,
[GPU_FILTER_LINEAR] = VK_SAMPLER_MIPMAP_MODE_LINEAR
};
static const VkSamplerAddressMode wraps[] = {
[GPU_WRAP_CLAMP] = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
[GPU_WRAP_REPEAT] = VK_SAMPLER_ADDRESS_MODE_REPEAT,
[GPU_WRAP_MIRROR] = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT
};
static const VkCompareOp compareOps[] = {
[GPU_COMPARE_NONE] = VK_COMPARE_OP_ALWAYS,
[GPU_COMPARE_EQUAL] = VK_COMPARE_OP_EQUAL,
[GPU_COMPARE_NEQUAL] = VK_COMPARE_OP_NOT_EQUAL,
[GPU_COMPARE_LESS] = VK_COMPARE_OP_LESS,
[GPU_COMPARE_LEQUAL] = VK_COMPARE_OP_LESS_OR_EQUAL,
[GPU_COMPARE_GREATER] = VK_COMPARE_OP_GREATER,
[GPU_COMPARE_GEQUAL] = VK_COMPARE_OP_GREATER_OR_EQUAL
};
VkSamplerCreateInfo samplerInfo = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = filters[info->mag],
.minFilter = filters[info->min],
.mipmapMode = mipFilters[info->mip],
.addressModeU = wraps[info->wrap[0]],
.addressModeV = wraps[info->wrap[1]],
.addressModeW = wraps[info->wrap[2]],
.anisotropyEnable = info->anisotropy >= 1.f,
.maxAnisotropy = info->anisotropy,
.compareEnable = info->compare != GPU_COMPARE_NONE,
.compareOp = compareOps[info->compare],
.minLod = info->lodClamp[0],
.maxLod = info->lodClamp[1] < 0.f ? VK_LOD_CLAMP_NONE : info->lodClamp[1]
};
VK(vkCreateSampler(state.device, &samplerInfo, NULL, &sampler->handle), "Could not create sampler") {
return false;
}
return true;
}
void gpu_sampler_destroy(gpu_sampler* sampler) {
condemn(sampler->handle, VK_OBJECT_TYPE_SAMPLER);
}
// Stream
gpu_stream* gpu_stream_begin(const char* label) {

View File

@ -24,6 +24,12 @@ struct Texture {
TextureInfo info;
};
struct Sampler {
uint32_t ref;
gpu_sampler* gpu;
SamplerInfo info;
};
struct Pass {
uint32_t ref;
PassInfo info;
@ -460,6 +466,44 @@ const TextureInfo* lovrTextureGetInfo(Texture* texture) {
return &texture->info;
}
// Sampler
Sampler* lovrSamplerCreate(SamplerInfo* info) {
lovrCheck(info->range[1] < 0.f || info->range[1] >= info->range[0], "Invalid Sampler mipmap range");
lovrCheck(info->anisotropy <= state.limits.anisotropy, "Sampler anisotropy (%f) exceeds anisotropy limit (%f)", info->anisotropy, state.limits.anisotropy);
Sampler* sampler = calloc(1, sizeof(Sampler) + gpu_sizeof_sampler());
lovrAssert(sampler, "Out of memory");
sampler->gpu = (gpu_sampler*) (sampler + 1);
sampler->info = *info;
sampler->ref = 1;
gpu_sampler_info gpu = {
.min = (gpu_filter) info->min,
.mag = (gpu_filter) info->mag,
.mip = (gpu_filter) info->mip,
.wrap[0] = (gpu_wrap) info->wrap[0],
.wrap[1] = (gpu_wrap) info->wrap[1],
.wrap[2] = (gpu_wrap) info->wrap[2],
.compare = (gpu_compare_mode) info->compare,
.anisotropy = MIN(info->anisotropy, state.limits.anisotropy),
.lodClamp = { info->range[0], info->range[1] }
};
lovrAssert(gpu_sampler_init(sampler->gpu, &gpu), "Failed to initialize sampler");
return sampler;
}
void lovrSamplerDestroy(void* ref) {
Sampler* sampler = ref;
gpu_sampler_destroy(sampler->gpu);
free(sampler);
}
const SamplerInfo* lovrSamplerGetInfo(Sampler* sampler) {
return &sampler->info;
}
// Pass
Pass* lovrGraphicsGetPass(PassInfo* info) {

View File

@ -7,6 +7,7 @@ struct Image;
typedef struct Buffer Buffer;
typedef struct Texture Texture;
typedef struct Sampler Sampler;
typedef struct Pass Pass;
typedef struct {
@ -192,6 +193,41 @@ Texture* lovrTextureCreateView(TextureViewInfo* view);
void lovrTextureDestroy(void* ref);
const TextureInfo* lovrTextureGetInfo(Texture* texture);
// Sampler
typedef enum {
FILTER_NEAREST,
FILTER_LINEAR
} FilterMode;
typedef enum {
WRAP_CLAMP,
WRAP_REPEAT,
WRAP_MIRROR
} WrapMode;
typedef enum {
COMPARE_NONE,
COMPARE_EQUAL,
COMPARE_NEQUAL,
COMPARE_LESS,
COMPARE_LEQUAL,
COMPARE_GREATER,
COMPARE_GEQUAL
} CompareMode;
typedef struct {
FilterMode min, mag, mip;
WrapMode wrap[3];
CompareMode compare;
float anisotropy;
float range[2];
} SamplerInfo;
Sampler* lovrSamplerCreate(SamplerInfo* info);
void lovrSamplerDestroy(void* ref);
const SamplerInfo* lovrSamplerGetInfo(Sampler* sampler);
// Pass
typedef enum {