From 15d62ecf6bf4ebe6104d44876246f62228345041 Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Fri, 31 Mar 2023 09:08:49 +0100 Subject: [PATCH] add support for different texture samplers --- include/application.hpp | 2 +- include/gfx.hpp | 40 +++++++++++++++++++++----- include/gfx_device.hpp | 2 +- include/resources/texture.hpp | 6 +++- src/application.cpp | 13 ++++----- src/gfx_device_vulkan.cpp | 29 +++++++++++++------ src/resources/texture.cpp | 53 ++++++++++++++--------------------- src/util/model_loader.cpp | 4 +-- test/src/game.cpp | 16 +++-------- 9 files changed, 92 insertions(+), 73 deletions(-) diff --git a/include/application.hpp b/include/application.hpp index a21823a..c3c313f 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -47,7 +47,7 @@ namespace engine { /* this descriptor set is bound per-material */ const gfx::DescriptorSetLayout* materialSetLayout; - const gfx::Sampler* materialSetSampler; + std::unordered_map samplers{}; }; class Application { diff --git a/include/gfx.hpp b/include/gfx.hpp index bbad17c..210c66b 100644 --- a/include/gfx.hpp +++ b/include/gfx.hpp @@ -3,6 +3,7 @@ #include #include #include +#include // Enums and structs for the graphics abstraction @@ -70,17 +71,11 @@ namespace engine::gfx { FLOAT4 }; - enum class TextureFilter { + enum class Filter : int { LINEAR, NEAREST, }; - enum class MipmapSetting { - OFF, - NEAREST, - LINEAR, - }; - enum class DescriptorType { UNIFORM_BUFFER, COMBINED_IMAGE_SAMPLER, @@ -123,4 +118,35 @@ namespace engine::gfx { ShaderStageFlags::Flags stageFlags = 0; }; + struct SamplerInfo { + Filter minify; + Filter magnify; + Filter mipmap; + bool anisotropicFiltering; + + bool operator==(const SamplerInfo&) const = default; + }; + } + +namespace std { + template<> + struct std::hash + { + std::size_t operator()(const engine::gfx::SamplerInfo& k) const + { + using std::hash; + + size_t h1 = hash()(static_cast(k.minify)); + size_t h2 = hash()(static_cast(k.magnify)); + size_t h3 = hash()(static_cast(k.mipmap)); + size_t h4 = hash()(k.anisotropicFiltering); + + return ((h1 & 0xFF) << 24) | + ((h2 & 0xFF) << 16) | + ((h3 & 0xFF) << 8) | + ((h4 & 0xFF) << 0); + } + }; + +} \ No newline at end of file diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index c473ba7..4029835 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -52,7 +52,7 @@ namespace engine { gfx::Image* createImage(uint32_t w, uint32_t h, const void* imageData); void destroyImage(const gfx::Image* image); - gfx::Sampler* createSampler(); + const gfx::Sampler* createSampler(const gfx::SamplerInfo& info); void destroySampler(const gfx::Sampler* sampler); uint64_t getFrameCount(); diff --git a/include/resources/texture.hpp b/include/resources/texture.hpp index 9f6068d..acfd735 100644 --- a/include/resources/texture.hpp +++ b/include/resources/texture.hpp @@ -4,6 +4,10 @@ #include +namespace engine { + struct RenderData; +} + namespace engine::resources { class Texture { @@ -16,7 +20,7 @@ public: ANISOTROPIC, }; - Texture(GFXDevice* gfxDevice, const gfx::DescriptorSetLayout* materialSetLayout, const gfx::Sampler* sampler, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter); + Texture(RenderData& renderData, const std::string& path, Filtering filtering); ~Texture(); Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; diff --git a/src/application.cpp b/src/application.cpp index cd23814..c54fbbb 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -111,7 +111,6 @@ namespace engine { binding0.stageFlags = gfx::ShaderStageFlags::FRAGMENT; } renderData.materialSetLayout = gfx()->createDescriptorSetLayout(materialSetBindings); - renderData.materialSetSampler = gfx()->createSampler(); // default resources { @@ -144,13 +143,9 @@ namespace engine { } { auto whiteTexture = std::make_unique( - gfx(), - renderData.materialSetLayout, - renderData.materialSetSampler, + renderData, getResourcePath("engine/textures/white.png"), - resources::Texture::Filtering::OFF, - false, - false + resources::Texture::Filtering::OFF ); getResourceManager()->addPersistent("builtin.white", std::move(whiteTexture)); } @@ -158,7 +153,9 @@ namespace engine { Application::~Application() { - gfx()->destroySampler(renderData.materialSetSampler); + for (const auto& [info, sampler] : renderData.samplers) { + gfx()->destroySampler(sampler); + } gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout); gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer); diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 656a52d..a4e7e3b 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -154,15 +154,26 @@ namespace engine { } } - [[maybe_unused]] static VkFilter getTextureFilter(gfx::TextureFilter filter) + [[maybe_unused]] static VkFilter getFilter(gfx::Filter filter) { switch (filter) { - case gfx::TextureFilter::LINEAR: + case gfx::Filter::LINEAR: return VK_FILTER_LINEAR; - case gfx::TextureFilter::NEAREST: + case gfx::Filter::NEAREST: return VK_FILTER_NEAREST; } - throw std::runtime_error("Unknown texture filter"); + throw std::runtime_error("Unknown filter"); + } + + [[maybe_unused]] static VkSamplerMipmapMode getSamplerMipmapMode(gfx::Filter filter) + { + switch (filter) { + case gfx::Filter::LINEAR: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + case gfx::Filter::NEAREST: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + throw std::runtime_error("Unknown filter"); } [[maybe_unused]] static VkSampleCountFlags getSampleCountFlags(gfx::MSAALevel level) @@ -1537,20 +1548,20 @@ namespace engine { delete image; } - gfx::Sampler *GFXDevice::createSampler() + const gfx::Sampler *GFXDevice::createSampler(const gfx::SamplerInfo& info) { gfx::Sampler* out = new gfx::Sampler{}; VkSamplerCreateInfo samplerInfo{}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.magFilter = converters::getFilter(info.magnify); + samplerInfo.minFilter = converters::getFilter(info.minify); + samplerInfo.mipmapMode = converters::getSamplerMipmapMode(info.mipmap); samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.mipLodBias = 0.0f; - samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.anisotropyEnable = info.anisotropicFiltering ? VK_TRUE : VK_FALSE; samplerInfo.maxAnisotropy = pimpl->device.properties.limits.maxSamplerAnisotropy; samplerInfo.minLod = 0.0f; samplerInfo.maxLod = VK_LOD_CLAMP_NONE; diff --git a/src/resources/texture.cpp b/src/resources/texture.cpp index 68b6800..bf7e35d 100644 --- a/src/resources/texture.cpp +++ b/src/resources/texture.cpp @@ -1,5 +1,6 @@ #include "resources/texture.hpp" +#include "application.hpp" #include "util/files.hpp" #include "log.hpp" @@ -7,58 +8,46 @@ namespace engine::resources { -Texture::Texture(GFXDevice* gfxDevice, const gfx::DescriptorSetLayout* materialSetLayout, const gfx::Sampler* sampler, const std::string& path, Filtering filtering, bool useMipmaps, bool useLinearMagFilter) - : m_gfxDevice(gfxDevice) +Texture::Texture(RenderData& renderData, const std::string& path, Filtering filtering) + : m_gfxDevice(renderData.gfxdev.get()) { int width, height; std::unique_ptr> texbuf = util::readImageFile(path, &width, &height); - gfx::TextureFilter minFilter = gfx::TextureFilter::NEAREST; - gfx::TextureFilter magFilter = gfx::TextureFilter::NEAREST; - gfx::MipmapSetting mipmapSetting = gfx::MipmapSetting::OFF; - bool anisotropyEnable = false; + gfx::SamplerInfo samplerInfo{}; - if (useLinearMagFilter) { - magFilter = gfx::TextureFilter::LINEAR; - } else { - magFilter = gfx::TextureFilter::NEAREST; - } + samplerInfo.magnify = gfx::Filter::LINEAR; switch (filtering) { case Filtering::OFF: - minFilter = gfx::TextureFilter::NEAREST; - mipmapSetting = gfx::MipmapSetting::NEAREST; - anisotropyEnable = false; + samplerInfo.minify = gfx::Filter::NEAREST; + samplerInfo.mipmap = gfx::Filter::NEAREST; + samplerInfo.anisotropicFiltering = false; break; case Filtering::BILINEAR: - minFilter = gfx::TextureFilter::LINEAR; - mipmapSetting = gfx::MipmapSetting::NEAREST; - anisotropyEnable = false; + samplerInfo.minify = gfx::Filter::LINEAR; + samplerInfo.mipmap = gfx::Filter::NEAREST; + samplerInfo.anisotropicFiltering = false; break; case Filtering::TRILINEAR: - minFilter = gfx::TextureFilter::LINEAR; - mipmapSetting = gfx::MipmapSetting::LINEAR; - anisotropyEnable = false; + samplerInfo.minify = gfx::Filter::LINEAR; + samplerInfo.mipmap = gfx::Filter::LINEAR; + samplerInfo.anisotropicFiltering = false; break; case Filtering::ANISOTROPIC: - minFilter = gfx::TextureFilter::LINEAR; - mipmapSetting = gfx::MipmapSetting::LINEAR; - anisotropyEnable = true; + samplerInfo.minify = gfx::Filter::LINEAR; + samplerInfo.mipmap = gfx::Filter::LINEAR; + samplerInfo.anisotropicFiltering = true; } - if (useMipmaps == false) { - mipmapSetting = gfx::MipmapSetting::OFF; + if (renderData.samplers.contains(samplerInfo) == false) { + renderData.samplers.insert(std::make_pair(samplerInfo, m_gfxDevice->createSampler(samplerInfo))); } - - (void)minFilter; - (void)magFilter; - (void)mipmapSetting; - (void)anisotropyEnable; m_image = m_gfxDevice->createImage(width, height, texbuf->data()); - m_descriptorSet = m_gfxDevice->allocateDescriptorSet(materialSetLayout); - m_gfxDevice->updateDescriptorCombinedImageSampler(m_descriptorSet, 0, m_image, sampler); + m_descriptorSet = m_gfxDevice->allocateDescriptorSet(renderData.materialSetLayout); + m_gfxDevice->updateDescriptorCombinedImageSampler(m_descriptorSet, 0, m_image, renderData.samplers.at(samplerInfo)); LOG_INFO("Loaded texture: {}, width: {} height: {}", path, width, height); diff --git a/src/util/model_loader.cpp b/src/util/model_loader.cpp index 2a2d2b8..5be2a38 100644 --- a/src/util/model_loader.cpp +++ b/src/util/model_loader.cpp @@ -182,8 +182,8 @@ namespace engine::util { absPath /= texPath.C_Str(); try { textures[i] = std::make_shared( - parent->app()->gfx(), parent->app()->renderData.materialSetLayout, parent->app()->renderData.materialSetSampler, absPath.string(), - resources::Texture::Filtering::TRILINEAR, true, true); + parent->app()->renderData, absPath.string(), + resources::Texture::Filtering::TRILINEAR); } catch (const std::runtime_error&) { textures[i] = parent->app()->getResource("builtin.white"); } diff --git a/test/src/game.cpp b/test/src/game.cpp index 25cdd7a..f1a14ea 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -84,22 +84,14 @@ void playGame(GameSettings settings) /* shared resources */ auto grassTexture = std::make_shared( - app.gfx(), - app.renderData.materialSetLayout, - app.renderData.materialSetSampler, + app.renderData, app.getResourcePath("textures/grass.jpg"), - engine::resources::Texture::Filtering::ANISOTROPIC, - true, - true + engine::resources::Texture::Filtering::ANISOTROPIC ); auto spaceTexture = std::make_shared( - app.gfx(), - app.renderData.materialSetLayout, - app.renderData.materialSetSampler, + app.renderData, app.getResourcePath("textures/space2.png"), - engine::resources::Texture::Filtering::ANISOTROPIC, - true, - true + engine::resources::Texture::Filtering::ANISOTROPIC ); /* cube */