Vulkan lod mipmaps
This commit is contained in:
parent
a408a475f5
commit
9465083742
|
@ -18,8 +18,8 @@ inline glm::vec4 fromHex(const std::string& str) {
|
|||
}
|
||||
inline std::string toHexa(const glm::vec4& rgb) {
|
||||
std::ostringstream sstr;
|
||||
sstr << std::hex << std::setw(2) << std::setfill('0') <<
|
||||
static_cast<int>(rgb.x * UCHAR_MAX) << static_cast<int>(rgb.y * UCHAR_MAX) << static_cast<int>(rgb.z * UCHAR_MAX) << std::endl;
|
||||
sstr << '#' << std::hex << std::setw(2) << std::setfill('0') <<
|
||||
static_cast<int>(rgb.x * UCHAR_MAX) << static_cast<int>(rgb.y * UCHAR_MAX) << static_cast<int>(rgb.z * UCHAR_MAX);
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,12 +40,12 @@ std::optional<Image::properties> Image::Read(const std::string& imagepath, std::
|
|||
info.size.height = *(unsigned int*)&(header[8 ]);
|
||||
info.size.width = *(unsigned int*)&(header[12]);
|
||||
unsigned int linearSize = *(unsigned int*)&(header[16]);
|
||||
info.mipMap = *(unsigned int*)&(header[24]);
|
||||
info.mipmapLevels = *(unsigned int*)&(header[24]);
|
||||
unsigned int fourCC = *(unsigned int*)&(header[80]);
|
||||
|
||||
|
||||
/* how big is it going to be including all mipmaps? */
|
||||
unsigned int bufsize = info.mipMap > 1 ? linearSize * 2 : linearSize;
|
||||
unsigned int bufsize = info.mipmapLevels > 1 ? linearSize * 2 : linearSize;
|
||||
data.resize(bufsize);
|
||||
fread(data.data(), 1, bufsize, fp);
|
||||
/* close the file pointer */
|
||||
|
@ -53,9 +53,6 @@ std::optional<Image::properties> Image::Read(const std::string& imagepath, std::
|
|||
|
||||
switch(fourCC)
|
||||
{
|
||||
case FOURCC_DXT1:
|
||||
info.format = Format::BC1;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
info.format = Format::BC2;
|
||||
break;
|
||||
|
|
|
@ -17,15 +17,14 @@ public:
|
|||
};
|
||||
// NOTE: matches VkFormat
|
||||
enum class Format {
|
||||
/// DXT1 RGBA SRGB
|
||||
BC1 = 134,
|
||||
/// DXT3 RGBA SRGB
|
||||
BC2 = 136,
|
||||
/// DXT1 RGBA SRGB
|
||||
/// DXT5 RGBA SRGB
|
||||
BC3 = 138,
|
||||
// MAYBE: R8G8B8A8
|
||||
// MAYBE: For HDR BC6H_SFLOAT = 144,
|
||||
};
|
||||
|
||||
// NOTE: matches VkImageLayout
|
||||
enum class Layout {
|
||||
UNDEFINED = 0,
|
||||
|
@ -68,15 +67,20 @@ public:
|
|||
|
||||
struct properties {
|
||||
frame size;
|
||||
uint32_t mipMap;
|
||||
uint32_t mipmapLevels;
|
||||
Format format;
|
||||
};
|
||||
struct requirement {
|
||||
properties props;
|
||||
struct requirement: properties {
|
||||
requirement(const properties& props, Layout layout, Usage usage, Aspect aspect,
|
||||
bool optimal = true): properties(props), layout(layout), usage(usage),
|
||||
aspect(aspect), optimal(optimal) { }
|
||||
Layout layout;
|
||||
Usage usage;
|
||||
bool linear = false;
|
||||
Aspect aspect = Aspect::COLOR;
|
||||
Aspect aspect;
|
||||
bool optimal;
|
||||
|
||||
static requirement Texture(const properties &props) {
|
||||
return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR); }
|
||||
};
|
||||
|
||||
static std::optional<properties> Read(const std::string&, std::vector<unsigned char>& data);
|
||||
|
@ -97,7 +101,7 @@ public:
|
|||
bool minLinear = true;
|
||||
Wrap wrap = Wrap::MIRRORED_REPEAT;
|
||||
int anisotropy = 0;
|
||||
//TODO: mipmap
|
||||
bool mipmap = true;
|
||||
};
|
||||
|
||||
/// Only supports dds files
|
||||
|
|
|
@ -14,7 +14,8 @@ const auto NO_DELETER = memory::Deleter(nullptr);
|
|||
memory::ptr memory::GetNull() { return memory::ptr(nullptr, NO_DELETER); }
|
||||
|
||||
Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device),
|
||||
capabilities({info.features.samplerAnisotropy == VK_TRUE}), device(device)
|
||||
capabilities({info.features.samplerAnisotropy == VK_TRUE ? std::make_optional(info.properties.limits.maxSamplerAnisotropy) : std::nullopt,
|
||||
info.properties.limits.maxSamplerLodBias}), device(device)
|
||||
{
|
||||
if(info.hasMemoryBudget()) {
|
||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
|
||||
|
@ -194,7 +195,7 @@ void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) {
|
|||
|
||||
submitCmd(transferBuffer, transferQueue);
|
||||
}
|
||||
void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) {
|
||||
beginCmd(graphicsBuffer);
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
|
@ -207,7 +208,7 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay
|
|||
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.levelCount = mipLevels;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
|
@ -250,28 +251,33 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay
|
|||
|
||||
submitCmd(graphicsBuffer, graphicsQueue);
|
||||
}
|
||||
void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height) {
|
||||
void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height, uint32_t mipLevels) {
|
||||
|
||||
beginCmd(transferBuffer);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
VkDeviceSize offset = 0;
|
||||
std::vector<VkBufferImageCopy> regions{mipLevels};
|
||||
for (size_t i = 0; i < mipLevels; i++) {
|
||||
regions[i].bufferOffset = offset;
|
||||
regions[i].bufferRowLength = std::max<uint32_t>(1, width >> i);
|
||||
regions[i].bufferImageHeight = std::max<uint32_t>(1, height >> i);
|
||||
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
regions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
regions[i].imageSubresource.mipLevel = i;
|
||||
regions[i].imageSubresource.baseArrayLayer = 0;
|
||||
regions[i].imageSubresource.layerCount = 1;
|
||||
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {width, height, 1};
|
||||
regions[i].imageOffset = {0, 0, 0};
|
||||
regions[i].imageExtent = {regions[i].bufferRowLength, regions[i].bufferImageHeight, 1};
|
||||
|
||||
vkCmdCopyBufferToImage(transferBuffer, src, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
//NOTE: may fail without width % 4 && height % 4
|
||||
offset += regions[i].imageExtent.height * regions[i].imageExtent.width * regions[i].imageExtent.depth;
|
||||
}
|
||||
vkCmdCopyBufferToImage(transferBuffer, src, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels, regions.data());
|
||||
|
||||
submitCmd(transferBuffer, transferQueue);
|
||||
}
|
||||
|
||||
|
||||
std::optional<uint32_t> Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) {
|
||||
updateProperties();
|
||||
#if LOG_TRACE
|
||||
|
|
|
@ -37,13 +37,14 @@ public:
|
|||
bool deallocate(const memory::area&);
|
||||
|
||||
void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height);
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels);
|
||||
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1);
|
||||
|
||||
void setTracyZone(const char* name);
|
||||
|
||||
struct Capabilities {
|
||||
bool anisotropy;
|
||||
std::optional<float> maxAnisotropy;
|
||||
float maxLodBias;
|
||||
};
|
||||
|
||||
constexpr VkDevice getDevice() const { return device; }
|
||||
|
|
|
@ -46,8 +46,8 @@ CommandCenter::~CommandCenter() {
|
|||
void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeline& pipe, VkExtent2D extent, const renderOptions& opt) {
|
||||
assert(freed);
|
||||
|
||||
depthbuffer = Image::Create({{{extent.height, extent.width}, 1, (Image::Format)depthFormat},
|
||||
Image::Layout::DEPTH_STENCIL_ATTACHMENT, Image::Usage::DEPTH_STENCIL_ATTACHMENT, false, Image::Aspect::DEPTH});
|
||||
depthbuffer = Image::Create(Image::requirement({{extent.height, extent.width}, 1, (Image::Format)depthFormat},
|
||||
Image::Layout::DEPTH_STENCIL_ATTACHMENT, Image::Usage::DEPTH_STENCIL_ATTACHMENT, Image::Aspect::DEPTH));
|
||||
|
||||
framebuffers.resize(views.size());
|
||||
|
||||
|
|
|
@ -263,6 +263,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
volkLoadInstance(instance);
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
const auto version = volkGetInstanceVersion();
|
||||
LOG_D("Vulkan " << VK_VERSION_MAJOR(version) << '.' << VK_VERSION_MINOR(version) << '.' << VK_VERSION_PATCH(version) << ", GLSL precompiled");
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
|
|||
VkImageCreateInfo info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
info.imageType = VK_IMAGE_TYPE_2D;
|
||||
info.extent.width = req.props.size.width;
|
||||
info.extent.height = req.props.size.height;
|
||||
info.extent.width = req.size.width;
|
||||
info.extent.height = req.size.height;
|
||||
info.extent.depth = 1;
|
||||
info.mipLevels = req.props.mipMap; //TODO:
|
||||
info.mipLevels = req.mipmapLevels;
|
||||
info.arrayLayers = 1;
|
||||
info.format = static_cast<VkFormat>(req.props.format);
|
||||
info.tiling = req.linear ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
|
||||
info.format = static_cast<VkFormat>(req.format);
|
||||
info.tiling = req.optimal ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR;
|
||||
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
info.usage = static_cast<VkImageUsageFlags>(req.usage);
|
||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
@ -54,25 +54,24 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
|
|||
if (data) {
|
||||
if(auto staging = WritableBuffer::Create(data.size)) {
|
||||
staging->write(data, 0);
|
||||
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height);
|
||||
alloc->transitionImageLayout(out.ref, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<VkImageLayout>(req.layout));
|
||||
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, req.mipmapLevels);
|
||||
info.initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels);
|
||||
} else {
|
||||
LOG_E("Cannot allocate staging memory");
|
||||
return memory::GetNull();
|
||||
}
|
||||
} else {
|
||||
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, static_cast<VkImageLayout>(req.layout));
|
||||
}
|
||||
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, static_cast<VkImageLayout>(req.layout), req.mipmapLevels);
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = out.ref;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = static_cast<VkFormat>(req.props.format);
|
||||
viewInfo.format = static_cast<VkFormat>(req.format);
|
||||
viewInfo.subresourceRange.aspectMask = static_cast<VkImageAspectFlags>(req.aspect);
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1; //TODO: mipmap
|
||||
viewInfo.subresourceRange.levelCount = req.mipmapLevels;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
|
@ -105,7 +104,7 @@ std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sa
|
|||
}();
|
||||
|
||||
vk::Image::info img;
|
||||
auto mem = createImage({header.size, header.mipMap, header.format, Layout::SHADER_READ_ONLY, Usage::SAMPLED, false},
|
||||
auto mem = createImage(requirement::Texture(header),
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data, img);
|
||||
if(!mem) {
|
||||
FATAL("Cannot create texture image");
|
||||
|
@ -121,9 +120,10 @@ std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sa
|
|||
samplerInfo.addressModeV = wrap;
|
||||
samplerInfo.addressModeW = wrap;
|
||||
|
||||
if (Allocator::GetDefault()->getCapabilities().anisotropy && props.anisotropy > 0) {
|
||||
auto maxAnisotropy = Allocator::GetDefault()->getCapabilities().maxAnisotropy;
|
||||
if (maxAnisotropy && props.anisotropy > 0) {
|
||||
samplerInfo.anisotropyEnable = VK_TRUE;
|
||||
samplerInfo.maxAnisotropy = 1 << (props.anisotropy-1);
|
||||
samplerInfo.maxAnisotropy = std::min<float>(maxAnisotropy.value(), 1 << (props.anisotropy-1));
|
||||
} else {
|
||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.f;
|
||||
|
@ -135,10 +135,10 @@ std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sa
|
|||
samplerInfo.compareEnable = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerInfo.mipmapMode = props.minLinear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.mipLodBias = 0.0f; //TODO:
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = 0.0f;
|
||||
samplerInfo.maxLod = props.mipmap ? header.mipmapLevels : 0.0f;
|
||||
|
||||
VkSampler sampler;
|
||||
if (vkCreateSampler(device, &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) {
|
||||
|
|
Loading…
Reference in New Issue