diff --git a/src/api/l_graphics_pass.c b/src/api/l_graphics_pass.c index 311e46bd..c79871af 100644 --- a/src/api/l_graphics_pass.c +++ b/src/api/l_graphics_pass.c @@ -234,6 +234,35 @@ static int l_lovrPassSend(lua_State* L) { return luax_typeerror(L, 3, "Buffer, Texture, Sampler, or number/vector"); } +static int l_lovrPassClear(lua_State* L) { + Pass* pass = luax_checktype(L, 1, Pass); + + Buffer* buffer = luax_totype(L, 2, Buffer); + + if (buffer) { + uint32_t offset = luax_optu32(L, 3, 0); + uint32_t extent = luax_optu32(L, 4, ~0u); + lovrPassClearBuffer(pass, buffer, offset, extent); + return 0; + } + + Texture* texture = luax_totype(L, 2, Texture); + + if (texture) { + float value[4]; + luax_readcolor(L, 3, value); + int index = lua_istable(L, 3) ? 4 : 6; + uint32_t layer = luax_optu32(L, index++, 1) - 1; + uint32_t layerCount = luax_optu32(L, index++, ~0u); + uint32_t level = luax_optu32(L, index++, 1) - 1; + uint32_t levelCount = luax_optu32(L, index++, ~0u); + lovrPassClearTexture(pass, texture, value, layer, layerCount, level, levelCount); + return 0; + } + + return luax_typeerror(L, 2, "Buffer or Texture"); +} + const luaL_Reg lovrPass[] = { { "getType", l_lovrPassGetType }, { "push", l_lovrPassPush }, @@ -258,5 +287,6 @@ const luaL_Reg lovrPass[] = { { "setWinding", l_lovrPassSetWinding }, { "setWireframe", l_lovrPassSetWireframe }, { "send", l_lovrPassSend }, + { "clear", l_lovrPassClear }, { NULL, NULL } }; diff --git a/src/core/gpu.h b/src/core/gpu.h index c575ef56..f5aaf0d5 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -492,7 +492,7 @@ void gpu_copy_textures(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, u void gpu_copy_buffer_texture(gpu_stream* stream, gpu_buffer* src, gpu_texture* dst, uint32_t srcOffset, uint16_t dstOffset[4], uint16_t extent[3]); void gpu_copy_texture_buffer(gpu_stream* stream, gpu_texture* src, gpu_buffer* dst, uint16_t srcOffset[4], uint32_t dstOffset, uint16_t extent[3]); void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, uint32_t size); -void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, uint16_t layer, uint16_t layerCount, uint16_t level, uint16_t levelCount, float value[4]); +void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, float value[4], uint32_t layer, uint32_t layerCount, uint32_t level, uint32_t levelCount); void gpu_blit(gpu_stream* stream, gpu_texture* src, gpu_texture* dst, uint16_t srcOffset[4], uint16_t dstOffset[4], uint16_t srcExtent[3], uint16_t dstExtent[3], gpu_filter filter); // Entry diff --git a/src/core/gpu_vk.c b/src/core/gpu_vk.c index bc6b6b84..4e1619d0 100644 --- a/src/core/gpu_vk.c +++ b/src/core/gpu_vk.c @@ -1491,7 +1491,7 @@ void gpu_clear_buffer(gpu_stream* stream, gpu_buffer* buffer, uint32_t offset, u vkCmdFillBuffer(stream->commands, buffer->handle, buffer->offset + offset, size, 0); } -void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, uint16_t layer, uint16_t layerCount, uint16_t level, uint16_t levelCount, float value[4]) { +void gpu_clear_texture(gpu_stream* stream, gpu_texture* texture, float value[4], uint32_t layer, uint32_t layerCount, uint32_t level, uint32_t levelCount) { VkImageSubresourceRange range = { .aspectMask = texture->aspect, .baseMipLevel = level, diff --git a/src/modules/graphics/graphics.c b/src/modules/graphics/graphics.c index b2c33d0c..eafa569a 100644 --- a/src/modules/graphics/graphics.c +++ b/src/modules/graphics/graphics.c @@ -241,7 +241,7 @@ bool lovrGraphicsInit(bool debug, bool vsync) { gpu_stream* transfers = getTransfers(); float white[4] = { 1.f, 1.f, 1.f, 1.f }; - gpu_clear_texture(transfers, state.defaultTexture->gpu, 0, 1, 0, 1, white); + gpu_clear_texture(transfers, state.defaultTexture->gpu, white, 0, ~0u, 0, ~0u); if (!zeros) { gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer()); @@ -1521,6 +1521,25 @@ void lovrPassSendSampler(Pass* pass, const char* name, size_t length, uint32_t s pass->bindingsDirty = true; } +void lovrPassClearBuffer(Pass* pass, Buffer* buffer, uint32_t offset, uint32_t extent) { + if (extent == 0) return; + if (extent == ~0u) extent = buffer->size - offset; + lovrCheck(pass->info.type == PASS_TRANSFER, "This function can only be called on a transfer pass"); + lovrCheck(!lovrBufferIsTemporary(buffer), "Temporary buffers can not be cleared"); + lovrCheck(offset % 4 == 0, "Buffer clear offset must be a multiple of 4"); + lovrCheck(extent % 4 == 0, "Buffer clear extent must be a multiple of 4"); + lovrCheck(offset + extent <= buffer->size, "Buffer clear range goes past the end of the Buffer"); + gpu_clear_buffer(pass->stream, buffer->gpu, offset, extent); +} + +void lovrPassClearTexture(Pass* pass, Texture* texture, float value[4], uint32_t layer, uint32_t layerCount, uint32_t level, uint32_t levelCount) { + lovrCheck(pass->info.type == PASS_TRANSFER, "This function can only be called on a transfer pass"); + lovrCheck(!texture->info.parent, "Texture views can not be cleared"); + lovrCheck(texture->info.type == TEXTURE_3D || layer + layerCount <= texture->info.depth, "Texture clear range exceeds texture layer count"); + lovrCheck(level + levelCount <= texture->info.mipmaps, "Texture clear range exceeds texture mipmap count"); + gpu_clear_texture(pass->stream, texture->gpu, value, layer, layerCount, level, levelCount); +} + // Helpers static void* tempAlloc(size_t size) { diff --git a/src/modules/graphics/graphics.h b/src/modules/graphics/graphics.h index a715df1f..24ed4fde 100644 --- a/src/modules/graphics/graphics.h +++ b/src/modules/graphics/graphics.h @@ -372,3 +372,5 @@ void lovrPassSetWireframe(Pass* pass, bool wireframe); void lovrPassSendBuffer(Pass* pass, const char* name, size_t length, uint32_t slot, Buffer* buffer, uint32_t offset, uint32_t extent); void lovrPassSendTexture(Pass* pass, const char* name, size_t length, uint32_t slot, Texture* texture); void lovrPassSendSampler(Pass* pass, const char* name, size_t length, uint32_t slot, Sampler* sampler); +void lovrPassClearBuffer(Pass* pass, Buffer* buffer, uint32_t offset, uint32_t extent); +void lovrPassClearTexture(Pass* pass, Texture* texture, float value[4], uint32_t layer, uint32_t layerCount, uint32_t level, uint32_t levelCount);