1
0
Fork 0
Univerxel/src/client/render/vk/api/Images.cpp

139 lines
5.3 KiB
C++

#include "Images.hpp"
#include "Buffers.hpp"
#include "../Allocator.hpp"
#include "../../../../core/utils/logger.hpp"
using namespace render::vk;
Image::~Image() {
vkDestroyImage(Allocator::GetDefault()->getDevice(), ref, ALLOC);
}
Texture::~Texture() {
vkDestroySampler(Allocator::GetDefault()->getDevice(), sampler, ALLOC);
vkDestroyImageView(Allocator::GetDefault()->getDevice(), view, ALLOC);
}
memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags properties, const render::data_view view, Image::info& out) {
auto alloc = Allocator::GetDefault();
auto device = alloc->getDevice();
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.depth = 1;
info.mipLevels = req.props.mipMap; //TODO:
info.arrayLayers = 1;
info.format = static_cast<VkFormat>(req.props.format);
info.tiling = req.linear ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
info.initialLayout = static_cast<VkImageLayout>(req.layout);
info.usage = static_cast<VkImageUsageFlags>(req.usage);
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.flags = 0;
if (view) {
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
if (vkCreateImage(device, &info, ALLOC, &out.ref) != VK_SUCCESS) {
LOG_E("Failed to create image");
return memory::GetNull();
}
out.offset = 0;
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, out.ref, &memRequirements);
auto memory = alloc->allocate(memRequirements, properties, true);
if (!memory || vkBindImageMemory(device, out.ref, memory->ref, memory->offset) != VK_SUCCESS) {
LOG_E("Failed to allocate image memory");
return memory::GetNull();
}
if (view) {
if(auto staging = WritableBuffer::Create(view.size)) {
staging->write(view, 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));
} else {
FATAL("Cannot allocate staging memory");
return memory::GetNull();
}
}
return memory;
}
//TODO: createImages
std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sampling& props) {
auto device = Allocator::GetDefault()->getDevice();
std::vector<unsigned char> data;
auto header = [&] {
if (auto header = render::Image::Read(path, data)) {
return header.value();
}
FATAL("Cannot read texture");
}();
vk::Image::info img;
auto mem = createImage({header.size, header.mipMap, header.format, Layout::SHADER_READ_ONLY, Usage::SAMPLED, false},
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data, img);
if(!mem) {
FATAL("Cannot create texture image");
}
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = img.ref;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = static_cast<VkFormat>(header.format);
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
VkImageView view;
if (vkCreateImageView(device, &viewInfo, ALLOC, &view) != VK_SUCCESS) {
FATAL("Failed to create texture image view!");
}
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = props.magLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
samplerInfo.minFilter = props.minLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
const auto wrap = static_cast<VkSamplerAddressMode>(props.wrap);
samplerInfo.addressModeU = wrap;
samplerInfo.addressModeV = wrap;
samplerInfo.addressModeW = wrap;
if (Allocator::GetDefault()->getCapabilities().anisotropy && props.anisotropy > 0) {
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 1 << (props.anisotropy-1);
} else {
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.f;
}
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f; //TODO:
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
VkSampler sampler;
if (vkCreateSampler(device, &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) {
FATAL("Failed to create texture sampler!");
}
return std::unique_ptr<Texture>(new Texture(sampler, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem)));
}