mirror of https://github.com/bjornbytes/lovr.git
Sampler;
This commit is contained in:
parent
203a60c63a
commit
22e15513f9
|
@ -423,6 +423,7 @@ if(LOVR_ENABLE_GRAPHICS)
|
||||||
src/api/l_graphics.c
|
src/api/l_graphics.c
|
||||||
src/api/l_graphics_buffer.c
|
src/api/l_graphics_buffer.c
|
||||||
src/api/l_graphics_texture.c
|
src/api/l_graphics_texture.c
|
||||||
|
src/api/l_graphics_sampler.c
|
||||||
src/api/l_graphics_pass.c
|
src/api/l_graphics_pass.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,17 @@ StringEntry lovrBufferLayout[] = {
|
||||||
{ 0 }
|
{ 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[] = {
|
StringEntry lovrFieldType[] = {
|
||||||
[FIELD_I8x4] = ENTRY("i8x4"),
|
[FIELD_I8x4] = ENTRY("i8x4"),
|
||||||
[FIELD_U8x4] = ENTRY("u8x4"),
|
[FIELD_U8x4] = ENTRY("u8x4"),
|
||||||
|
@ -51,6 +62,12 @@ StringEntry lovrFieldType[] = {
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StringEntry lovrFilterMode[] = {
|
||||||
|
[FILTER_NEAREST] = ENTRY("nearest"),
|
||||||
|
[FILTER_LINEAR] = ENTRY("linear"),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
StringEntry lovrPassType[] = {
|
StringEntry lovrPassType[] = {
|
||||||
[PASS_RENDER] = ENTRY("render"),
|
[PASS_RENDER] = ENTRY("render"),
|
||||||
[PASS_COMPUTE] = ENTRY("compute"),
|
[PASS_COMPUTE] = ENTRY("compute"),
|
||||||
|
@ -86,6 +103,12 @@ StringEntry lovrTextureUsage[] = {
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StringEntry lovrWrapMode[] = {
|
||||||
|
[WRAP_CLAMP] = ENTRY("clamp"),
|
||||||
|
[WRAP_REPEAT] = ENTRY("repeat"),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[] = {
|
static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[] = {
|
||||||
[FIELD_I8x4] = { 4, 1, 4, 4 },
|
[FIELD_I8x4] = { 4, 1, 4, 4 },
|
||||||
[FIELD_U8x4] = { 4, 1, 4, 4 },
|
[FIELD_U8x4] = { 4, 1, 4, 4 },
|
||||||
|
@ -705,6 +728,74 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
|
||||||
return 1;
|
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[] = {
|
static const luaL_Reg lovrGraphics[] = {
|
||||||
{ "init", l_lovrGraphicsInit },
|
{ "init", l_lovrGraphicsInit },
|
||||||
{ "submit", l_lovrGraphicsSubmit },
|
{ "submit", l_lovrGraphicsSubmit },
|
||||||
|
@ -716,6 +807,7 @@ static const luaL_Reg lovrGraphics[] = {
|
||||||
{ "buffer", l_lovrGraphicsBuffer },
|
{ "buffer", l_lovrGraphicsBuffer },
|
||||||
{ "newBuffer", l_lovrGraphicsNewBuffer },
|
{ "newBuffer", l_lovrGraphicsNewBuffer },
|
||||||
{ "newTexture", l_lovrGraphicsNewTexture },
|
{ "newTexture", l_lovrGraphicsNewTexture },
|
||||||
|
{ "newSampler", l_lovrGraphicsNewSampler },
|
||||||
{ "pass", l_lovrGraphicsPass },
|
{ "pass", l_lovrGraphicsPass },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
typedef struct gpu_buffer gpu_buffer;
|
typedef struct gpu_buffer gpu_buffer;
|
||||||
typedef struct gpu_texture gpu_texture;
|
typedef struct gpu_texture gpu_texture;
|
||||||
|
typedef struct gpu_sampler gpu_sampler;
|
||||||
typedef struct gpu_stream gpu_stream;
|
typedef struct gpu_stream gpu_stream;
|
||||||
|
|
||||||
size_t gpu_sizeof_buffer(void);
|
size_t gpu_sizeof_buffer(void);
|
||||||
size_t gpu_sizeof_texture(void);
|
size_t gpu_sizeof_texture(void);
|
||||||
|
size_t gpu_sizeof_sampler(void);
|
||||||
|
|
||||||
// Buffer
|
// Buffer
|
||||||
|
|
||||||
|
@ -132,6 +134,35 @@ typedef enum {
|
||||||
GPU_FILTER_LINEAR
|
GPU_FILTER_LINEAR
|
||||||
} gpu_filter;
|
} 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
|
// Stream
|
||||||
|
|
||||||
gpu_stream* gpu_stream_begin(const char* label);
|
gpu_stream* gpu_stream_begin(const char* label);
|
||||||
|
|
|
@ -27,12 +27,17 @@ struct gpu_texture {
|
||||||
bool layered;
|
bool layered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct gpu_sampler {
|
||||||
|
VkSampler handle;
|
||||||
|
};
|
||||||
|
|
||||||
struct gpu_stream {
|
struct gpu_stream {
|
||||||
VkCommandBuffer commands;
|
VkCommandBuffer commands;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t gpu_sizeof_buffer() { return sizeof(gpu_buffer); }
|
size_t gpu_sizeof_buffer() { return sizeof(gpu_buffer); }
|
||||||
size_t gpu_sizeof_texture() { return sizeof(gpu_texture); }
|
size_t gpu_sizeof_texture() { return sizeof(gpu_texture); }
|
||||||
|
size_t gpu_sizeof_sampler() { return sizeof(gpu_sampler); }
|
||||||
|
|
||||||
// Internals
|
// Internals
|
||||||
|
|
||||||
|
@ -617,6 +622,62 @@ void gpu_texture_destroy(gpu_texture* texture) {
|
||||||
gpu_release(state.memory + texture->memory);
|
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
|
// Stream
|
||||||
|
|
||||||
gpu_stream* gpu_stream_begin(const char* label) {
|
gpu_stream* gpu_stream_begin(const char* label) {
|
||||||
|
|
|
@ -24,6 +24,12 @@ struct Texture {
|
||||||
TextureInfo info;
|
TextureInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Sampler {
|
||||||
|
uint32_t ref;
|
||||||
|
gpu_sampler* gpu;
|
||||||
|
SamplerInfo info;
|
||||||
|
};
|
||||||
|
|
||||||
struct Pass {
|
struct Pass {
|
||||||
uint32_t ref;
|
uint32_t ref;
|
||||||
PassInfo info;
|
PassInfo info;
|
||||||
|
@ -460,6 +466,44 @@ const TextureInfo* lovrTextureGetInfo(Texture* texture) {
|
||||||
return &texture->info;
|
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
|
||||||
|
|
||||||
Pass* lovrGraphicsGetPass(PassInfo* info) {
|
Pass* lovrGraphicsGetPass(PassInfo* info) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct Image;
|
||||||
|
|
||||||
typedef struct Buffer Buffer;
|
typedef struct Buffer Buffer;
|
||||||
typedef struct Texture Texture;
|
typedef struct Texture Texture;
|
||||||
|
typedef struct Sampler Sampler;
|
||||||
typedef struct Pass Pass;
|
typedef struct Pass Pass;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -192,6 +193,41 @@ Texture* lovrTextureCreateView(TextureViewInfo* view);
|
||||||
void lovrTextureDestroy(void* ref);
|
void lovrTextureDestroy(void* ref);
|
||||||
const TextureInfo* lovrTextureGetInfo(Texture* texture);
|
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
|
// Pass
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
Loading…
Reference in New Issue