summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitmodules3
-rw-r--r--Makefile1
-rw-r--r--engine/xe_descriptors.cpp4
-rw-r--r--engine/xe_descriptors.hpp2
-rw-r--r--engine/xe_engine.cpp14
-rw-r--r--engine/xe_engine.hpp9
-rw-r--r--engine/xe_image.cpp166
-rw-r--r--engine/xe_image.hpp35
-rw-r--r--engine/xe_render_system.cpp149
-rw-r--r--engine/xe_render_system.hpp25
-rwxr-xr-xengine/xe_swap_chain.hpp2
m---------lib/stb0
-rw-r--r--res/image/scaly.pngbin0 -> 3227705 bytes
-rw-r--r--res/image/texture.pngbin0 -> 1338368 bytes
-rwxr-xr-xres/shaders/simple_shader.frag7
-rw-r--r--res/shaders/simple_shader.frag.spvbin1112 -> 1456 bytes
-rwxr-xr-xres/shaders/simple_shader.vert16
-rw-r--r--res/shaders/simple_shader.vert.spvbin2816 -> 2912 bytes
-rwxr-xr-xsrc/first_app.cpp11
-rw-r--r--src/simple_renderer.cpp13
-rw-r--r--src/simple_renderer.hpp4
21 files changed, 396 insertions, 65 deletions
diff --git a/.gitmodules b/.gitmodules
index 4214750..c48bf84 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "glm"]
path = lib/glm
url = https://github.com/g-truc/glm.git
+[submodule "stb"]
+ path = lib/stb
+ url = https://github.com/nothings/stb.git
diff --git a/Makefile b/Makefile
index 561c5bf..a97fd1d 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ INCFLAGS = -Isrc
INCFLAGS += -Iengine
INCFLAGS += -Ilib/glfw/include
INCFLAGS += -Ilib/glm
+INCFLAGS += -Ilib/stb
CCFLAGS = -std=c++17 -O2 -g
CCFLAGS += $(INCFLAGS)
diff --git a/engine/xe_descriptors.cpp b/engine/xe_descriptors.cpp
index ef6dc2c..f1f4436 100644
--- a/engine/xe_descriptors.cpp
+++ b/engine/xe_descriptors.cpp
@@ -9,13 +9,15 @@ XeDescriptorSetLayout::Builder &XeDescriptorSetLayout::Builder::addBinding(
uint32_t binding,
VkDescriptorType descriptorType,
VkShaderStageFlags stageFlags,
- uint32_t count) {
+ VkSampler *sampler) {
assert(bindings.count(binding) == 0 && "Binding already in use");
+ uint32_t count = 1;
VkDescriptorSetLayoutBinding layoutBinding{};
layoutBinding.binding = binding;
layoutBinding.descriptorType = descriptorType;
layoutBinding.descriptorCount = count;
layoutBinding.stageFlags = stageFlags;
+ layoutBinding.pImmutableSamplers = sampler;
bindings[binding] = layoutBinding;
return *this;
}
diff --git a/engine/xe_descriptors.hpp b/engine/xe_descriptors.hpp
index 6e7950e..5efe9b4 100644
--- a/engine/xe_descriptors.hpp
+++ b/engine/xe_descriptors.hpp
@@ -19,7 +19,7 @@ class XeDescriptorSetLayout {
uint32_t binding,
VkDescriptorType descriptorType,
VkShaderStageFlags stageFlags,
- uint32_t count = 1);
+ VkSampler *sampler);
std::unique_ptr<XeDescriptorSetLayout> build() const;
private:
diff --git a/engine/xe_engine.cpp b/engine/xe_engine.cpp
index ea54bb4..6a971c9 100644
--- a/engine/xe_engine.cpp
+++ b/engine/xe_engine.cpp
@@ -1,4 +1,5 @@
#include "xe_engine.hpp"
+#include "xe_image.hpp"
#include <chrono>
namespace xe {
@@ -7,18 +8,15 @@ XeEngine::XeEngine(int width, int height, std::string name) : xeWindow{width, he
xeDevice{xeWindow},
xeRenderer{xeWindow, xeDevice},
xeCamera{} {
- loadDescriptors();
+ loadDescriptorPool();
};
-void XeEngine::loadDescriptors() {
+void XeEngine::loadDescriptorPool() {
xeDescriptorPool = XeDescriptorPool::Builder(xeDevice)
.setMaxSets(XeSwapChain::MAX_FRAMES_IN_FLIGHT)
.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
- .build();
-
- xeDescriptorSetLayout = XeDescriptorSetLayout::Builder(xeDevice)
- .addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT)
+ .addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
.build();
}
@@ -35,6 +33,10 @@ std::shared_ptr<XeModel> XeEngine::loadModelFromData(std::vector<XeModel::Vertex
return std::make_shared<XeModel>(xeDevice, builder);
}
+std::shared_ptr<XeImage> XeEngine::loadImage(const std::string &filename) {
+ return std::make_shared<XeImage>(xeDevice, filename);
+}
+
bool XeEngine::poll() {
glfwPollEvents();
auto newTime = std::chrono::high_resolution_clock::now();
diff --git a/engine/xe_engine.hpp b/engine/xe_engine.hpp
index d3862d4..5731b50 100644
--- a/engine/xe_engine.hpp
+++ b/engine/xe_engine.hpp
@@ -5,8 +5,9 @@
#include "xe_renderer.hpp"
#include "xe_camera.hpp"
#include "xe_descriptors.hpp"
-#include <chrono>
+#include "xe_image.hpp"
+#include <chrono>
#include <string>
namespace xe {
@@ -26,7 +27,8 @@ class XeEngine {
std::shared_ptr<XeModel> loadModelFromFile(const std::string &filename);
std::shared_ptr<XeModel> loadModelFromData(std::vector<XeModel::Vertex> vertices, std::vector<uint32_t> indices);
-
+ std::shared_ptr<XeImage> loadImage(const std::string &filename);
+
bool beginFrame() { return xeRenderer.beginFrame(); }
void endFrame() { xeRenderer.endFrame(); }
void close() { vkDeviceWaitIdle(xeDevice.device()); }
@@ -36,7 +38,7 @@ class XeEngine {
private:
- void loadDescriptors();
+ void loadDescriptorPool();
XeWindow xeWindow;
XeDevice xeDevice;
@@ -49,7 +51,6 @@ class XeEngine {
float FOV = 50.f;
std::unique_ptr<XeDescriptorPool> xeDescriptorPool;
- std::unique_ptr<XeDescriptorSetLayout> xeDescriptorSetLayout;
friend class XeRenderSystem;
};
diff --git a/engine/xe_image.cpp b/engine/xe_image.cpp
new file mode 100644
index 0000000..c7b1488
--- /dev/null
+++ b/engine/xe_image.cpp
@@ -0,0 +1,166 @@
+#include "xe_image.hpp"
+
+#include <vulkan/vulkan.h>
+#include <stdexcept>
+#include <memory>
+#include <cstring>
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+namespace xe {
+
+XeImage::XeImage(XeDevice &xeDevice, const std::string &filename) : xeDevice{xeDevice} {
+ createTextureImage(filename);
+}
+
+XeImage::~XeImage() {
+ vkDestroyImage(xeDevice.device(), textureImage, nullptr);
+ vkFreeMemory(xeDevice.device(), textureImageMemory, nullptr);
+}
+
+void XeImage::createTextureImage(const std::string &filename) {
+ int texWidth, texHeight, texChannels;
+ stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
+ VkDeviceSize imageSize = texWidth * texHeight * 4;
+
+ if (!pixels) {
+ throw std::runtime_error("failed to load texture: " + filename);
+ }
+
+ VkBuffer stagingBuffer;
+ VkDeviceMemory stagingBufferMemory;
+
+ xeDevice.createBuffer(
+ imageSize,
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ stagingBuffer,
+ stagingBufferMemory
+ );
+
+ void* data;
+ vkMapMemory(xeDevice.device(), stagingBufferMemory, 0, imageSize, 0, &data);
+ memcpy(data, pixels, static_cast<size_t>(imageSize));
+ vkUnmapMemory(xeDevice.device(), stagingBufferMemory);
+
+ stbi_image_free(pixels);
+
+ createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
+
+ transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
+ transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ vkDestroyBuffer(xeDevice.device(), stagingBuffer, nullptr);
+ vkFreeMemory(xeDevice.device(), stagingBufferMemory, nullptr);
+
+}
+
+void XeImage::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
+
+ VkImageCreateInfo imageInfo{};
+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageInfo.extent.width = width;
+ imageInfo.extent.height = height;
+ imageInfo.extent.depth = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.arrayLayers = 1;
+ imageInfo.format = format;
+ imageInfo.tiling = tiling;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ imageInfo.usage = usage;
+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ if (vkCreateImage(xeDevice.device(), &imageInfo, nullptr, &image) != VK_SUCCESS) {
+ throw std::runtime_error("failed to create image!");
+ }
+
+ VkMemoryRequirements memRequirements;
+ vkGetImageMemoryRequirements(xeDevice.device(), image, &memRequirements);
+
+ VkMemoryAllocateInfo allocInfo{};
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memRequirements.size;
+ allocInfo.memoryTypeIndex = xeDevice.findMemoryType(memRequirements.memoryTypeBits, properties);
+
+ if (vkAllocateMemory(xeDevice.device(), &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
+ throw std::runtime_error("failed to allocate image memory!");
+ }
+
+ vkBindImageMemory(xeDevice.device(), image, imageMemory, 0);
+}
+
+void XeImage::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
+ VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands();
+
+ 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 {
+ throw std::invalid_argument("unsupported layout transition!");
+ }
+
+ vkCmdPipelineBarrier(
+ commandBuffer,
+ sourceStage, destinationStage,
+ 0,
+ 0, nullptr,
+ 0, nullptr,
+ 1, &barrier
+ );
+
+ xeDevice.endSingleTimeCommands(commandBuffer);
+ }
+
+ void XeImage::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
+ VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands();
+
+ VkBufferImageCopy region{};
+ region.bufferOffset = 0;
+ 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(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+
+ xeDevice.endSingleTimeCommands(commandBuffer);
+ }
+
+} \ No newline at end of file
diff --git a/engine/xe_image.hpp b/engine/xe_image.hpp
new file mode 100644
index 0000000..c3ffe4f
--- /dev/null
+++ b/engine/xe_image.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "xe_device.hpp"
+
+#include <string>
+
+namespace xe {
+
+class XeImage {
+
+ public:
+
+ XeImage(XeDevice &xeDevice, const std::string &filename);
+ ~XeImage();
+
+ XeImage(const XeImage&) = delete;
+ XeImage operator=(const XeImage&) = delete;
+
+ private:
+
+ void createTextureImage(const std::string &filename);
+ void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
+ void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
+ void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
+
+ XeDevice &xeDevice;
+
+ VkImage textureImage;
+ VkDeviceMemory textureImageMemory;
+
+ friend class XeRenderSystem;
+
+};
+
+}
diff --git a/engine/xe_render_system.cpp b/engine/xe_render_system.cpp
index e713884..80f76af 100644
--- a/engine/xe_render_system.cpp
+++ b/engine/xe_render_system.cpp
@@ -21,19 +21,69 @@ XeRenderSystem::XeRenderSystem(
std::string vert,
std::string frag,
uint32_t pushCunstantDataSize,
- uint32_t uniformBufferDataSize)
- : xeDevice{xeEngine.xeDevice}, xeRenderer{xeEngine.xeRenderer} {
- createUniformBuffers(*xeEngine.xeDescriptorPool, *xeEngine.xeDescriptorSetLayout, uniformBufferDataSize);
- createPipelineLayout(*xeEngine.xeDescriptorSetLayout, pushCunstantDataSize, uniformBufferDataSize);
+ uint32_t uniformBufferDataSize,
+ XeImage *image
+) : xeDevice{xeEngine.xeDevice},
+ xeRenderer{xeEngine.xeRenderer},
+ pushCunstantDataSize{pushCunstantDataSize},
+ uniformBufferDataSize{uniformBufferDataSize},
+ textureSamplerBinding{image != nullptr} {
+ createDescriptorSetLayout();
+ createUniformBuffers();
+ createTextureImageView(image);
+ createDescriptorSets(*xeEngine.xeDescriptorPool);
+ createPipelineLayout();
createPipeline(xeRenderer.getSwapChainRenderPass(), vert, frag);
}
XeRenderSystem::~XeRenderSystem() {
vkDestroyPipelineLayout(xeDevice.device(), pipelineLayout, nullptr);
+ if ( textureSamplerBinding ) {
+ vkDestroySampler(xeDevice.device(), textureSampler, nullptr);
+ vkDestroyImageView(xeDevice.device(), textureImageView, nullptr);
+ }
};
-void XeRenderSystem::createUniformBuffers(XeDescriptorPool &xeDescriptorPool, XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t uniformBufferDataSize) {
+void XeRenderSystem::createDescriptorSetLayout() {
+ XeDescriptorSetLayout::Builder builder{xeDevice};
+ int binding = 0;
+
+ if (uniformBufferDataSize > 0) {
+ builder.addBinding(binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, nullptr);
+ binding += 1;
+ }
+ if (textureSamplerBinding) {
+
+ 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_REPEAT;
+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ samplerInfo.anisotropyEnable = VK_FALSE;
+ 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;
+ samplerInfo.minLod = 0.0f;
+ samplerInfo.maxLod = 0.0f;
+
+ if (vkCreateSampler(xeDevice.device(), &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {
+ throw std::runtime_error("failed to create texture sampler!");
+ }
+
+ builder.addBinding(binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &textureSampler);
+ binding += 1;
+ }
+
+ xeDescriptorSetLayout = builder.build();
+}
+
+void XeRenderSystem::createUniformBuffers() {
if(uniformBufferDataSize == 0) return;
uboBuffers = std::vector<std::unique_ptr<XeBuffer>>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
@@ -42,22 +92,65 @@ void XeRenderSystem::createUniformBuffers(XeDescriptorPool &xeDescriptorPool, Xe
xeDevice,
uniformBufferDataSize,
XeSwapChain::MAX_FRAMES_IN_FLIGHT,
+
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
uboBuffers[i]->map();
}
+}
+
+void XeRenderSystem::createTextureImageView(XeImage *image) {
+
+ if (!textureSamplerBinding) {
+ return;
+ }
+
+ VkImageViewCreateInfo viewInfo{};
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = image->textureImage;
+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+ 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(xeDevice.device(), &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
+ throw std::runtime_error("failed to create texture image view!");
+ }
+}
+
+void XeRenderSystem::createDescriptorSets(XeDescriptorPool &xeDescriptorPool) {
+
descriptorSets = std::vector<VkDescriptorSet>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
for (int i = 0; i < descriptorSets.size(); i++) {
auto bufferInfo = uboBuffers[i]->descriptorInfo();
- XeDescriptorWriter(xeDescriptorSetLayout, xeDescriptorPool)
- .writeBuffer(0, &bufferInfo)
- .build(descriptorSets[i]);
+ XeDescriptorWriter writer{*xeDescriptorSetLayout, xeDescriptorPool};
+
+ int binding = 0;
+
+ if (uniformBufferDataSize > 0) {
+ writer.writeBuffer(binding, &bufferInfo);
+ binding += 1;
+ }
+
+ if (textureSamplerBinding) {
+ VkDescriptorImageInfo imageInfo{};
+ imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ imageInfo.imageView = textureImageView;
+ imageInfo.sampler = textureSampler;
+ writer.writeImage(binding, &imageInfo);
+ binding += 1;
+ }
+ writer.build(descriptorSets[i]);
}
+
}
-void XeRenderSystem::createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t pushCunstantDataSize, uint32_t uniformBufferDataSize) {
+void XeRenderSystem::createPipelineLayout() {
VkPushConstantRange pushConstantRange;
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
@@ -75,12 +168,13 @@ void XeRenderSystem::createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSet
pipelineLayoutInfo.pPushConstantRanges = nullptr;
}
- std::vector<VkDescriptorSetLayout> descriptorSetLayouts{xeDescriptorSetLayout.getDescriptorSetLayout()};
+ std::vector<VkDescriptorSetLayout> descriptorSetLayouts{xeDescriptorSetLayout->getDescriptorSetLayout()};
if (uniformBufferDataSize > 0) {
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size());
pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
} else {
+
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.pSetLayouts = nullptr;
}
@@ -107,13 +201,11 @@ void XeRenderSystem::createPipeline(VkRenderPass renderPass, std::string vert, s
);
}
-void XeRenderSystem::loadPushConstant(void *pushConstantData, uint32_t pushConstantSize) {
- if(!boundPipeline) {
- xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
- xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
- boundPipeline = true;
- }
- if(!boundDescriptor) {
+void XeRenderSystem::start() {
+ xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
+ xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
+ if(descriptorSets.size() > 0) {
+
vkCmdBindDescriptorSets(
xeRenderer.getCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -123,28 +215,29 @@ void XeRenderSystem::loadPushConstant(void *pushConstantData, uint32_t pushConst
&descriptorSets[xeRenderer.getFrameIndex()],
0,
nullptr);
- boundDescriptor = true;
+
}
+}
+
+void XeRenderSystem::loadPushConstant(void *pushConstantData) {
vkCmdPushConstants(
xeRenderer.getCurrentCommandBuffer(),
pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0,
- pushConstantSize,
+ pushCunstantDataSize,
pushConstantData);
}
-void XeRenderSystem::loadUniformObject(void *uniformBufferData, uint32_t uniformBufferSize) {
+void XeRenderSystem::loadUniformObject(void *uniformBufferData) {
uboBuffers[xeRenderer.getFrameIndex()]->writeToBuffer(uniformBufferData);
- uboBuffers[xeRenderer.getFrameIndex()]->flush();
+}
+
+void XeRenderSystem::loadTexture(XeImage *image) {
+ // createTextureImageView(image);
}
void XeRenderSystem::render(XeGameObject &gameObject) {
- if(!boundPipeline){
- xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
- xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
- boundPipeline = true;
- }
gameObject.model->bind(xeRenderer.getCurrentCommandBuffer());
gameObject.model->draw(xeRenderer.getCurrentCommandBuffer());
@@ -152,8 +245,6 @@ void XeRenderSystem::render(XeGameObject &gameObject) {
}
void XeRenderSystem::stop() {
- boundPipeline = false;
- boundDescriptor = false;
xeRenderer.endSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
}
diff --git a/engine/xe_render_system.hpp b/engine/xe_render_system.hpp
index fa56fdd..fbf10fc 100644
--- a/engine/xe_render_system.hpp
+++ b/engine/xe_render_system.hpp
@@ -7,6 +7,7 @@
#include "xe_descriptors.hpp"
#include "xe_renderer.hpp"
#include "xe_engine.hpp"
+#include "xe_image.hpp"
#include <memory>
@@ -20,7 +21,8 @@ class XeRenderSystem {
std::string vert,
std::string frag,
uint32_t pushCunstantDataSize,
- uint32_t uniformBufferDataSize
+ uint32_t uniformBufferDataSize,
+ XeImage *image
);
~XeRenderSystem();
@@ -28,20 +30,29 @@ class XeRenderSystem {
XeRenderSystem(const XeRenderSystem &) = delete;
XeRenderSystem operator=(const XeRenderSystem &) = delete;
- void loadPushConstant(void *pushConstantData, uint32_t pushConstantSize);
- void loadUniformObject(void *uniformBufferData, uint32_t uniformBufferSize);
+ void start();
+ void loadPushConstant(void *pushConstantData);
+ void loadUniformObject(void *uniformBufferData);
+ void loadTexture(XeImage *image);
void render(XeGameObject &gameObject);
void stop();
private:
- void createUniformBuffers(XeDescriptorPool &xeDescriptorPool, XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t uniformBufferDataSize);
- void createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t pushCunstantDataSize, uint32_t uniformBufferDataSize);
+ void createDescriptorSetLayout();
+ void createUniformBuffers();
+ void createTextureImageView(XeImage *image);
+ void createDescriptorSets(XeDescriptorPool &xeDescriptorPool);
+ void createPipelineLayout();
void createPipeline(VkRenderPass renderPass, std::string vert, std::string frag);
bool boundPipeline{false};
bool boundDescriptor{false};
+ uint32_t uniformBufferDataSize;
+ uint32_t pushCunstantDataSize;
+ bool textureSamplerBinding;
+
XeDevice& xeDevice;
XeRenderer& xeRenderer;
@@ -49,7 +60,11 @@ class XeRenderSystem {
std::vector<std::unique_ptr<XeBuffer>> uboBuffers;
std::vector<VkDescriptorSet> descriptorSets;
+ VkSampler textureSampler;
+ VkImageView textureImageView;
+
VkPipelineLayout pipelineLayout;
+ std::unique_ptr<XeDescriptorSetLayout> xeDescriptorSetLayout;
};
diff --git a/engine/xe_swap_chain.hpp b/engine/xe_swap_chain.hpp
index 50aa03f..c0299a3 100755
--- a/engine/xe_swap_chain.hpp
+++ b/engine/xe_swap_chain.hpp
@@ -13,7 +13,7 @@ namespace xe {
class XeSwapChain {
public:
- static constexpr int MAX_FRAMES_IN_FLIGHT = 2;
+ static constexpr int MAX_FRAMES_IN_FLIGHT = 3;
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent);
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent, std::shared_ptr<XeSwapChain> previous);
diff --git a/lib/stb b/lib/stb
new file mode 160000
+Subproject 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d5
diff --git a/res/image/scaly.png b/res/image/scaly.png
new file mode 100644
index 0000000..cefdd5f
--- /dev/null
+++ b/res/image/scaly.png
Binary files differ
diff --git a/res/image/texture.png b/res/image/texture.png
new file mode 100644
index 0000000..e1db6c1
--- /dev/null
+++ b/res/image/texture.png
Binary files differ
diff --git a/res/shaders/simple_shader.frag b/res/shaders/simple_shader.frag
index b11a5a8..4eaaafc 100755
--- a/res/shaders/simple_shader.frag
+++ b/res/shaders/simple_shader.frag
@@ -1,19 +1,22 @@
#version 450
layout (location = 0) in vec3 fragColor;
+layout (location = 1) in vec2 fragUv;
layout (location = 0) out vec4 outColor;
-layout(set = 0, binding = 0) uniform GlobalUbo {
+layout (binding = 0) uniform GlobalUbo {
mat4 projectionViewMatrix;
vec3 directionToLight;
} ubo;
+layout (binding = 1) uniform sampler2D texSampler;
+
layout(push_constant) uniform Push {
mat4 transform;
mat4 normalMatrix;
} push;
void main() {
- outColor = vec4(fragColor, 1.0);
+ outColor = mix(texture(texSampler, fragUv), vec4(fragColor, 1.0), .5);
} \ No newline at end of file
diff --git a/res/shaders/simple_shader.frag.spv b/res/shaders/simple_shader.frag.spv
index ff80cc6..a6afbfe 100644
--- a/res/shaders/simple_shader.frag.spv
+++ b/res/shaders/simple_shader.frag.spv
Binary files differ
diff --git a/res/shaders/simple_shader.vert b/res/shaders/simple_shader.vert
index 55b0199..a61fa0b 100755
--- a/res/shaders/simple_shader.vert
+++ b/res/shaders/simple_shader.vert
@@ -1,18 +1,19 @@
#version 450
-layout(location = 0) in vec3 position;
-layout(location = 1) in vec3 color;
-layout(location = 2) in vec3 normal;
-layout(location = 3) in vec2 uv;
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec3 color;
+layout (location = 2) in vec3 normal;
+layout (location = 3) in vec2 uv;
-layout(location = 0) out vec3 fragColor;
+layout (location = 0) out vec3 fragColor;
+layout (location = 1) out vec2 fragUv;
-layout(set = 0, binding = 0) uniform GlobalUbo {
+layout (binding = 0) uniform GlobalUbo {
mat4 projectionViewMatrix;
vec3 directionToLight;
} ubo;
-layout(push_constant) uniform Push {
+layout (push_constant) uniform Push {
mat4 modelMatrix;
mat4 normalMatrix;
} push;
@@ -27,4 +28,5 @@ void main() {
float lightIntensity = AMBIENT + max(dot(normalWorldSpace, ubo.directionToLight), 0);
fragColor = lightIntensity * vec3(1/position.y,position.y,clamp(sin(position.x - position.z), 0, 1));
+ fragUv = uv;
} \ No newline at end of file
diff --git a/res/shaders/simple_shader.vert.spv b/res/shaders/simple_shader.vert.spv
index bba7f70..84c0f48 100644
--- a/res/shaders/simple_shader.vert.spv
+++ b/res/shaders/simple_shader.vert.spv
Binary files differ
diff --git a/src/first_app.cpp b/src/first_app.cpp
index cff92db..40a5681 100755
--- a/src/first_app.cpp
+++ b/src/first_app.cpp
@@ -14,6 +14,8 @@
#include <glm/gtc/constants.hpp>
#include <array>
+#include <string>
+
namespace app {
FirstApp::FirstApp() : xeEngine{WIDTH, HEIGHT, "Hello, Vulkan!"} {
@@ -24,7 +26,12 @@ FirstApp::~FirstApp() {}
void FirstApp::run() {
- SimpleRenderer renderer{xeEngine};
+ const std::string s = "res/image/texture.png";
+
+ std::shared_ptr<xe::XeImage> image = xeEngine.loadImage("res/image/texture.png");
+ std::shared_ptr<xe::XeImage> image2 = xeEngine.loadImage("res/image/scaly.png");
+
+ SimpleRenderer renderer{xeEngine, image.get()};
auto viewerObject = xe::XeGameObject::createGameObject();
viewerObject.transform.translation = {-7.f, 3.f, -7.f};
@@ -39,7 +46,7 @@ void FirstApp::run() {
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
if(xeEngine.beginFrame()) {
- renderer.render(gameObjects, xeEngine.getCamera());
+ renderer.render(gameObjects, xeEngine.getCamera(), image2.get());
xeEngine.endFrame();
}
}
diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp
index b4c115a..548b77d 100644
--- a/src/simple_renderer.cpp
+++ b/src/simple_renderer.cpp
@@ -2,20 +2,23 @@
namespace app {
-SimpleRenderer::SimpleRenderer(xe::XeEngine &xeEngine)
- : xeRenderSystem{xeEngine, "res/shaders/simple_shader.vert.spv", "res/shaders/simple_shader.frag.spv", sizeof(PushConstant), sizeof(UniformBuffer)} {};
+SimpleRenderer::SimpleRenderer(xe::XeEngine &xeEngine, xe::XeImage *xeImage)
+ : xeRenderSystem{xeEngine, "res/shaders/simple_shader.vert.spv", "res/shaders/simple_shader.frag.spv", sizeof(PushConstant), sizeof(UniformBuffer), xeImage} {};
-void SimpleRenderer::render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera) {
+void SimpleRenderer::render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera, xe::XeImage *xeImage) {
+
+ xeRenderSystem.start();
UniformBuffer ubo{};
ubo.projectionView = xeCamera.getProjection() * xeCamera.getView();
- xeRenderSystem.loadUniformObject(&ubo, sizeof(ubo));
+ xeRenderSystem.loadUniformObject(&ubo);
+ xeRenderSystem.loadTexture(xeImage);
for(auto &obj : gameObjects) {
PushConstant pc{};
pc.modelMatrix = obj.transform.mat4();
pc.normalMatrix = obj.transform.normalMatrix();
- xeRenderSystem.loadPushConstant(&pc, sizeof(pc));
+ xeRenderSystem.loadPushConstant(&pc);
xeRenderSystem.render(obj);
}
diff --git a/src/simple_renderer.hpp b/src/simple_renderer.hpp
index 22ba0b4..20e3997 100644
--- a/src/simple_renderer.hpp
+++ b/src/simple_renderer.hpp
@@ -19,14 +19,14 @@ class SimpleRenderer {
public:
- SimpleRenderer(xe::XeEngine &xeEngine);
+ SimpleRenderer(xe::XeEngine &xeEngine, xe::XeImage *xeImage);
~SimpleRenderer() {};
SimpleRenderer(const SimpleRenderer&) = delete;
SimpleRenderer operator=(const SimpleRenderer&) = delete;
- void render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera);
+ void render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera, xe::XeImage *xeImage);
private:
xe::XeRenderSystem xeRenderSystem;