Texture creation and binding works!
This commit is contained in:
parent
4012425d35
commit
ef1bceb388
@ -2,7 +2,7 @@
|
||||
#include <Memory/Memory.hpp>
|
||||
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::MemoryPropertyFlags memory_flags) : dev(dev), image(_image) {
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::MemoryPropertyFlags memory_flags, vk::Extent3D& extent) : dev(dev), image(_image) {
|
||||
|
||||
auto reqs = dev.getImageMemoryRequirements(image);
|
||||
|
||||
@ -12,13 +12,14 @@ Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::
|
||||
};
|
||||
memory = dev.allocateMemory(alloc);
|
||||
dev.bindImageMemory(image, memory, 0);
|
||||
this->extent = extent;
|
||||
Log::debug("Image memory: %p\n", memory);
|
||||
|
||||
}
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::ImageCreateInfo info, vk::MemoryPropertyFlags memory_flags) : dev(dev) {
|
||||
image = dev.createImage(info);
|
||||
|
||||
*this = Image(phys_dev, dev, image, memory_flags);
|
||||
*this = Image(phys_dev, dev, image, memory_flags, info.extent);
|
||||
}
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Extent3D extent, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memory_flags) : dev(dev) {
|
||||
|
||||
@ -12,9 +12,13 @@ struct Image {
|
||||
vk::Image image;
|
||||
vk::DeviceMemory memory;
|
||||
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image image, vk::MemoryPropertyFlags memory_flags);
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image image, vk::MemoryPropertyFlags memory_flags, vk::Extent3D& extent);
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::ImageCreateInfo info, vk::MemoryPropertyFlags memory_flags);
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Extent3D extent, vk::Format format, vk::ImageTiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memory_flags);
|
||||
|
||||
operator vk::Image&() {
|
||||
return image;
|
||||
}
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
@ -4,5 +4,6 @@
|
||||
- Add more comments
|
||||
## Long Term Improvements
|
||||
- ~~Properly query surface to find supported formats for surfaces~~
|
||||
- Fix all this cleanup vs destructor NONSENSE (inconsistency)
|
||||
- Add pipeline caching
|
||||
- Make more robust solution to window minimization (flushing out Input system should provide candidates)
|
||||
@ -8,6 +8,7 @@
|
||||
#include <util/log.hpp>
|
||||
|
||||
CommandBuffer::CommandBuffer(vk::Device dev, u32 queue_family) {
|
||||
Log::debug("Command Buffer created\n");
|
||||
/* (For now) allow command buffers to be individually recycled */
|
||||
auto pool_info = vk::CommandPoolCreateInfo {
|
||||
.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer
|
||||
@ -49,7 +50,7 @@ void CommandBuffer::copy(Buffer& src, Image& dst, vk::ImageLayout layout) {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = { 0, 0, 0 },
|
||||
.imageExtent = dst.extent,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <Renderer/RenderPass.hpp>
|
||||
#include <Renderer/UniformBuffer.hpp>
|
||||
#include <Renderer/VertexBuffer.hpp>
|
||||
#include <Resources/Texture.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
@ -188,6 +189,22 @@ void GraphicsPipeline::update(uint32_t binding, const UniformBuffer& uni) {
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
void GraphicsPipeline::update(uint32_t binding, const Texture& tex) {
|
||||
auto tex_info = vk::DescriptorImageInfo {
|
||||
.sampler = tex.sampler,
|
||||
.imageView = tex.view,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
};
|
||||
|
||||
dev.updateDescriptorSets(vk::WriteDescriptorSet {
|
||||
.dstSet = desc_set,
|
||||
.dstBinding = binding,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &tex_info,
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
GraphicsPipeline::~GraphicsPipeline() {
|
||||
dev.destroyDescriptorSetLayout(desc_layout);
|
||||
dev.destroyPipelineLayout(layout);
|
||||
|
||||
@ -7,6 +7,7 @@ struct Shader;
|
||||
struct UniformBuffer;
|
||||
struct VertexBuffer;
|
||||
struct RenderPass;
|
||||
struct Texture;
|
||||
|
||||
struct GraphicsPipeline {
|
||||
GraphicsPipeline(vk::Device dev, const std::vector<Shader>& shaders,
|
||||
@ -26,6 +27,7 @@ struct GraphicsPipeline {
|
||||
|
||||
/* create overload for every type of object we need to update */
|
||||
void update(uint32_t binding, const UniformBuffer& uni);
|
||||
void update(uint32_t binding, const Texture& tex);
|
||||
|
||||
~GraphicsPipeline();
|
||||
};
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#include <Renderer/Renderer.hpp>
|
||||
#include <Resources/Texture.hpp>
|
||||
|
||||
#include <Window/Window.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
@ -16,12 +18,12 @@
|
||||
|
||||
|
||||
const static std::vector<Vertex> triangle = {
|
||||
{{ 1.0, -1.0, 1.0 }, { 1.0, 0.0 }},
|
||||
{{ 1.0, 1.0, 1.0 }, { 1.0, 1.0 }},
|
||||
{{-1.0, 1.0, 1.0 }, { 0.0, 1.0 }},
|
||||
{{-1.0, 1.0, 1.0 }, { 0.0, 1.0 }},
|
||||
{{-1.0, -1.0, 1.0 }, { 0.0, 0.0 }},
|
||||
{{ 1.0, -1.0, 1.0 }, { 1.0, 0.0 }},
|
||||
{{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }},
|
||||
{{ 1.0, 1.0, -1.0 }, { 1.0, 1.0 }},
|
||||
{{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }},
|
||||
{{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }},
|
||||
{{-1.0, -1.0, -1.0 }, { 0.0, 0.0 }},
|
||||
{{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }},
|
||||
};
|
||||
|
||||
using namespace std::string_literals;
|
||||
@ -101,7 +103,7 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
if (discrete_idx == -1)
|
||||
discrete_idx = 0;
|
||||
|
||||
auto& phys_dev = phys_devs[discrete_idx];
|
||||
phys_dev = phys_devs[discrete_idx];
|
||||
Log::info("Selected device: \"%s\" (#%zu)\n", phys_dev.getProperties().deviceName.data(), discrete_idx);
|
||||
|
||||
/* find queue family */
|
||||
@ -184,23 +186,65 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
|
||||
vertex_buffer->upload(triangle);
|
||||
|
||||
textures = createTextures({
|
||||
"assets/textures/oil.jpg",
|
||||
});
|
||||
|
||||
std::vector<Shader> shaders = {
|
||||
{ dev, "assets/shaders/basic.vert.spv", vk::ShaderStageFlagBits::eVertex },
|
||||
{ dev, "assets/shaders/trace.frag.spv", vk::ShaderStageFlagBits::eFragment },
|
||||
{ dev, "assets/shaders/basic.frag.spv", vk::ShaderStageFlagBits::eFragment },
|
||||
};
|
||||
|
||||
std::vector<vk::DescriptorSetLayoutBinding> bindings = {
|
||||
uniform_buffer->binding(0),
|
||||
textures[0].binding(1),
|
||||
};
|
||||
|
||||
pipeline = std::make_unique<GraphicsPipeline>(dev, shaders, swapchain->extent, *render_pass, bindings, *vertex_buffer);
|
||||
|
||||
pipeline->update(0, *uniform_buffer);
|
||||
pipeline->update(1, textures[0]);
|
||||
|
||||
shaders[0].cleanup();
|
||||
shaders[1].cleanup();
|
||||
}
|
||||
|
||||
std::vector<Texture> Renderer::createTextures(const std::vector<std::string>& names) {
|
||||
std::vector<Texture> ret;
|
||||
|
||||
CommandBuffer texture_cmd(dev, queue_family);
|
||||
|
||||
texture_cmd.begin();
|
||||
|
||||
for (const auto& name : names) {
|
||||
ret.push_back({phys_dev, dev, texture_cmd, "assets/textures/oil.jpg"});
|
||||
}
|
||||
|
||||
texture_cmd.end();
|
||||
|
||||
auto texture_creation_fence = dev.createFence(vk::FenceCreateInfo {});
|
||||
dev.resetFences(texture_creation_fence);
|
||||
|
||||
queue.submit(vk::SubmitInfo {
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = texture_cmd,
|
||||
}, texture_creation_fence);
|
||||
|
||||
if (dev.waitForFences(texture_creation_fence, vk::True, UINT64_MAX) != vk::Result::eSuccess) {
|
||||
Log::error("Failed to create textures\n");
|
||||
}
|
||||
|
||||
dev.destroyFence(texture_creation_fence);
|
||||
|
||||
for (auto& tex : ret) {
|
||||
tex.finishCreation();
|
||||
}
|
||||
|
||||
texture_cmd.cleanup(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Renderer::draw() {
|
||||
|
||||
if(dev.waitForFences(render_fence, true, UINT64_MAX) != vk::Result::eSuccess) {
|
||||
@ -270,7 +314,7 @@ void Renderer::draw() {
|
||||
const auto p = glm::perspective(glm::radians(90.0f), static_cast<float>(sz.width) / static_cast<float>(sz.height), 0.01f, 50.0f);
|
||||
|
||||
uniform_buffer->upload(UniformData{
|
||||
//.mvp = p * glm::rotate(glm::mat4(1.0), glm::radians(static_cast<float>(frame)), glm::vec3(1.0, 1.0, 1.0)),
|
||||
.mvp = p * glm::rotate(glm::mat4(1.0), glm::radians(static_cast<float>(frame)), glm::vec3(1.0, 1.0, 1.0)),
|
||||
.time = static_cast<float>(frame) * 0.0167f,
|
||||
.aspect_ratio = static_cast<float>(sz.width)/static_cast<float>(sz.height),
|
||||
});
|
||||
@ -331,6 +375,10 @@ Renderer::~Renderer() {
|
||||
vertex_buffer.reset();
|
||||
pipeline.reset();
|
||||
|
||||
for (auto& tex : textures) {
|
||||
tex.cleanup();
|
||||
}
|
||||
|
||||
swapchain.reset();
|
||||
|
||||
dev.destroySemaphore(image_wait_semaphore);
|
||||
|
||||
@ -12,18 +12,22 @@
|
||||
struct Window;
|
||||
struct UniformBuffer;
|
||||
struct VertexBuffer;
|
||||
struct Texture;
|
||||
|
||||
/* Contains all of the Vulkan objects involved in rendering the scene */
|
||||
struct Renderer {
|
||||
Renderer(Window& win);
|
||||
~Renderer();
|
||||
|
||||
std::vector<Texture> createTextures(const std::vector<std::string>& names);
|
||||
|
||||
void draw();
|
||||
void present();
|
||||
|
||||
Window& win;
|
||||
|
||||
vk::Instance instance;
|
||||
vk::PhysicalDevice phys_dev;
|
||||
vk::Device dev;
|
||||
|
||||
vk::Fence render_fence;
|
||||
@ -42,6 +46,8 @@ struct Renderer {
|
||||
std::unique_ptr<VertexBuffer> vertex_buffer;
|
||||
std::unique_ptr<UniformBuffer> uniform_buffer;
|
||||
|
||||
std::vector<Texture> textures;
|
||||
|
||||
uint32_t current_image_idx;
|
||||
uint64_t frame = 0;
|
||||
};
|
||||
|
||||
@ -5,32 +5,103 @@
|
||||
#include <Renderer/CommandBuffer.hpp>
|
||||
|
||||
#include <util/file.hpp>
|
||||
#include <util/log.hpp>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
/* externall synchonized, just writes to a command buffer, you still need to pull the trigger (allows bulk texture image preperation) */
|
||||
Texture::Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer& command_buffer, const std::string& fname) : dev(dev) {
|
||||
Log::debug("Starting texture creation for: %s\n", fname.c_str());
|
||||
|
||||
Texture::Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer command_buffer, const std::string& fname) {
|
||||
int n_channels;
|
||||
vk::Extent3D extent;
|
||||
|
||||
auto image_data = stbi_load(fname.c_str(), reinterpret_cast<int*>(&extent.width), reinterpret_cast<int*>(&extent.height), &n_channels, STBI_rgb_alpha);
|
||||
extent.depth = 1;
|
||||
|
||||
image = std::make_unique<Image>(phys_dev, dev, extent, vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled,
|
||||
image = std::make_unique<Image>(phys_dev, dev, extent, vk::Format::eR8G8B8A8Unorm,
|
||||
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
|
||||
vk::DeviceSize sz = static_cast<vk::DeviceSize>(extent.width * extent.height) * sizeof(uint32_t);
|
||||
|
||||
/* staging buffer to hold image data from the CPU */
|
||||
Buffer staging(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc,
|
||||
staging = std::make_unique<Buffer>(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
|
||||
staging.upload(image_data);
|
||||
staging->upload(image_data);
|
||||
stbi_image_free(image_data);
|
||||
|
||||
command_buffer.copy(staging, *image);
|
||||
/* pipeline memory barrier ensures this doesn't get reordered wrong */
|
||||
|
||||
/* TODO: Finish, also rethink if we want submission to happen internally or externally to the function for creation */
|
||||
auto staging_buffer_trans_barrier = vk::ImageMemoryBarrier {
|
||||
.srcAccessMask = vk::AccessFlagBits(0),
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.image = *image,
|
||||
.subresourceRange = vk::ImageSubresourceRange {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/* transfer optimal --> shader optimal */
|
||||
auto shader_barrier = vk::ImageMemoryBarrier{
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.image = *image,
|
||||
.subresourceRange = vk::ImageSubresourceRange {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits(0), nullptr, nullptr, staging_buffer_trans_barrier);
|
||||
command_buffer.copy(*staging, *image);
|
||||
command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, vk::DependencyFlagBits(0), nullptr, nullptr, shader_barrier);
|
||||
}
|
||||
|
||||
|
||||
void Texture::finishCreation() {
|
||||
view = dev.createImageView(vk::ImageViewCreateInfo {
|
||||
.image = *image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = vk::Format::eR8G8B8A8Unorm,
|
||||
.subresourceRange = vk::ImageSubresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.levelCount = 1,
|
||||
.layerCount = 1,
|
||||
},
|
||||
});
|
||||
|
||||
sampler = dev.createSampler(vk::SamplerCreateInfo {
|
||||
.magFilter = vk::Filter::eLinear,
|
||||
.minFilter = vk::Filter::eLinear,
|
||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||
.addressModeU = vk::SamplerAddressMode::eClampToEdge,
|
||||
.addressModeV = vk::SamplerAddressMode::eClampToEdge,
|
||||
.addressModeW = vk::SamplerAddressMode::eClampToEdge,
|
||||
.mipLodBias = 0.0,
|
||||
.anisotropyEnable = vk::False,
|
||||
.maxAnisotropy = 0.0,
|
||||
.compareEnable = vk::False,
|
||||
.compareOp = vk::CompareOp::eAlways,
|
||||
.minLod = 0.0,
|
||||
.maxLod = 0.0,
|
||||
.borderColor = vk::BorderColor::eIntOpaqueBlack,
|
||||
.unnormalizedCoordinates = vk::False,
|
||||
});
|
||||
}
|
||||
|
||||
void Texture::cleanup() {
|
||||
staging.reset();
|
||||
image->cleanup();
|
||||
dev.destroyImageView(view);
|
||||
dev.destroySampler(sampler);
|
||||
}
|
||||
@ -7,8 +7,31 @@
|
||||
#include <memory>
|
||||
|
||||
struct CommandBuffer;
|
||||
struct Buffer;
|
||||
|
||||
struct Texture {
|
||||
vk::Device dev;
|
||||
std::unique_ptr<Image> image;
|
||||
Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer command_buffer, const std::string& fname);
|
||||
vk::ImageView view;
|
||||
vk::Sampler sampler;
|
||||
|
||||
std::unique_ptr<Buffer> staging;
|
||||
|
||||
Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer& command_buffer, const std::string& fname);
|
||||
|
||||
inline vk::DescriptorSetLayoutBinding binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eAll) {
|
||||
return vk::DescriptorSetLayoutBinding {
|
||||
.binding = binding,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||
.pImmutableSamplers = nullptr,
|
||||
};
|
||||
}
|
||||
|
||||
/* seperates out steps that need to be taken *after* command buffer is submitted */
|
||||
void finishCreation();
|
||||
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
@ -8,6 +8,8 @@ layout (set = 0, binding = 0) uniform Matrices {
|
||||
float time;
|
||||
};
|
||||
|
||||
layout (set = 0, binding = 1) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
FragColor = texture(tex, texCoord);
|
||||
}
|
||||
Binary file not shown.
@ -10,6 +10,6 @@ layout (set = 0, binding = 0) uniform Matrices {
|
||||
};
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aPos, 1.0);
|
||||
gl_Position = mpv*vec4(aPos, 1.0);
|
||||
texCoord = aTexCoord;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
BIN
assets/textures/oil.jpg
Normal file
BIN
assets/textures/oil.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 129 KiB |
@ -42,7 +42,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
ren.draw();
|
||||
ren.present();
|
||||
Log::debug("Frame: %.2lf milliseconds (60fps ~ 16.67)\n", frame_timer.stop());
|
||||
Log::debug("Frame: %.2lf milliseconds (60fps ~ 16.67)\r", frame_timer.stop());
|
||||
}
|
||||
|
||||
} catch (const std::string& e) {
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Log {
|
||||
return static_cast<MessageLevelBit>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
|
||||
}
|
||||
|
||||
static const MessageLevelBit log_mask = ERROR | INFO;
|
||||
static const MessageLevelBit log_mask = ERROR | INFO | DEBUG;
|
||||
|
||||
template<typename ...Args>
|
||||
static void print(MessageLevelBit level, const std::string& fmt, Args... args) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user