Vulkan first texture
parent
3ea83d40ac
commit
a3d9a157f3
BIN
resource/content/shaders/Tris.fs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Tris.fs.spv (Stored with Git LFS)
Binary file not shown.
BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)
Binary file not shown.
|
@ -1,10 +1,13 @@
|
|||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(binding = 1) uniform sampler2D texSampler;
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
outColor = texture(texSampler, fragTexCoord);
|
||||
}
|
||||
|
|
|
@ -9,10 +9,13 @@ layout(binding = 0) uniform UniformBufferObject {
|
|||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 2) in vec2 inTexCoord;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
fragTexCoord = inTexCoord;
|
||||
}
|
|
@ -72,7 +72,7 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
|
|||
ImGui::SameLine();
|
||||
changeRenderer |= ImGui::Checkbox("Stochastic", &options.renderer.voxel.stochastic);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Hide textures tilling\nMay cause visible inconsistances on chunk borders");
|
||||
ImGui::SetTooltip("Hide textures tiling\nMay cause visible inconsistances on chunk borders");
|
||||
|
||||
changeRenderer |= ImGui::Checkbox("Geometry", &options.renderer.voxel.geometry);
|
||||
ImGui::SameLine();
|
||||
|
|
|
@ -22,9 +22,9 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD
|
|||
}
|
||||
|
||||
updateProperties();
|
||||
{
|
||||
{ // Transfer
|
||||
if (!info.queueIndices.transferFamily.has_value()) {
|
||||
LOG_W("No transfer queue family. Using graphics one");
|
||||
LOG_W("No transfer queue family. Fallback to graphics one");
|
||||
}
|
||||
const auto family = info.queueIndices.transferFamily.value_or(info.queueIndices.graphicsFamily.value());
|
||||
|
||||
|
@ -37,8 +37,7 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD
|
|||
if (vkCreateCommandPool(device, &poolInfo, ALLOC, &transferPool) != VK_SUCCESS) {
|
||||
FATAL("Failed to create transfer pool!");
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
|
@ -48,12 +47,33 @@ Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalD
|
|||
vkAllocateCommandBuffers(device, &allocInfo, &transferBuffer);
|
||||
tracyCtx = TracyVkContext(info.device, device, transferQueue, transferBuffer);
|
||||
}
|
||||
{ // Graphics
|
||||
vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue);
|
||||
VkCommandPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value();
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) {
|
||||
FATAL("Failed to create graphics pool!");
|
||||
}
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandPool = graphicsPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
vkAllocateCommandBuffers(device, &allocInfo, &graphicsBuffer);
|
||||
}
|
||||
}
|
||||
Allocator::~Allocator() {
|
||||
TracyVkDestroy(tracyCtx);
|
||||
vkFreeCommandBuffers(device, transferPool, 1, &transferBuffer);
|
||||
vkFreeCommandBuffers(device, graphicsPool, 1, &graphicsBuffer);
|
||||
|
||||
vkDestroyCommandPool(device, transferPool, ALLOC);
|
||||
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
||||
//NOTE: all allocations are delete by ~vector
|
||||
}
|
||||
|
||||
|
@ -189,6 +209,39 @@ Allocator::memory_ptr Allocator::createBuffers(const std::vector<buffer_requirem
|
|||
|
||||
return memory;
|
||||
}
|
||||
Allocator::memory_ptr Allocator::createImage(const VkImageCreateInfo& info, VkMemoryPropertyFlags properties, image_info& out,
|
||||
const void *data, VkDeviceSize data_size, VkDeviceSize data_offset, VkImageLayout finalLayout) {
|
||||
|
||||
if (vkCreateImage(device, &info, ALLOC, &out.image) != VK_SUCCESS) {
|
||||
LOG_E("Failed to create image");
|
||||
return GetNull();
|
||||
}
|
||||
out.offset = 0;
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(device, out.image, &memRequirements);
|
||||
|
||||
auto memory = allocate(memRequirements, properties, true);
|
||||
if (!memory || vkBindImageMemory(device, out.image, memory->ref, memory->offset) != VK_SUCCESS) {
|
||||
LOG_E("Failed to allocate image memory");
|
||||
return GetNull();
|
||||
}
|
||||
|
||||
if (data_size != 0 && data != nullptr) {
|
||||
Allocator::buffer_info stagingBuffer;
|
||||
if(auto stagingMemory = createBuffer({data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) {
|
||||
stagingMemory->write(data, data_size, data_offset);
|
||||
transitionImageLayout(out.image, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
copyBufferToImage(stagingBuffer, out, info.extent.width, info.extent.height);
|
||||
transitionImageLayout(out.image, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, finalLayout);
|
||||
vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor
|
||||
} else {
|
||||
FATAL("Cannot allocate staging memory");
|
||||
return GetNull();
|
||||
}
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
void Allocator::updateProperties() {
|
||||
if (hasBudget()) {
|
||||
|
@ -203,12 +256,12 @@ void Allocator::updateProperties() {
|
|||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
|
||||
}
|
||||
}
|
||||
Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties) {
|
||||
Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) {
|
||||
// Search in existing allocations
|
||||
for (auto& alloc: allocations) {
|
||||
if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) &&
|
||||
(getProperties().memoryTypes[alloc->memoryType].propertyFlags & properties) == properties &&
|
||||
alloc->size > requirements.size
|
||||
alloc->size > requirements.size && alloc->optimalTiling == optimalTiling
|
||||
) {
|
||||
VkDeviceSize start = 0;
|
||||
auto aligned = [&](VkDeviceSize offset) {
|
||||
|
@ -261,20 +314,36 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM
|
|||
vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr);
|
||||
}
|
||||
|
||||
auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, ptr)).get();
|
||||
auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, optimalTiling, ptr)).get();
|
||||
allocation->areas.push_back({requirements.size, 0});
|
||||
|
||||
return memory_ptr(new memory_area{memory, requirements.size, 0, ptr}, allocation->deleter);
|
||||
}
|
||||
|
||||
void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) {
|
||||
//FIXME: assert no out of range
|
||||
|
||||
void beginCmd(VkCommandBuffer buffer) {
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
vkBeginCommandBuffer(transferBuffer, &beginInfo);
|
||||
vkBeginCommandBuffer(buffer, &beginInfo);
|
||||
}
|
||||
void submitCmd(VkCommandBuffer buffer, VkQueue queue) {
|
||||
vkEndCommandBuffer(buffer);
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &buffer;
|
||||
|
||||
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
//TODO: parallelize
|
||||
vkQueueWaitIdle(queue); //MAYBE: use fences
|
||||
vkResetCommandBuffer(buffer, 0);
|
||||
}
|
||||
void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) {
|
||||
//FIXME: assert no out of range
|
||||
|
||||
beginCmd(transferBuffer);
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.srcOffset = 0;
|
||||
|
@ -282,17 +351,70 @@ void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size)
|
|||
copyRegion.size = size;
|
||||
vkCmdCopyBuffer(transferBuffer, src.buffer, dst.buffer, 1, ©Region);
|
||||
|
||||
vkEndCommandBuffer(transferBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &transferBuffer;
|
||||
|
||||
vkQueueSubmit(transferQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(transferQueue); //MAYBE: use fences
|
||||
vkResetCommandBuffer(transferBuffer, 0);
|
||||
submitCmd(transferBuffer, transferQueue);
|
||||
}
|
||||
void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
beginCmd(graphicsBuffer);
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = oldLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
} else {
|
||||
FATAL("Unsupported layout transition!");
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(graphicsBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
submitCmd(graphicsBuffer, graphicsQueue);
|
||||
}
|
||||
void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t width, uint32_t height) {
|
||||
beginCmd(transferBuffer);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = src.offset;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {width, height, 1};
|
||||
|
||||
vkCmdCopyBufferToImage(transferBuffer, src.buffer, dest.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
submitCmd(transferBuffer, transferQueue);
|
||||
}
|
||||
|
||||
|
||||
std::optional<uint32_t> Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) {
|
||||
updateProperties();
|
||||
|
@ -350,8 +472,8 @@ void Allocator::MemoryDeleter::operator()(memory_area* area) {
|
|||
LOG_E("Allocation area not found");
|
||||
delete area;
|
||||
}
|
||||
Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, void *ptr):
|
||||
device(device), memory(memory), size(size), memoryType(memoryType), ptr(ptr), deleter(this) { }
|
||||
Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr):
|
||||
device(device), memory(memory), size(size), memoryType(memoryType), optimalTiling(optimalTiling), ptr(ptr), deleter(this) { }
|
||||
Allocator::Allocation::~Allocation() {
|
||||
if(!areas.empty())
|
||||
LOG_E("Freeing " << areas.size() << " floating buffers");
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
using memory_ptr = std::unique_ptr<memory_area, MemoryDeleter>;
|
||||
|
||||
memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags);
|
||||
memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false);
|
||||
bool deallocate(const memory_area&);
|
||||
|
||||
struct buffer_info {
|
||||
|
@ -55,7 +55,17 @@ public:
|
|||
memory_ptr createBuffer(const buffer_requirement&, VkMemoryPropertyFlags, buffer_info&);
|
||||
memory_ptr createBuffers(const std::vector<buffer_requirement> &, VkMemoryPropertyFlags, std::vector<buffer_info> &);
|
||||
|
||||
struct image_info {
|
||||
VkImage image = nullptr;
|
||||
VkDeviceSize offset = 0;
|
||||
};
|
||||
memory_ptr createImage(const VkImageCreateInfo&, VkMemoryPropertyFlags, image_info&,
|
||||
const void *data = nullptr, VkDeviceSize data_size = 0, VkDeviceSize data_offset = 0,
|
||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size);
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||
void copyBufferToImage(buffer_info buffer, image_info image, uint32_t width, uint32_t height);
|
||||
|
||||
void setTracyZone(const char* name);
|
||||
|
||||
|
@ -68,13 +78,14 @@ private:
|
|||
void updateProperties();
|
||||
|
||||
struct Allocation {
|
||||
Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, void *ptr);
|
||||
Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr);
|
||||
~Allocation();
|
||||
|
||||
const VkDevice device;
|
||||
const VkDeviceMemory memory;
|
||||
const VkDeviceSize size;
|
||||
const uint32_t memoryType;
|
||||
const bool optimalTiling;
|
||||
void *const ptr = nullptr;
|
||||
const MemoryDeleter deleter;
|
||||
|
||||
|
@ -92,6 +103,9 @@ private:
|
|||
VkCommandPool transferPool;
|
||||
VkCommandBuffer transferBuffer; // MAYBE: parallel upload
|
||||
TracyVkCtx tracyCtx;
|
||||
VkQueue graphicsQueue;
|
||||
VkCommandPool graphicsPool;
|
||||
VkCommandBuffer graphicsBuffer;
|
||||
|
||||
std::vector<std::unique_ptr<Allocation>> allocations;
|
||||
};
|
||||
|
|
|
@ -4,12 +4,18 @@
|
|||
#include "Pipeline.hpp"
|
||||
#include "../Renderer.hpp"
|
||||
#include "buffer/VertexData.hpp"
|
||||
#include "texture.hpp"
|
||||
|
||||
using namespace render::vk;
|
||||
|
||||
#define CONTENT_DIR "content/"
|
||||
#define TEXTURES_DIR CONTENT_DIR "textures/"
|
||||
|
||||
CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vector<VkImageView> &views,
|
||||
const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt):
|
||||
device(device), indexedBufferMemory(Allocator::GetNull()), uniformBuffersMemory(Allocator::GetNull()) {
|
||||
const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device),
|
||||
indexedBufferMemory(Allocator::GetNull()), sampleImageMemory(Allocator::GetNull()),
|
||||
uniformBuffersMemory(Allocator::GetNull())
|
||||
{
|
||||
{ // Graphics command pool
|
||||
vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue);
|
||||
VkCommandPoolCreateInfo poolInfo{};
|
||||
|
@ -34,6 +40,80 @@ device(device), indexedBufferMemory(Allocator::GetNull()), uniformBuffersMemory(
|
|||
FATAL("Cannot create vertex buffer");
|
||||
}
|
||||
}
|
||||
{ // Texture sampler (const)
|
||||
std::vector<unsigned char> data;
|
||||
dds::header_info header;
|
||||
if (dds::readDDS(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", data, header)) {
|
||||
FATAL("Cannot read texture");
|
||||
}
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = header.width;
|
||||
imageInfo.extent.height = header.height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = header.mipMapCount; //TODO:
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = header.format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.flags = 0;
|
||||
|
||||
sampleImageMemory = alloc.createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, sampleImage, data.data(), data.size());
|
||||
if(!sampleImageMemory) {
|
||||
FATAL("Cannot create texture image");
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = sampleImage.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = 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;
|
||||
if (vkCreateImageView(device, &viewInfo, nullptr, &sampleImageView) != VK_SUCCESS) {
|
||||
FATAL("Failed to create texture image view!");
|
||||
}
|
||||
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
|
||||
if (info.features.samplerAnisotropy && opt.anisotropy > 0) {
|
||||
samplerInfo.anisotropyEnable = VK_TRUE;
|
||||
samplerInfo.maxAnisotropy = 1 << (opt.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;
|
||||
|
||||
if (vkCreateSampler(device, &samplerInfo, nullptr, &sampleSampler) != VK_SUCCESS) {
|
||||
FATAL("Failed to create texture sampler!");
|
||||
}
|
||||
}
|
||||
|
||||
allocate(alloc, views, pipe, info.swapDetails.capabilities.currentExtent, opt);
|
||||
}
|
||||
|
@ -45,6 +125,11 @@ CommandCenter::~CommandCenter() {
|
|||
vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC);
|
||||
indexedBufferMemory.reset();
|
||||
|
||||
vkDestroySampler(device, sampleSampler, ALLOC);
|
||||
vkDestroyImageView(device, sampleImageView, ALLOC);
|
||||
vkDestroyImage(device, sampleImage.image, ALLOC);
|
||||
sampleImageMemory.reset();
|
||||
|
||||
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
||||
}
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
@ -83,14 +168,16 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
|||
}
|
||||
}
|
||||
{ // Descriptor pool
|
||||
VkDescriptorPoolSize poolSize{};
|
||||
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
poolSize.descriptorCount = framebuffers.size();
|
||||
std::array<VkDescriptorPoolSize, 2> poolSizes{};
|
||||
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
poolSizes[0].descriptorCount = framebuffers.size();
|
||||
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
poolSizes[1].descriptorCount = framebuffers.size();
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
poolInfo.poolSizeCount = 1;
|
||||
poolInfo.pPoolSizes = &poolSize;
|
||||
poolInfo.poolSizeCount = poolSizes.size();
|
||||
poolInfo.pPoolSizes = poolSizes.data();
|
||||
poolInfo.maxSets = framebuffers.size();
|
||||
poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
|
||||
|
||||
|
@ -117,20 +204,29 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
|||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = sizeof(buffer::vk::UniformBufferObject);
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = descriptorSets[i];
|
||||
descriptorWrite.dstBinding = 0;
|
||||
descriptorWrite.dstArrayElement = 0;
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = sampleImageView;
|
||||
imageInfo.sampler = sampleSampler;
|
||||
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
||||
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrites[0].dstSet = descriptorSets[i];
|
||||
descriptorWrites[0].dstBinding = 0;
|
||||
descriptorWrites[0].dstArrayElement = 0;
|
||||
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptorWrites[0].descriptorCount = 1;
|
||||
descriptorWrites[0].pBufferInfo = &bufferInfo;
|
||||
|
||||
descriptorWrite.pBufferInfo = &bufferInfo;
|
||||
descriptorWrite.pImageInfo = nullptr;
|
||||
descriptorWrite.pTexelBufferView = nullptr;
|
||||
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrites[1].dstSet = descriptorSets[i];
|
||||
descriptorWrites[1].dstBinding = 1;
|
||||
descriptorWrites[1].dstArrayElement = 0;
|
||||
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrites[1].descriptorCount = 1;
|
||||
descriptorWrites[1].pImageInfo = &imageInfo;
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
|
||||
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,11 @@ private:
|
|||
Allocator::buffer_info indexBuffer;
|
||||
Allocator::memory_ptr indexedBufferMemory;
|
||||
|
||||
Allocator::image_info sampleImage;
|
||||
VkImageView sampleImageView;
|
||||
VkSampler sampleSampler;
|
||||
Allocator::memory_ptr sampleImageMemory;
|
||||
|
||||
glm::mat4 proj;
|
||||
std::vector<Allocator::buffer_info> uniformBuffers;
|
||||
Allocator::memory_ptr uniformBuffersMemory;
|
||||
|
|
|
@ -26,7 +26,11 @@ struct PhysicalDeviceInfo {
|
|||
PhysicalDeviceInfo() {}
|
||||
PhysicalDeviceInfo(GLFWwindow *window, VkPhysicalDevice device, VkSurfaceKHR surface):
|
||||
window(window), device(device), surface(surface),
|
||||
swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface)) { }
|
||||
swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface))
|
||||
{
|
||||
vkGetPhysicalDeviceProperties(device, &properties);
|
||||
vkGetPhysicalDeviceFeatures(device, &features);
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR getFormat() const;
|
||||
bool hasMemoryBudget() const;
|
||||
|
@ -36,6 +40,8 @@ struct PhysicalDeviceInfo {
|
|||
VkSurfaceKHR surface;
|
||||
SwapChainSupportDetails swapDetails;
|
||||
QueueFamilyIndices queueIndices;
|
||||
VkPhysicalDeviceProperties properties;
|
||||
VkPhysicalDeviceFeatures features;
|
||||
std::vector<const char *> optionalExtensions;
|
||||
};
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#define CONTENT_DIR "content/"
|
||||
#define SHADER_DIR CONTENT_DIR "shaders/"
|
||||
#define TEXTURES_DIR CONTENT_DIR "textures/"
|
||||
|
||||
constexpr auto BLENDING = true;
|
||||
|
||||
|
@ -58,10 +57,17 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
|
|||
}
|
||||
}
|
||||
{
|
||||
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
|
||||
samplerLayoutBinding.binding = 1;
|
||||
samplerLayoutBinding.descriptorCount = 1;
|
||||
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
samplerLayoutBinding.pImmutableSamplers = nullptr;
|
||||
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings = {buffer::vk::UniformBufferObject::getLayoutBinding(), samplerLayoutBinding};
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layoutInfo.bindingCount = 1;
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings = {buffer::vk::UniformBufferObject::getLayoutBinding()};
|
||||
layoutInfo.bindingCount = bindings.size();
|
||||
layoutInfo.pBindings = bindings.data();
|
||||
|
||||
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &descriptorSetLayout) != VK_SUCCESS) {
|
||||
|
|
|
@ -289,15 +289,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
uint bestScore = 0;
|
||||
for(const auto& device: devices) {
|
||||
uint score = 1;
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
|
||||
auto infos = PhysicalDeviceInfo(window.getPtr(), device, surface);
|
||||
|
||||
//FIXME: if (!deviceFeatures.geometryShader) continue;
|
||||
|
||||
{
|
||||
uint32_t availableExtensionsCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &availableExtensionsCount, nullptr);
|
||||
|
@ -324,10 +317,17 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
}
|
||||
}
|
||||
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
if (infos.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
score += 10000;
|
||||
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
score += infos.properties.limits.maxImageDimension2D;
|
||||
|
||||
if (infos.features.geometryShader)
|
||||
score += 2000;
|
||||
|
||||
if (infos.features.samplerAnisotropy)
|
||||
score += 1000;
|
||||
|
||||
//TODO: check others limits
|
||||
|
||||
if (!infos.queueIndices.isComplete())
|
||||
|
@ -347,9 +347,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
LOG_E("Any GPU matching requirements");
|
||||
return false;
|
||||
}
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(physicalInfo.device, &deviceProperties);
|
||||
LOG_D("Using " << deviceProperties.deviceName);
|
||||
LOG_D("Using " << physicalInfo.properties.deviceName);
|
||||
}
|
||||
|
||||
VkDevice device;
|
||||
|
@ -371,7 +369,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
}
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
//TODO:
|
||||
deviceFeatures.geometryShader = physicalInfo.features.geometryShader;
|
||||
deviceFeatures.samplerAnisotropy = physicalInfo.features.samplerAnisotropy;
|
||||
|
||||
std::vector<const char*> extensions(requiredExtensions);
|
||||
extensions.insert(extensions.end(), physicalInfo.optionalExtensions.begin(), physicalInfo.optionalExtensions.end());
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace buffer::vk {
|
|||
struct VertexData {
|
||||
glm::vec2 pos;
|
||||
glm::vec3 color;
|
||||
glm::vec2 uv;
|
||||
|
||||
static VkVertexInputBindingDescription getBindingDescription() {
|
||||
VkVertexInputBindingDescription description{};
|
||||
|
@ -18,8 +19,8 @@ struct VertexData {
|
|||
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
return description;
|
||||
}
|
||||
static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};
|
||||
static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
|
||||
attributeDescriptions[0].binding = 0;
|
||||
attributeDescriptions[0].location = 0;
|
||||
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
|
@ -28,15 +29,19 @@ struct VertexData {
|
|||
attributeDescriptions[1].location = 1;
|
||||
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[1].offset = offsetof(VertexData, color);
|
||||
attributeDescriptions[2].binding = 0;
|
||||
attributeDescriptions[2].location = 2;
|
||||
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attributeDescriptions[2].offset = offsetof(VertexData, uv);
|
||||
return attributeDescriptions;
|
||||
}
|
||||
};
|
||||
|
||||
const std::vector<VertexData> vertices = {
|
||||
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
|
||||
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}
|
||||
};
|
||||
const std::vector<uint16_t> indices = {
|
||||
0, 1, 2, 2, 3, 0
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
#include "texture.hpp"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
|
||||
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
|
||||
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
|
||||
|
||||
VkResult render::vk::dds::readDDS(const std::string& imagepath, std::vector<unsigned char>& data, header_info& info) {
|
||||
|
||||
unsigned char header[124];
|
||||
|
||||
FILE *fp;
|
||||
|
||||
/* try to open the file */
|
||||
fp = fopen(imagepath.c_str(), "rb");
|
||||
if (fp == NULL){
|
||||
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
|
||||
return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT;
|
||||
}
|
||||
|
||||
/* verify the type of file */
|
||||
char filecode[4];
|
||||
fread(filecode, 1, 4, fp);
|
||||
if (strncmp(filecode, "DDS ", 4) != 0) {
|
||||
fclose(fp);
|
||||
return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT;
|
||||
}
|
||||
|
||||
/* get the surface desc */
|
||||
fread(&header, 124, 1, fp);
|
||||
|
||||
info.height = *(unsigned int*)&(header[8 ]);
|
||||
info.width = *(unsigned int*)&(header[12]);
|
||||
unsigned int linearSize = *(unsigned int*)&(header[16]);
|
||||
info.mipMapCount = *(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.mipMapCount > 1 ? linearSize * 2 : linearSize;
|
||||
data.resize(bufsize);
|
||||
fread(data.data(), 1, bufsize, fp);
|
||||
/* close the file pointer */
|
||||
fclose(fp);
|
||||
|
||||
switch(fourCC)
|
||||
{
|
||||
case FOURCC_DXT1:
|
||||
info.format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
|
||||
break;
|
||||
case FOURCC_DXT3:
|
||||
info.format = VK_FORMAT_BC2_SRGB_BLOCK;
|
||||
break;
|
||||
case FOURCC_DXT5:
|
||||
info.format = VK_FORMAT_BC3_SRGB_BLOCK;
|
||||
break;
|
||||
//MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK
|
||||
default:
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
#if FALSE
|
||||
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST);
|
||||
|
||||
TODO: glGenerateTextureMipmap(textureID);
|
||||
#endif
|
||||
return VK_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <volk.h>
|
||||
|
||||
namespace render::vk::dds {
|
||||
struct header_info {
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
unsigned int mipMapCount;
|
||||
VkFormat format;
|
||||
};
|
||||
VkResult readDDS(const std::string& imagepath, std::vector<unsigned char>& data, header_info& info);
|
||||
}
|
Loading…
Reference in New Issue