From ef19a334a9880509629062cc538c1dad4af65df9 Mon Sep 17 00:00:00 2001 From: bjorn Date: Tue, 7 Jun 2022 20:42:10 -0700 Subject: [PATCH] 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. --- src/api/l_graphics_pass.c | 14 +++++++++ src/modules/graphics/graphics.c | 50 ++++++++++++++++++++++++++------- src/modules/graphics/graphics.h | 2 ++ 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/api/l_graphics_pass.c b/src/api/l_graphics_pass.c index 83656deb..565522f4 100644 --- a/src/api/l_graphics_pass.c +++ b/src/api/l_graphics_pass.c @@ -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 }, diff --git a/src/modules/graphics/graphics.c b/src/modules/graphics/graphics.c index c7543d38..57bc53b0 100644 --- a/src/modules/graphics/graphics.c +++ b/src/modules/graphics/graphics.c @@ -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, diff --git a/src/modules/graphics/graphics.h b/src/modules/graphics/graphics.h index 702c2152..5628a8f9 100644 --- a/src/modules/graphics/graphics.h +++ b/src/modules/graphics/graphics.h @@ -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);