Pass:setSampler;

This is an experimental take on the "default filter" system.  Each
render Pass has its own "global sampler", initialized to trilinear.  The
global sampler will be used by default to sample textures/materials in
shaders.  You can set it to a filter mode or a full Sampler object.  You
can always send your own Sampler objects to Shaders if you want
per-texture sampler settings.  The global sampler is designed to be set a
small number of times per pass instead of on every draw.  Basically,
just do Pass:setSampler('nearest') and draw your minecraft world.
This commit is contained in:
bjorn 2022-06-07 20:42:10 -07:00
parent a26e732ab0
commit ef19a334a9
3 changed files with 56 additions and 10 deletions

View File

@ -238,6 +238,19 @@ static int l_lovrPassSetDepthClamp(lua_State* L) {
return 0;
}
static int l_lovrPassSetSampler(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
if (lua_type(L, 2) != LUA_TUSERDATA) {
FilterMode filter = luax_checkenum(L, 2, FilterMode, "linear");
Sampler* sampler = lovrGraphicsGetDefaultSampler(filter);
lovrPassSetSampler(pass, sampler);
} else {
Sampler* sampler = luax_checktype(L, 2, Sampler);
lovrPassSetSampler(pass, sampler);
}
return 0;
}
static int l_lovrPassSetScissor(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
uint32_t scissor[4];
@ -668,6 +681,7 @@ const luaL_Reg lovrPass[] = {
{ "setDepthWrite", l_lovrPassSetDepthWrite },
{ "setDepthOffset", l_lovrPassSetDepthOffset },
{ "setDepthClamp", l_lovrPassSetDepthClamp },
{ "setSampler", l_lovrPassSetSampler },
{ "setScissor", l_lovrPassSetScissor },
{ "setShader", l_lovrPassSetShader },
{ "setStencilTest", l_lovrPassSetStencilTest },

View File

@ -107,6 +107,7 @@ typedef struct {
typedef struct {
float color[4];
Shader* shader;
Sampler* sampler;
uint64_t formatHash;
gpu_pipeline_info info;
float viewport[4];
@ -139,6 +140,7 @@ struct Pass {
Pipeline* pipeline;
Pipeline pipelines[4];
uint32_t pipelineIndex;
bool samplerDirty;
char constants[256];
bool constantsDirty;
gpu_binding bindings[32];
@ -237,7 +239,7 @@ static struct {
Attachment attachments[16];
Buffer* defaultBuffer;
Texture* defaultTexture;
Sampler* defaultSampler;
Sampler* defaultSamplers[2];
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
VertexFormat vertexFormats[DEFAULT_FORMAT_COUNT];
map_t pipelineLookup;
@ -349,12 +351,14 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
lovrRelease(image, lovrImageDestroy);
state.defaultSampler = lovrSamplerCreate(&(SamplerInfo) {
.min = FILTER_LINEAR,
.mag = FILTER_LINEAR,
.mip = FILTER_LINEAR,
.wrap = { WRAP_REPEAT, WRAP_REPEAT, WRAP_REPEAT }
});
for (uint32_t i = 0; i < 2; i++) {
state.defaultSamplers[i] = lovrSamplerCreate(&(SamplerInfo) {
.min = i == 0 ? FILTER_NEAREST : FILTER_LINEAR,
.mag = i == 0 ? FILTER_NEAREST : FILTER_LINEAR,
.mip = i == 0 ? FILTER_NEAREST : FILTER_LINEAR,
.wrap = { WRAP_REPEAT, WRAP_REPEAT, WRAP_REPEAT }
});
}
gpu_stream* transfers = getTransfers();
gpu_clear_buffer(transfers, state.defaultBuffer->gpu, 0, 4096);
@ -399,7 +403,8 @@ void lovrGraphicsDestroy() {
}
lovrRelease(state.defaultBuffer, lovrBufferDestroy);
lovrRelease(state.defaultTexture, lovrTextureDestroy);
lovrRelease(state.defaultSampler, lovrSamplerDestroy);
lovrRelease(state.defaultSamplers[0], lovrSamplerDestroy);
lovrRelease(state.defaultSamplers[1], lovrSamplerDestroy);
for (uint32_t i = 0; i < COUNTOF(state.defaultShaders); i++) {
lovrRelease(state.defaultShaders[i], lovrShaderDestroy);
}
@ -901,6 +906,10 @@ const TextureInfo* lovrTextureGetInfo(Texture* texture) {
// Sampler
Sampler* lovrGraphicsGetDefaultSampler(FilterMode mode) {
return state.defaultSamplers[mode];
}
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);
@ -1458,6 +1467,7 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
pass->pipeline->formatHash = 0;
pass->pipeline->shader = NULL;
pass->pipeline->dirty = true;
pass->samplerDirty = true;
memset(pass->constants, 0, sizeof(pass->constants));
pass->constantsDirty = true;
@ -1480,7 +1490,9 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
pass->builtins[0] = (gpu_binding) { 0, GPU_SLOT_UNIFORM_BUFFER, .buffer = cameras };
pass->builtins[1] = (gpu_binding) { 1, GPU_SLOT_UNIFORM_BUFFER, .buffer = draws };
pass->builtins[2] = (gpu_binding) { 2, GPU_SLOT_SAMPLER, .sampler = state.defaultSampler->gpu };
pass->builtins[2] = (gpu_binding) { 2, GPU_SLOT_SAMPLER, .sampler = NULL };
pass->pipeline->sampler = state.defaultSamplers[FILTER_LINEAR];
pass->samplerDirty = true;
pass->vertexBuffer = NULL;
pass->indexBuffer = NULL;
@ -1536,6 +1548,7 @@ void lovrPassPush(Pass* pass, StackType stack) {
lovrCheck(pass->pipelineIndex < COUNTOF(pass->pipelines), "%s stack overflow (more pushes than pops?)", "Pipeline");
memcpy(pass->pipeline, &pass->pipelines[pass->pipelineIndex - 1], sizeof(Pipeline));
lovrRetain(pass->pipeline->shader);
lovrRetain(pass->pipeline->sampler);
break;
default: break;
}
@ -1553,6 +1566,8 @@ void lovrPassPop(Pass* pass, StackType stack) {
lovrCheck(pass->pipelineIndex < COUNTOF(pass->pipelines), "%s stack underflow (more pops than pushes?)", "Pipeline");
gpu_set_viewport(pass->stream, pass->pipeline->viewport, pass->pipeline->depthRange);
gpu_set_scissor(pass->stream, pass->pipeline->scissor);
pass->pipeline->dirty = true;
pass->samplerDirty = true;
break;
default: break;
}
@ -1701,6 +1716,15 @@ void lovrPassSetDepthClamp(Pass* pass, bool clamp) {
}
}
void lovrPassSetSampler(Pass* pass, Sampler* sampler) {
if (sampler != pass->pipeline->sampler) {
lovrRetain(sampler);
lovrRelease(pass->pipeline->sampler, lovrSamplerDestroy);
pass->pipeline->sampler = sampler;
pass->samplerDirty = true;
}
}
void lovrPassSetScissor(Pass* pass, uint32_t scissor[4]) {
gpu_set_scissor(pass->stream, scissor);
memcpy(pass->pipeline->scissor, scissor, 4 * sizeof(uint32_t));
@ -1747,7 +1771,7 @@ void lovrPassSetShader(Pass* pass, Shader* shader) {
} else if (shader->textureMask & bit) {
pass->bindings[i].texture = state.defaultTexture->gpu;
} else if (shader->samplerMask & bit) {
pass->bindings[i].sampler = state.defaultSampler->gpu;
pass->bindings[i].sampler = state.defaultSamplers[FILTER_LINEAR]->gpu;
}
pass->bindingMask |= bit;
@ -2044,6 +2068,12 @@ static void flushBuiltins(Pass* pass, Draw* draw, Shader* shader) {
rebind = true;
}
if (pass->samplerDirty) {
pass->builtins[2].sampler = pass->pipeline->sampler->gpu;
pass->samplerDirty = false;
rebind = true;
}
if (rebind) {
gpu_bundle_info bundleInfo = {
.layout = state.layouts.data[state.builtinLayout].gpu,

View File

@ -236,6 +236,7 @@ typedef struct {
float range[2];
} SamplerInfo;
Sampler* lovrGraphicsGetDefaultSampler(FilterMode mode);
Sampler* lovrSamplerCreate(SamplerInfo* info);
void lovrSamplerDestroy(void* ref);
const SamplerInfo* lovrSamplerGetInfo(Sampler* sampler);
@ -380,6 +381,7 @@ void lovrPassSetDepthTest(Pass* pass, CompareMode test);
void lovrPassSetDepthWrite(Pass* pass, bool write);
void lovrPassSetDepthOffset(Pass* pass, float offset, float sloped);
void lovrPassSetDepthClamp(Pass* pass, bool clamp);
void lovrPassSetSampler(Pass* pass, Sampler* sampler);
void lovrPassSetScissor(Pass* pass, uint32_t scissor[4]);
void lovrPassSetShader(Pass* pass, Shader* shader);
void lovrPassSetStencilTest(Pass* pass, CompareMode test, uint8_t value, uint8_t mask);