add support for different texture samplers

This commit is contained in:
Bailey Harrison 2023-03-31 09:08:49 +01:00
parent 424d22cf69
commit 15d62ecf6b
9 changed files with 92 additions and 73 deletions

View File

@ -47,7 +47,7 @@ namespace engine {
/* this descriptor set is bound per-material */ /* this descriptor set is bound per-material */
const gfx::DescriptorSetLayout* materialSetLayout; const gfx::DescriptorSetLayout* materialSetLayout;
const gfx::Sampler* materialSetSampler; std::unordered_map<gfx::SamplerInfo, const gfx::Sampler*> samplers{};
}; };
class Application { class Application {

View File

@ -3,6 +3,7 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <type_traits> #include <type_traits>
#include <functional>
// Enums and structs for the graphics abstraction // Enums and structs for the graphics abstraction
@ -70,17 +71,11 @@ namespace engine::gfx {
FLOAT4 FLOAT4
}; };
enum class TextureFilter { enum class Filter : int {
LINEAR, LINEAR,
NEAREST, NEAREST,
}; };
enum class MipmapSetting {
OFF,
NEAREST,
LINEAR,
};
enum class DescriptorType { enum class DescriptorType {
UNIFORM_BUFFER, UNIFORM_BUFFER,
COMBINED_IMAGE_SAMPLER, COMBINED_IMAGE_SAMPLER,
@ -123,4 +118,35 @@ namespace engine::gfx {
ShaderStageFlags::Flags stageFlags = 0; 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<engine::gfx::SamplerInfo>
{
std::size_t operator()(const engine::gfx::SamplerInfo& k) const
{
using std::hash;
size_t h1 = hash<int>()(static_cast<int>(k.minify));
size_t h2 = hash<int>()(static_cast<int>(k.magnify));
size_t h3 = hash<int>()(static_cast<int>(k.mipmap));
size_t h4 = hash<bool>()(k.anisotropicFiltering);
return ((h1 & 0xFF) << 24) |
((h2 & 0xFF) << 16) |
((h3 & 0xFF) << 8) |
((h4 & 0xFF) << 0);
}
};
}

View File

@ -52,7 +52,7 @@ namespace engine {
gfx::Image* createImage(uint32_t w, uint32_t h, const void* imageData); gfx::Image* createImage(uint32_t w, uint32_t h, const void* imageData);
void destroyImage(const gfx::Image* image); void destroyImage(const gfx::Image* image);
gfx::Sampler* createSampler(); const gfx::Sampler* createSampler(const gfx::SamplerInfo& info);
void destroySampler(const gfx::Sampler* sampler); void destroySampler(const gfx::Sampler* sampler);
uint64_t getFrameCount(); uint64_t getFrameCount();

View File

@ -4,6 +4,10 @@
#include <string> #include <string>
namespace engine {
struct RenderData;
}
namespace engine::resources { namespace engine::resources {
class Texture { class Texture {
@ -16,7 +20,7 @@ public:
ANISOTROPIC, 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();
Texture(const Texture&) = delete; Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete; Texture& operator=(const Texture&) = delete;

View File

@ -111,7 +111,6 @@ namespace engine {
binding0.stageFlags = gfx::ShaderStageFlags::FRAGMENT; binding0.stageFlags = gfx::ShaderStageFlags::FRAGMENT;
} }
renderData.materialSetLayout = gfx()->createDescriptorSetLayout(materialSetBindings); renderData.materialSetLayout = gfx()->createDescriptorSetLayout(materialSetBindings);
renderData.materialSetSampler = gfx()->createSampler();
// default resources // default resources
{ {
@ -144,13 +143,9 @@ namespace engine {
} }
{ {
auto whiteTexture = std::make_unique<resources::Texture>( auto whiteTexture = std::make_unique<resources::Texture>(
gfx(), renderData,
renderData.materialSetLayout,
renderData.materialSetSampler,
getResourcePath("engine/textures/white.png"), getResourcePath("engine/textures/white.png"),
resources::Texture::Filtering::OFF, resources::Texture::Filtering::OFF
false,
false
); );
getResourceManager<resources::Texture>()->addPersistent("builtin.white", std::move(whiteTexture)); getResourceManager<resources::Texture>()->addPersistent("builtin.white", std::move(whiteTexture));
} }
@ -158,7 +153,9 @@ namespace engine {
Application::~Application() Application::~Application()
{ {
gfx()->destroySampler(renderData.materialSetSampler); for (const auto& [info, sampler] : renderData.samplers) {
gfx()->destroySampler(sampler);
}
gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout); gfx()->destroyDescriptorSetLayout(renderData.materialSetLayout);
gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer); gfx()->destroyUniformBuffer(renderData.frameSetUniformBuffer);

View File

@ -154,15 +154,26 @@ namespace engine {
} }
} }
[[maybe_unused]] static VkFilter getTextureFilter(gfx::TextureFilter filter) [[maybe_unused]] static VkFilter getFilter(gfx::Filter filter)
{ {
switch (filter) { switch (filter) {
case gfx::TextureFilter::LINEAR: case gfx::Filter::LINEAR:
return VK_FILTER_LINEAR; return VK_FILTER_LINEAR;
case gfx::TextureFilter::NEAREST: case gfx::Filter::NEAREST:
return VK_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) [[maybe_unused]] static VkSampleCountFlags getSampleCountFlags(gfx::MSAALevel level)
@ -1537,20 +1548,20 @@ namespace engine {
delete image; delete image;
} }
gfx::Sampler *GFXDevice::createSampler() const gfx::Sampler *GFXDevice::createSampler(const gfx::SamplerInfo& info)
{ {
gfx::Sampler* out = new gfx::Sampler{}; gfx::Sampler* out = new gfx::Sampler{};
VkSamplerCreateInfo samplerInfo{}; VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR; samplerInfo.magFilter = converters::getFilter(info.magnify);
samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.minFilter = converters::getFilter(info.minify);
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; samplerInfo.mipmapMode = converters::getSamplerMipmapMode(info.mipmap);
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.mipLodBias = 0.0f; samplerInfo.mipLodBias = 0.0f;
samplerInfo.anisotropyEnable = VK_TRUE; samplerInfo.anisotropyEnable = info.anisotropicFiltering ? VK_TRUE : VK_FALSE;
samplerInfo.maxAnisotropy = pimpl->device.properties.limits.maxSamplerAnisotropy; samplerInfo.maxAnisotropy = pimpl->device.properties.limits.maxSamplerAnisotropy;
samplerInfo.minLod = 0.0f; samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = VK_LOD_CLAMP_NONE; samplerInfo.maxLod = VK_LOD_CLAMP_NONE;

View File

@ -1,5 +1,6 @@
#include "resources/texture.hpp" #include "resources/texture.hpp"
#include "application.hpp"
#include "util/files.hpp" #include "util/files.hpp"
#include "log.hpp" #include "log.hpp"
@ -7,58 +8,46 @@
namespace engine::resources { 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) Texture::Texture(RenderData& renderData, const std::string& path, Filtering filtering)
: m_gfxDevice(gfxDevice) : m_gfxDevice(renderData.gfxdev.get())
{ {
int width, height; int width, height;
std::unique_ptr<std::vector<uint8_t>> texbuf = util::readImageFile(path, &width, &height); std::unique_ptr<std::vector<uint8_t>> texbuf = util::readImageFile(path, &width, &height);
gfx::TextureFilter minFilter = gfx::TextureFilter::NEAREST; gfx::SamplerInfo samplerInfo{};
gfx::TextureFilter magFilter = gfx::TextureFilter::NEAREST;
gfx::MipmapSetting mipmapSetting = gfx::MipmapSetting::OFF;
bool anisotropyEnable = false;
if (useLinearMagFilter) { samplerInfo.magnify = gfx::Filter::LINEAR;
magFilter = gfx::TextureFilter::LINEAR;
} else {
magFilter = gfx::TextureFilter::NEAREST;
}
switch (filtering) { switch (filtering) {
case Filtering::OFF: case Filtering::OFF:
minFilter = gfx::TextureFilter::NEAREST; samplerInfo.minify = gfx::Filter::NEAREST;
mipmapSetting = gfx::MipmapSetting::NEAREST; samplerInfo.mipmap = gfx::Filter::NEAREST;
anisotropyEnable = false; samplerInfo.anisotropicFiltering = false;
break; break;
case Filtering::BILINEAR: case Filtering::BILINEAR:
minFilter = gfx::TextureFilter::LINEAR; samplerInfo.minify = gfx::Filter::LINEAR;
mipmapSetting = gfx::MipmapSetting::NEAREST; samplerInfo.mipmap = gfx::Filter::NEAREST;
anisotropyEnable = false; samplerInfo.anisotropicFiltering = false;
break; break;
case Filtering::TRILINEAR: case Filtering::TRILINEAR:
minFilter = gfx::TextureFilter::LINEAR; samplerInfo.minify = gfx::Filter::LINEAR;
mipmapSetting = gfx::MipmapSetting::LINEAR; samplerInfo.mipmap = gfx::Filter::LINEAR;
anisotropyEnable = false; samplerInfo.anisotropicFiltering = false;
break; break;
case Filtering::ANISOTROPIC: case Filtering::ANISOTROPIC:
minFilter = gfx::TextureFilter::LINEAR; samplerInfo.minify = gfx::Filter::LINEAR;
mipmapSetting = gfx::MipmapSetting::LINEAR; samplerInfo.mipmap = gfx::Filter::LINEAR;
anisotropyEnable = true; samplerInfo.anisotropicFiltering = true;
} }
if (useMipmaps == false) { if (renderData.samplers.contains(samplerInfo) == false) {
mipmapSetting = gfx::MipmapSetting::OFF; 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_image = m_gfxDevice->createImage(width, height, texbuf->data());
m_descriptorSet = m_gfxDevice->allocateDescriptorSet(materialSetLayout); m_descriptorSet = m_gfxDevice->allocateDescriptorSet(renderData.materialSetLayout);
m_gfxDevice->updateDescriptorCombinedImageSampler(m_descriptorSet, 0, m_image, sampler); m_gfxDevice->updateDescriptorCombinedImageSampler(m_descriptorSet, 0, m_image, renderData.samplers.at(samplerInfo));
LOG_INFO("Loaded texture: {}, width: {} height: {}", path, width, height); LOG_INFO("Loaded texture: {}, width: {} height: {}", path, width, height);

View File

@ -182,8 +182,8 @@ namespace engine::util {
absPath /= texPath.C_Str(); absPath /= texPath.C_Str();
try { try {
textures[i] = std::make_shared<resources::Texture>( textures[i] = std::make_shared<resources::Texture>(
parent->app()->gfx(), parent->app()->renderData.materialSetLayout, parent->app()->renderData.materialSetSampler, absPath.string(), parent->app()->renderData, absPath.string(),
resources::Texture::Filtering::TRILINEAR, true, true); resources::Texture::Filtering::TRILINEAR);
} catch (const std::runtime_error&) { } catch (const std::runtime_error&) {
textures[i] = parent->app()->getResource<resources::Texture>("builtin.white"); textures[i] = parent->app()->getResource<resources::Texture>("builtin.white");
} }

View File

@ -84,22 +84,14 @@ void playGame(GameSettings settings)
/* shared resources */ /* shared resources */
auto grassTexture = std::make_shared<engine::resources::Texture>( auto grassTexture = std::make_shared<engine::resources::Texture>(
app.gfx(), app.renderData,
app.renderData.materialSetLayout,
app.renderData.materialSetSampler,
app.getResourcePath("textures/grass.jpg"), app.getResourcePath("textures/grass.jpg"),
engine::resources::Texture::Filtering::ANISOTROPIC, engine::resources::Texture::Filtering::ANISOTROPIC
true,
true
); );
auto spaceTexture = std::make_shared<engine::resources::Texture>( auto spaceTexture = std::make_shared<engine::resources::Texture>(
app.gfx(), app.renderData,
app.renderData.materialSetLayout,
app.renderData.materialSetSampler,
app.getResourcePath("textures/space2.png"), app.getResourcePath("textures/space2.png"),
engine::resources::Texture::Filtering::ANISOTROPIC, engine::resources::Texture::Filtering::ANISOTROPIC
true,
true
); );
/* cube */ /* cube */