holy shit an image
This commit is contained in:
parent
f4fcfd3fda
commit
b97a9e2b7b
7988
include/stb_image.h
Normal file
7988
include/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
14
meson.build
14
meson.build
|
@ -24,16 +24,6 @@ common_cpp_args = [
|
||||||
|
|
||||||
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
|
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
|
||||||
|
|
||||||
source_file_names = [
|
|
||||||
'src/main.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
sources = []
|
|
||||||
|
|
||||||
foreach file : source_file_names
|
|
||||||
sources += files(file)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
dependency('fmt', include_type: 'system'),
|
dependency('fmt', include_type: 'system'),
|
||||||
dependency('glfw3', include_type: 'system'),
|
dependency('glfw3', include_type: 'system'),
|
||||||
|
@ -43,7 +33,7 @@ deps = [
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'graphics-test',
|
'graphics-test',
|
||||||
sources,
|
sources: files('src/main.cpp'),
|
||||||
include_directories: include_directories('include', is_system: true),
|
include_directories: include_directories('include', is_system: true),
|
||||||
dependencies: deps,
|
dependencies: deps,
|
||||||
)
|
)
|
||||||
|
|
338
src/main.cpp
338
src/main.cpp
|
@ -1,12 +1,13 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <glm/glm.hpp>
|
#include <stb_image.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||||
#define VK_ENABLE_BETA_EXTENSIONS
|
#define VK_ENABLE_BETA_EXTENSIONS
|
||||||
|
@ -43,24 +44,26 @@ constexpr bool enableValidationLayers = true;
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec2 pos;
|
glm::vec2 pos;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
|
glm::vec2 tex_coord;
|
||||||
|
|
||||||
static fn getBindingDescription() -> vk::VertexInputBindingDescription {
|
static fn getBindingDescription() -> vk::VertexInputBindingDescription {
|
||||||
return { .binding = 0, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex };
|
return { .binding = 0, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex };
|
||||||
}
|
}
|
||||||
|
|
||||||
static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 2> {
|
static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 3> {
|
||||||
return {
|
return {
|
||||||
vk::VertexInputAttributeDescription { 0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, pos) },
|
{ { 0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, pos) },
|
||||||
vk::VertexInputAttributeDescription { 1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color) }
|
{ 1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color) },
|
||||||
|
{ 2, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, tex_coord) } }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<Vertex, 4> vertices = {
|
constexpr std::array<Vertex, 4> vertices = {
|
||||||
{ { { -0.5F, -0.5F }, { 1.0F, 0.0F, 0.0F } },
|
{ { { -0.5F, -0.5F }, { 1.0F, 0.0F, 0.0F }, { 1.0F, 0.0F } },
|
||||||
{ { 0.5F, -0.5F }, { 0.0F, 1.0F, 0.0F } },
|
{ { 0.5F, -0.5F }, { 0.0F, 1.0F, 0.0F }, { 0.0F, 0.0F } },
|
||||||
{ { 0.5F, 0.5F }, { 0.0F, 0.0F, 1.0F } },
|
{ { 0.5F, 0.5F }, { 0.0F, 0.0F, 1.0F }, { 0.0F, 1.0F } },
|
||||||
{ { -0.5F, 0.5F }, { 1.0F, 1.0F, 1.0F } } }
|
{ { -0.5F, 0.5F }, { 1.0F, 1.0F, 1.0F }, { 1.0F, 1.0F } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<u16, 6> indices = { 0, 1, 2, 2, 3, 0 };
|
constexpr std::array<u16, 6> indices = { 0, 1, 2, 2, 3, 0 };
|
||||||
|
@ -102,6 +105,11 @@ class VulkanApp {
|
||||||
|
|
||||||
vk::UniqueCommandPool mCommandPool;
|
vk::UniqueCommandPool mCommandPool;
|
||||||
|
|
||||||
|
vk::UniqueImage mTextureImage;
|
||||||
|
vk::UniqueDeviceMemory mTextureImageMemory;
|
||||||
|
vk::UniqueImageView mTextureImageView;
|
||||||
|
vk::UniqueSampler mTextureSampler;
|
||||||
|
|
||||||
vk::UniqueBuffer mVertexBuffer;
|
vk::UniqueBuffer mVertexBuffer;
|
||||||
vk::UniqueDeviceMemory mVertexBufferMemory;
|
vk::UniqueDeviceMemory mVertexBufferMemory;
|
||||||
vk::UniqueBuffer mIndexBuffer;
|
vk::UniqueBuffer mIndexBuffer;
|
||||||
|
@ -190,6 +198,9 @@ class VulkanApp {
|
||||||
createGraphicsPipeline();
|
createGraphicsPipeline();
|
||||||
createFramebuffers();
|
createFramebuffers();
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
|
createTextureImage();
|
||||||
|
createTextureImageView();
|
||||||
|
createTextureSampler();
|
||||||
createVertexBuffer();
|
createVertexBuffer();
|
||||||
createIndexBuffer();
|
createIndexBuffer();
|
||||||
createUniformBuffers();
|
createUniformBuffers();
|
||||||
|
@ -341,7 +352,9 @@ class VulkanApp {
|
||||||
queueCreateInfos.emplace_back(queueCreateInfo);
|
queueCreateInfos.emplace_back(queueCreateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::PhysicalDeviceFeatures deviceFeatures;
|
vk::PhysicalDeviceFeatures deviceFeatures {
|
||||||
|
.samplerAnisotropy = vk::True,
|
||||||
|
};
|
||||||
|
|
||||||
vk::DeviceCreateInfo createInfo { .queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
vk::DeviceCreateInfo createInfo { .queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
||||||
.pQueueCreateInfos = queueCreateInfos.data(),
|
.pQueueCreateInfos = queueCreateInfos.data(),
|
||||||
|
@ -466,9 +479,19 @@ class VulkanApp {
|
||||||
.pImmutableSamplers = nullptr,
|
.pImmutableSamplers = nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vk::DescriptorSetLayoutBinding samplerLayoutBinding {
|
||||||
|
.binding = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<vk::DescriptorSetLayoutBinding, 2> bindings = { uboLayoutBinding, samplerLayoutBinding };
|
||||||
|
|
||||||
vk::DescriptorSetLayoutCreateInfo layoutInfo {
|
vk::DescriptorSetLayoutCreateInfo layoutInfo {
|
||||||
.bindingCount = 1,
|
.bindingCount = static_cast<u32>(bindings.size()),
|
||||||
.pBindings = &uboLayoutBinding,
|
.pBindings = bindings.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mDescriptorSetLayout = mDevice->createDescriptorSetLayoutUnique(layoutInfo);
|
mDescriptorSetLayout = mDevice->createDescriptorSetLayoutUnique(layoutInfo);
|
||||||
|
@ -497,7 +520,7 @@ class VulkanApp {
|
||||||
fragShaderStageInfo };
|
fragShaderStageInfo };
|
||||||
|
|
||||||
vk::VertexInputBindingDescription bindingDescription = Vertex::getBindingDescription();
|
vk::VertexInputBindingDescription bindingDescription = Vertex::getBindingDescription();
|
||||||
std::array<vk::VertexInputAttributeDescription, 2> attributeDescriptions =
|
std::array<vk::VertexInputAttributeDescription, 3> attributeDescriptions =
|
||||||
Vertex::getAttributeDescriptions();
|
Vertex::getAttributeDescriptions();
|
||||||
|
|
||||||
vk::PipelineVertexInputStateCreateInfo vertexInputInfo {
|
vk::PipelineVertexInputStateCreateInfo vertexInputInfo {
|
||||||
|
@ -615,6 +638,213 @@ class VulkanApp {
|
||||||
mCommandPool = mDevice->createCommandPoolUnique(poolInfo);
|
mCommandPool = mDevice->createCommandPoolUnique(poolInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn createTextureImage() -> void {
|
||||||
|
i32 texWidth = 0, texHeight = 0, texChannels = 0;
|
||||||
|
stbi_uc* pixels =
|
||||||
|
stbi_load("src/textures/texture.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
|
|
||||||
|
vk::DeviceSize imageSize =
|
||||||
|
static_cast<vk::DeviceSize>(texWidth) * static_cast<vk::DeviceSize>(texHeight) * 4;
|
||||||
|
|
||||||
|
if (!pixels)
|
||||||
|
throw std::runtime_error("Failed to load texture image!");
|
||||||
|
|
||||||
|
vk::UniqueBuffer stagingBuffer;
|
||||||
|
vk::UniqueDeviceMemory stagingBufferMemory;
|
||||||
|
|
||||||
|
createBuffer(
|
||||||
|
imageSize,
|
||||||
|
vk::BufferUsageFlagBits::eTransferSrc,
|
||||||
|
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
|
||||||
|
stagingBuffer,
|
||||||
|
stagingBufferMemory
|
||||||
|
);
|
||||||
|
|
||||||
|
copyData(stagingBufferMemory.get(), imageSize, pixels);
|
||||||
|
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
createImage(
|
||||||
|
static_cast<u32>(texWidth),
|
||||||
|
static_cast<u32>(texHeight),
|
||||||
|
vk::Format::eR8G8B8A8Srgb,
|
||||||
|
vk::ImageTiling::eOptimal,
|
||||||
|
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
|
||||||
|
vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||||
|
mTextureImage,
|
||||||
|
mTextureImageMemory
|
||||||
|
);
|
||||||
|
|
||||||
|
transitionImageLayout(
|
||||||
|
mTextureImage.get(),
|
||||||
|
vk::Format::eR8G8B8A8Srgb,
|
||||||
|
vk::ImageLayout::eUndefined,
|
||||||
|
vk::ImageLayout::eTransferDstOptimal
|
||||||
|
);
|
||||||
|
|
||||||
|
copyBufferToImage(
|
||||||
|
stagingBuffer.get(), mTextureImage.get(), static_cast<u32>(texWidth), static_cast<u32>(texHeight)
|
||||||
|
);
|
||||||
|
|
||||||
|
transitionImageLayout(
|
||||||
|
mTextureImage.get(),
|
||||||
|
vk::Format::eR8G8B8A8Srgb,
|
||||||
|
vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
vk::ImageLayout::eShaderReadOnlyOptimal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createTextureImageView() -> void {
|
||||||
|
mTextureImageView =
|
||||||
|
createImageView(mTextureImage.get(), vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createTextureSampler() -> void {
|
||||||
|
vk::PhysicalDeviceProperties properties = mPhysicalDevice.getProperties();
|
||||||
|
|
||||||
|
vk::SamplerCreateInfo samplerInfo {
|
||||||
|
.magFilter = vk::Filter::eLinear,
|
||||||
|
.minFilter = vk::Filter::eLinear,
|
||||||
|
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||||
|
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.mipLodBias = 0.0F,
|
||||||
|
.anisotropyEnable = vk::False,
|
||||||
|
.maxAnisotropy = properties.limits.maxSamplerAnisotropy,
|
||||||
|
.compareEnable = vk::False,
|
||||||
|
.compareOp = vk::CompareOp::eAlways,
|
||||||
|
.minLod = 0.0F,
|
||||||
|
.maxLod = 0.0F,
|
||||||
|
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||||
|
.unnormalizedCoordinates = vk::False,
|
||||||
|
};
|
||||||
|
|
||||||
|
mTextureSampler = mDevice->createSamplerUnique(samplerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createImageView(vk::Image image, vk::Format format, vk::ImageAspectFlags aspectFlags)
|
||||||
|
-> vk::UniqueImageView {
|
||||||
|
vk::ImageViewCreateInfo viewInfo {
|
||||||
|
.image = image, .viewType = vk::ImageViewType::e2D, .format = format, .subresourceRange = {
|
||||||
|
.aspectMask = aspectFlags,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return mDevice->createImageViewUnique(viewInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createImage(
|
||||||
|
u32 width,
|
||||||
|
u32 height,
|
||||||
|
vk::Format format,
|
||||||
|
vk::ImageTiling tiling,
|
||||||
|
vk::ImageUsageFlags usage,
|
||||||
|
vk::MemoryPropertyFlags properties,
|
||||||
|
vk::UniqueImage& image,
|
||||||
|
vk::UniqueDeviceMemory& imageMemory
|
||||||
|
) -> void {
|
||||||
|
vk::ImageCreateInfo imageInfo {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = format,
|
||||||
|
.extent = { .width = width, .height = height, .depth = 1 },
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
|
.tiling = tiling,
|
||||||
|
.usage = usage,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive,
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
image = mDevice->createImageUnique(imageInfo);
|
||||||
|
|
||||||
|
vk::MemoryRequirements memRequirements = mDevice->getImageMemoryRequirements(image.get());
|
||||||
|
|
||||||
|
vk::MemoryAllocateInfo allocInfo {
|
||||||
|
.allocationSize = memRequirements.size,
|
||||||
|
.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties),
|
||||||
|
};
|
||||||
|
|
||||||
|
imageMemory = mDevice->allocateMemoryUnique(allocInfo);
|
||||||
|
|
||||||
|
mDevice->bindImageMemory(image.get(), imageMemory.get(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transitionImageLayout(
|
||||||
|
vk::Image image,
|
||||||
|
vk::Format format,
|
||||||
|
vk::ImageLayout oldLayout,
|
||||||
|
vk::ImageLayout newLayout
|
||||||
|
) -> void {
|
||||||
|
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier barrier {
|
||||||
|
.srcAccessMask = { },
|
||||||
|
.dstAccessMask = { },
|
||||||
|
.oldLayout = oldLayout,
|
||||||
|
.newLayout = newLayout,
|
||||||
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
|
.image = image,
|
||||||
|
// clang-format off
|
||||||
|
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1 },
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineStageFlags sourceStage;
|
||||||
|
vk::PipelineStageFlags destinationStage;
|
||||||
|
|
||||||
|
if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) {
|
||||||
|
barrier.srcAccessMask = {};
|
||||||
|
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||||
|
|
||||||
|
sourceStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||||
|
destinationStage = vk::PipelineStageFlagBits::eTransfer;
|
||||||
|
} else if (oldLayout == vk::ImageLayout::eTransferDstOptimal &&
|
||||||
|
newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) {
|
||||||
|
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||||
|
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||||
|
|
||||||
|
sourceStage = vk::PipelineStageFlagBits::eTransfer;
|
||||||
|
destinationStage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("Unsupported layout transition!");
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBuffer->pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier);
|
||||||
|
|
||||||
|
endSingleTimeCommands(std::move(commandBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copyBufferToImage(vk::Buffer buffer, vk::Image image, u32 width, u32 height) -> void {
|
||||||
|
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
|
vk::BufferImageCopy region {
|
||||||
|
.bufferOffset = 0,
|
||||||
|
.bufferRowLength = 0,
|
||||||
|
.bufferImageHeight = 0,
|
||||||
|
.imageSubresource = { .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.mipLevel = 0,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1 },
|
||||||
|
.imageOffset = { 0, 0, 0 },
|
||||||
|
.imageExtent = { width, height, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
commandBuffer->copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion);
|
||||||
|
|
||||||
|
endSingleTimeCommands(std::move(commandBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
fn createVertexBuffer() -> void {
|
fn createVertexBuffer() -> void {
|
||||||
vk::DeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
|
vk::DeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
|
||||||
|
|
||||||
|
@ -629,9 +859,7 @@ class VulkanApp {
|
||||||
stagingBufferMemory
|
stagingBufferMemory
|
||||||
);
|
);
|
||||||
|
|
||||||
void* data = mDevice->mapMemory(stagingBufferMemory.get(), 0, bufferSize);
|
copyData(stagingBufferMemory.get(), bufferSize, vertices.data());
|
||||||
memcpy(data, vertices.data(), static_cast<usize>(bufferSize));
|
|
||||||
mDevice->unmapMemory(stagingBufferMemory.get());
|
|
||||||
|
|
||||||
createBuffer(
|
createBuffer(
|
||||||
bufferSize,
|
bufferSize,
|
||||||
|
@ -661,9 +889,7 @@ class VulkanApp {
|
||||||
stagingBufferMemory
|
stagingBufferMemory
|
||||||
);
|
);
|
||||||
|
|
||||||
void* data = mDevice->mapMemory(stagingBufferMemory.get(), 0, bufferSize);
|
copyData(stagingBufferMemory.get(), bufferSize, indices.data());
|
||||||
memcpy(data, indices.data(), static_cast<usize>(bufferSize));
|
|
||||||
mDevice->unmapMemory(stagingBufferMemory.get());
|
|
||||||
|
|
||||||
createBuffer(
|
createBuffer(
|
||||||
bufferSize,
|
bufferSize,
|
||||||
|
@ -700,15 +926,15 @@ class VulkanApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createDescriptorPool() -> void {
|
fn createDescriptorPool() -> void {
|
||||||
vk::DescriptorPoolSize poolSize {
|
std::array<vk::DescriptorPoolSize, 2> poolSizes = {
|
||||||
.type = vk::DescriptorType::eUniformBuffer,
|
{ { .type = vk::DescriptorType::eUniformBuffer, .descriptorCount = MAX_FRAMES_IN_FLIGHT },
|
||||||
.descriptorCount = static_cast<u32>(MAX_FRAMES_IN_FLIGHT),
|
{ .type = vk::DescriptorType::eCombinedImageSampler, .descriptorCount = MAX_FRAMES_IN_FLIGHT } },
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::DescriptorPoolCreateInfo poolInfo {
|
vk::DescriptorPoolCreateInfo poolInfo {
|
||||||
.maxSets = static_cast<u32>(MAX_FRAMES_IN_FLIGHT),
|
.maxSets = MAX_FRAMES_IN_FLIGHT,
|
||||||
.poolSizeCount = 1,
|
.poolSizeCount = static_cast<u32>(poolSizes.size()),
|
||||||
.pPoolSizes = &poolSize,
|
.pPoolSizes = poolSizes.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
mDescriptorPool = mDevice->createDescriptorPoolUnique(poolInfo);
|
mDescriptorPool = mDevice->createDescriptorPoolUnique(poolInfo);
|
||||||
|
@ -732,16 +958,31 @@ class VulkanApp {
|
||||||
.range = sizeof(UniformBufferObject),
|
.range = sizeof(UniformBufferObject),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::WriteDescriptorSet descriptorWrite {
|
vk::DescriptorImageInfo imageInfo {
|
||||||
.dstSet = mDescriptorSets[i],
|
.sampler = mTextureSampler.get(),
|
||||||
.dstBinding = 0,
|
.imageView = mTextureImageView.get(),
|
||||||
.dstArrayElement = 0,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
|
||||||
.pBufferInfo = &bufferInfo,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mDevice->updateDescriptorSets(1, &descriptorWrite, 0, nullptr);
|
std::array<vk::WriteDescriptorSet, 2> descriptorWrites = {
|
||||||
|
{ {
|
||||||
|
.dstSet = mDescriptorSets[i],
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||||
|
.pBufferInfo = &bufferInfo,
|
||||||
|
}, {
|
||||||
|
.dstSet = mDescriptorSets[i],
|
||||||
|
.dstBinding = 1,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.pImageInfo = &imageInfo,
|
||||||
|
} }
|
||||||
|
};
|
||||||
|
|
||||||
|
mDevice->updateDescriptorSets(descriptorWrites, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +1013,7 @@ class VulkanApp {
|
||||||
mDevice->bindBufferMemory(buffer.get(), bufferMemory.get(), 0);
|
mDevice->bindBufferMemory(buffer.get(), bufferMemory.get(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize deviceSize) -> void {
|
fn beginSingleTimeCommands() -> vk::UniqueCommandBuffer {
|
||||||
vk::CommandBufferAllocateInfo allocInfo {
|
vk::CommandBufferAllocateInfo allocInfo {
|
||||||
.commandPool = mCommandPool.get(),
|
.commandPool = mCommandPool.get(),
|
||||||
.level = vk::CommandBufferLevel::ePrimary,
|
.level = vk::CommandBufferLevel::ePrimary,
|
||||||
|
@ -785,10 +1026,10 @@ class VulkanApp {
|
||||||
|
|
||||||
commandBuffer->begin(beginInfo);
|
commandBuffer->begin(beginInfo);
|
||||||
|
|
||||||
vk::BufferCopy copyRegion { .size = deviceSize };
|
return commandBuffer;
|
||||||
|
}
|
||||||
commandBuffer->copyBuffer(srcBuffer, dstBuffer, 1, ©Region);
|
|
||||||
|
|
||||||
|
fn endSingleTimeCommands(vk::UniqueCommandBuffer commandBuffer) -> void {
|
||||||
commandBuffer->end();
|
commandBuffer->end();
|
||||||
|
|
||||||
vk::SubmitInfo submitInfo { .commandBufferCount = 1, .pCommandBuffers = &commandBuffer.get() };
|
vk::SubmitInfo submitInfo { .commandBufferCount = 1, .pCommandBuffers = &commandBuffer.get() };
|
||||||
|
@ -797,6 +1038,22 @@ class VulkanApp {
|
||||||
mGraphicsQueue.waitIdle();
|
mGraphicsQueue.waitIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copyData(vk::DeviceMemory stagingBufferMemory, vk::DeviceSize bufferSize, const void* src) -> void {
|
||||||
|
void* data = mDevice->mapMemory(stagingBufferMemory, 0, bufferSize);
|
||||||
|
memcpy(data, src, static_cast<usize>(bufferSize));
|
||||||
|
mDevice->unmapMemory(stagingBufferMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize deviceSize) -> void {
|
||||||
|
vk::UniqueCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||||
|
|
||||||
|
vk::BufferCopy copyRegion { .size = deviceSize };
|
||||||
|
|
||||||
|
commandBuffer->copyBuffer(srcBuffer, dstBuffer, 1, ©Region);
|
||||||
|
|
||||||
|
endSingleTimeCommands(std::move(commandBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
fn findMemoryType(u32 typeFilter, vk::MemoryPropertyFlags properties) -> u32 {
|
fn findMemoryType(u32 typeFilter, vk::MemoryPropertyFlags properties) -> u32 {
|
||||||
vk::PhysicalDeviceMemoryProperties memProperties = mPhysicalDevice.getMemoryProperties();
|
vk::PhysicalDeviceMemoryProperties memProperties = mPhysicalDevice.getMemoryProperties();
|
||||||
|
|
||||||
|
@ -1052,7 +1309,10 @@ class VulkanApp {
|
||||||
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty();
|
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return qfIndices.isComplete() && extensionsSupported && swapChainAdequate;
|
vk::PhysicalDeviceFeatures supportedFeatures = device.getFeatures();
|
||||||
|
|
||||||
|
return qfIndices.isComplete() && extensionsSupported && swapChainAdequate &&
|
||||||
|
supportedFeatures.samplerAnisotropy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fn checkDeviceExtensionSupport(vk::PhysicalDevice device) -> bool {
|
static fn checkDeviceExtensionSupport(vk::PhysicalDevice device) -> bool {
|
||||||
|
|
Binary file not shown.
|
@ -1,9 +1,12 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D texSampler;
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 1.0);
|
outColor = texture(texSampler, fragTexCoord);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,13 @@ layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
layout(location = 0) in vec2 inPosition;
|
||||||
layout(location = 1) in vec3 inColor;
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec2 inTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
||||||
fragColor = inColor;
|
fragColor = inColor;
|
||||||
|
fragTexCoord = inTexCoord;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
BIN
src/textures/texture.jpg
Normal file
BIN
src/textures/texture.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Loading…
Reference in a new issue