feat: 搭建 Vulkan 1.4 渲染器骨架,绘制旋转 3D 立方体
使用 Vulkan 1.4 现代路径初始化引擎骨架: - 用 Shader Object (VK_EXT_shader_object) 替代传统 VkPipeline - 用 Dynamic Rendering 替代 RenderPass/Framebuffer - 用 Synchronization2 管理 barrier 核心模块: - Window:GLFW 封装,GLFW_NO_API 模式,兼容 Wayland - Log:spdlog 封装 - Types:u32/u64/f32 类型别名 Vulkan 后端: - Device:Instance、PhysicalDevice、LogicalDevice、Queue 及 feature 查询 - Swapchain:Image、ImageView、DepthBuffer、Recreate - ShaderManager:SPIR-V 加载与 ShaderEXT 创建 - CommandManager:CommandPool 与主 CommandBuffer - SyncManager:per-frame Fence 与 ImageAvailable semaphore,per-image RenderFinished semaphore,2 frames in flight - MemoryAllocator:内存子分配器,256MB block,persistent mapping - Buffer:VertexBuffer、IndexBuffer、UniformBuffer 封装 - UniformBuffer:每帧上传 MVP 矩阵 - DescriptorManager:DescriptorSetLayout、DescriptorPool、DescriptorSet 及更新 Renderer: - 协调所有子系统 - 绘制每面不同颜色的旋转 3D 立方体 - 启用 depth test,MVP 矩阵由 GLM 计算 构建: - CMake 组织 Engine 静态库与 App 可执行文件 - glfw、glm、spdlog 通过 add_subdirectory 引入
This commit is contained in:
@@ -0,0 +1,464 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/9/20.
|
||||
//
|
||||
|
||||
#include <Engine/Renderer/Renderer.h>
|
||||
#include <Engine/Vulkan/Device.h>
|
||||
#include <Engine/Vulkan/MemoryAllocator.h>
|
||||
#include <Engine/Vulkan/DescriptorManager.h>
|
||||
#include <Engine/Vulkan/ShaderManager.h>
|
||||
#include <Engine/Vulkan/Swapchain.h>
|
||||
#include <Engine/Vulkan/CommandManager.h>
|
||||
#include <Engine/Vulkan/SyncManager.h>
|
||||
#include <Engine/Vulkan/Buffer.h>
|
||||
#include <Engine/Vulkan/UniformBuffer.h>
|
||||
#include <Engine/Core/Window.h>
|
||||
#include <Engine/Core/Log.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace Engine
|
||||
{
|
||||
// 顶点结构:位置 + 颜色
|
||||
struct Vertex
|
||||
{
|
||||
float position[3];
|
||||
float color[3];
|
||||
};
|
||||
|
||||
// Uniform Buffer 结构
|
||||
struct UniformBufferObject
|
||||
{
|
||||
glm::mat4 mvp;
|
||||
};
|
||||
|
||||
Renderer::Renderer(Window& window)
|
||||
: m_Window(window)
|
||||
{
|
||||
// 1. Device
|
||||
m_Device = CreateScope<Device>(window);
|
||||
|
||||
// 2. MemoryAllocator
|
||||
m_Allocator = CreateScope<MemoryAllocator>(*m_Device);
|
||||
|
||||
// 3. DescriptorManager
|
||||
m_DescriptorManager = CreateScope<DescriptorManager>(*m_Device);
|
||||
|
||||
// 4. DescriptorSetLayout(一个 uniform buffer binding)
|
||||
m_DescriptorSetLayout = m_DescriptorManager->CreateUniformBufferLayout(0);
|
||||
|
||||
// 5. PipelineLayout(shader 绑定描述符时用)
|
||||
m_PipelineLayout = m_DescriptorManager->CreatePipelineLayout(m_DescriptorSetLayout);
|
||||
|
||||
// 6. ShaderManager,编译 shader 时传入描述符布局
|
||||
m_ShaderManager = CreateScope<ShaderManager>(*m_Device);
|
||||
|
||||
std::string shaderDir = "shaders/";
|
||||
auto vert = m_ShaderManager->CreateFromFile(
|
||||
shaderDir + "simple_shader.vert.spv",
|
||||
vk::ShaderStageFlagBits::eVertex,
|
||||
m_DescriptorSetLayout);
|
||||
auto frag = m_ShaderManager->CreateFromFile(
|
||||
shaderDir + "simple_shader.frag.spv",
|
||||
vk::ShaderStageFlagBits::eFragment,
|
||||
m_DescriptorSetLayout);
|
||||
|
||||
m_VertShader = vert.Handle;
|
||||
m_FragShader = frag.Handle;
|
||||
|
||||
if (!m_VertShader || !m_FragShader)
|
||||
{
|
||||
ENGINE_FATAL("Failed to create shader objects");
|
||||
}
|
||||
|
||||
// 7. Swapchain
|
||||
m_Swapchain = CreateScope<Swapchain>(*m_Device, *m_Allocator, window);
|
||||
m_Extent = m_Swapchain->GetExtent();
|
||||
m_Format = m_Swapchain->GetFormat();
|
||||
|
||||
// 8. SyncManager
|
||||
m_SyncManager = CreateScope<SyncManager>(*m_Device, kMaxFramesInFlight, m_Swapchain->GetImageCount());
|
||||
|
||||
// 9. CommandManager
|
||||
m_CommandManager = CreateScope<CommandManager>(*m_Device);
|
||||
|
||||
// 10. 顶点缓冲
|
||||
std::vector<Vertex> vertices = {
|
||||
// 前面 (-Z)
|
||||
{{-0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{ 0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{ 0.5f, 0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{-0.5f, 0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
// 后面 (+Z)
|
||||
{{-0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
// 左面 (-X)
|
||||
{{-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
// 右面 (+X)
|
||||
{{ 0.5f, -0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}},
|
||||
{{ 0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 0.0f}},
|
||||
{{ 0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 0.0f}},
|
||||
{{ 0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}},
|
||||
// 上面 (+Y)
|
||||
{{-0.5f, 0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}},
|
||||
{{ 0.5f, 0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}},
|
||||
{{ 0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 1.0f}},
|
||||
// 下面 (-Y)
|
||||
{{-0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 1.0f}},
|
||||
{{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 1.0f}},
|
||||
{{ 0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}},
|
||||
};
|
||||
u64 bufferSize = sizeof(Vertex) * vertices.size();
|
||||
|
||||
|
||||
m_VertexBuffer = CreateScope<Buffer>(
|
||||
*m_Device, *m_Allocator,
|
||||
bufferSize,
|
||||
vk::BufferUsageFlagBits::eVertexBuffer,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
||||
vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
m_VertexBuffer->Upload(vertices.data(), bufferSize);
|
||||
|
||||
|
||||
// 索引缓冲:两个三角形组成一个四边形
|
||||
std::vector<u32> indices = {
|
||||
0, 1, 2, 2, 3, 0, // 前面
|
||||
4, 5, 6, 6, 7, 4, // 后面
|
||||
8, 9,10,10,11, 8, // 左面
|
||||
12,13,14,14,15,12, // 右面
|
||||
16,17,18,18,19,16, // 上面
|
||||
20,21,22,22,23,20, // 下面
|
||||
};
|
||||
u64 indexBufferSize = sizeof(u32) * indices.size();
|
||||
|
||||
|
||||
m_IndexBuffer = CreateScope<Buffer>(
|
||||
*m_Device, *m_Allocator,
|
||||
indexBufferSize,
|
||||
vk::BufferUsageFlagBits::eIndexBuffer,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
||||
vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
m_IndexBuffer->Upload(indices.data(), indexBufferSize);
|
||||
|
||||
|
||||
// 11. Uniform Buffer
|
||||
m_UniformBuffer = CreateScope<UniformBuffer>(
|
||||
*m_Device, *m_Allocator, sizeof(UniformBufferObject));
|
||||
|
||||
// 12. DescriptorSet + 绑定 UniformBuffer
|
||||
m_DescriptorSet = m_DescriptorManager->AllocateDescriptorSet(m_DescriptorSetLayout);
|
||||
m_DescriptorManager->UpdateUniformBuffer(
|
||||
m_DescriptorSet, 0, m_UniformBuffer->Get(), m_UniformBuffer->GetSize());
|
||||
|
||||
// 13. Debug: 记录开始时间,用于旋转
|
||||
m_StartTime = std::chrono::steady_clock::now();
|
||||
|
||||
ENGINE_INFO("Renderer initialized");
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
m_Device->GetDevice().waitIdle();
|
||||
|
||||
if (m_VertShader)
|
||||
{
|
||||
m_Device->GetDevice().destroyShaderEXT(m_VertShader);
|
||||
}
|
||||
if (m_FragShader)
|
||||
{
|
||||
m_Device->GetDevice().destroyShaderEXT(m_FragShader);
|
||||
}
|
||||
|
||||
m_Device->GetDevice().destroyPipelineLayout(m_PipelineLayout);
|
||||
m_Device->GetDevice().destroyDescriptorSetLayout(m_DescriptorSetLayout);
|
||||
}
|
||||
|
||||
|
||||
void Renderer::Render()
|
||||
{
|
||||
u32 frameIndex = m_CurrentFrame;
|
||||
const auto& vkDevice = m_Device->GetDevice();
|
||||
|
||||
// 1. 更新 MVP 矩阵
|
||||
auto currentTime = std::chrono::steady_clock::now();
|
||||
float time = std::chrono::duration<float, std::chrono::seconds::period>(
|
||||
currentTime - m_StartTime).count();
|
||||
|
||||
auto model = glm::rotate(glm::mat4(1.0f),
|
||||
time * glm::radians(90.0f),
|
||||
glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
auto view = glm::lookAt(glm::vec3(0.0f, 0.0f, 2.0f),
|
||||
glm::vec3(0.0f, 0.0f, 0.0f),
|
||||
glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
|
||||
float aspect = static_cast<float>(m_Extent.width) /
|
||||
static_cast<float>(m_Extent.height);
|
||||
|
||||
auto proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 10.0f);
|
||||
proj[1][1] *= -1.0f; // Vulkan Y 翻转
|
||||
|
||||
UniformBufferObject ubo{};
|
||||
ubo.mvp = proj * view * model;
|
||||
|
||||
m_UniformBuffer->Update(&ubo, sizeof(ubo));
|
||||
|
||||
// 等待这一帧上一次完成
|
||||
m_SyncManager->WaitFence(frameIndex);
|
||||
|
||||
// 2. 获取交换链 image
|
||||
u32 imageIndex = 0;
|
||||
try
|
||||
{
|
||||
const auto result = vkDevice.acquireNextImageKHR(
|
||||
m_Swapchain->Get(),
|
||||
std::numeric_limits<u64>::max(),
|
||||
m_SyncManager->GetImageAvailable(frameIndex));
|
||||
|
||||
if (result.result == vk::Result::eErrorOutOfDateKHR)
|
||||
{
|
||||
m_Swapchain->Recreate(m_Window);
|
||||
return; // ← fence 没被 reset,下帧 wait 立即返回
|
||||
}
|
||||
imageIndex = result.value;
|
||||
}
|
||||
catch (const vk::OutOfDateKHRError&)
|
||||
{
|
||||
m_Swapchain->Recreate(m_Window);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. acquire 成功, reset fence
|
||||
m_SyncManager->ResetFence(frameIndex);
|
||||
|
||||
// 4. 录制命令
|
||||
auto cmd = m_CommandManager->BeginFrame();
|
||||
|
||||
TransitionImageLayout(cmd, m_Swapchain->GetImages()[imageIndex],
|
||||
vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eColorAttachmentOptimal);
|
||||
|
||||
// 深度转换
|
||||
vk::ImageMemoryBarrier2 depthBarrier;
|
||||
depthBarrier.setSrcStageMask(vk::PipelineStageFlagBits2::eEarlyFragmentTests)
|
||||
.setSrcAccessMask(vk::AccessFlagBits2::eDepthStencilAttachmentWrite)
|
||||
.setDstStageMask(vk::PipelineStageFlagBits2::eEarlyFragmentTests)
|
||||
.setDstAccessMask(vk::AccessFlagBits2::eDepthStencilAttachmentWrite)
|
||||
.setOldLayout(vk::ImageLayout::eUndefined)
|
||||
.setNewLayout(vk::ImageLayout::eDepthAttachmentOptimal)
|
||||
.setImage(m_Swapchain->GetDepthImage())
|
||||
.setSubresourceRange({
|
||||
vk::ImageAspectFlagBits::eDepth,
|
||||
0, 1, 0, 1
|
||||
});
|
||||
|
||||
vk::DependencyInfo depthDep;
|
||||
depthDep.setImageMemoryBarriers(depthBarrier);
|
||||
cmd.pipelineBarrier2(depthDep);
|
||||
|
||||
RecordCommands(cmd, imageIndex);
|
||||
|
||||
TransitionImageLayout(cmd, m_Swapchain->GetImages()[imageIndex],
|
||||
vk::ImageLayout::eColorAttachmentOptimal,
|
||||
vk::ImageLayout::ePresentSrcKHR);
|
||||
|
||||
m_CommandManager->EndFrame();
|
||||
|
||||
// 5. 提交
|
||||
std::array<vk::PipelineStageFlags, 1> waitStages = {
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput
|
||||
};
|
||||
std::array<vk::Semaphore, 1> waitSemaphores = {
|
||||
m_SyncManager->GetImageAvailable(frameIndex)
|
||||
};
|
||||
std::array<vk::Semaphore, 1> signalSemaphores = {
|
||||
m_SyncManager->GetRenderFinished(imageIndex)
|
||||
};
|
||||
|
||||
vk::SubmitInfo submitInfo;
|
||||
submitInfo.setCommandBuffers(cmd)
|
||||
.setWaitSemaphores(waitSemaphores)
|
||||
.setWaitDstStageMask(waitStages)
|
||||
.setSignalSemaphores(signalSemaphores);
|
||||
|
||||
m_Device->GetGraphicsQueue().submit(submitInfo, m_SyncManager->GetFrameFence(frameIndex));
|
||||
|
||||
// 6. 呈现
|
||||
std::array<vk::SwapchainKHR, 1> swapchains = {m_Swapchain->Get()};
|
||||
std::array<vk::Semaphore, 1> presentWait = {
|
||||
m_SyncManager->GetRenderFinished(imageIndex)
|
||||
};
|
||||
|
||||
vk::PresentInfoKHR presentInfo;
|
||||
presentInfo.setImageIndices(imageIndex)
|
||||
.setSwapchains(swapchains)
|
||||
.setWaitSemaphores(presentWait);
|
||||
|
||||
try
|
||||
{
|
||||
auto result = m_Device->GetPresentQueue().presentKHR(presentInfo);
|
||||
if (result == vk::Result::eSuboptimalKHR)
|
||||
{
|
||||
m_Swapchain->Recreate(m_Window);
|
||||
}
|
||||
}
|
||||
catch (const vk::OutOfDateKHRError&)
|
||||
{
|
||||
m_Swapchain->Recreate(m_Window);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::RecordCommands(vk::CommandBuffer cmd, u32 imageIndex)
|
||||
{
|
||||
vk::ClearValue clearValue;
|
||||
clearValue.color = vk::ClearColorValue(std::array<float, 4>{0.1f, 0.1f, 0.1f, 1.0f});
|
||||
|
||||
// 颜色附件
|
||||
vk::RenderingAttachmentInfo colorAttachment;
|
||||
colorAttachment.setImageView(m_Swapchain->GetImageViews()[imageIndex])
|
||||
.setImageLayout(vk::ImageLayout::eColorAttachmentOptimal)
|
||||
.setLoadOp(vk::AttachmentLoadOp::eClear)
|
||||
.setStoreOp(vk::AttachmentStoreOp::eStore)
|
||||
.setClearValue(clearValue);
|
||||
|
||||
// 深度附件
|
||||
vk::RenderingAttachmentInfo depthAttachment;
|
||||
depthAttachment.setImageView(m_Swapchain->GetDepthImageView())
|
||||
.setImageLayout(vk::ImageLayout::eDepthAttachmentOptimal)
|
||||
.setLoadOp(vk::AttachmentLoadOp::eClear)
|
||||
.setStoreOp(vk::AttachmentStoreOp::eDontCare)
|
||||
.setClearValue(vk::ClearValue(vk::ClearDepthStencilValue(1.0f, 0)));
|
||||
|
||||
vk::RenderingInfo renderingInfo;
|
||||
renderingInfo.setRenderArea({{0, 0}, m_Extent})
|
||||
.setLayerCount(1)
|
||||
.setColorAttachments(colorAttachment)
|
||||
.setPDepthAttachment(&depthAttachment);
|
||||
|
||||
cmd.beginRendering(renderingInfo);
|
||||
|
||||
// 绑定着色器
|
||||
std::array<vk::ShaderStageFlagBits, 2> stages = {
|
||||
vk::ShaderStageFlagBits::eVertex,
|
||||
vk::ShaderStageFlagBits::eFragment
|
||||
};
|
||||
std::array<vk::ShaderEXT, 2> shaders = {m_VertShader, m_FragShader};
|
||||
cmd.bindShadersEXT(stages, shaders);
|
||||
|
||||
// 绑定描述符集
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
|
||||
m_PipelineLayout, 0,
|
||||
m_DescriptorSet, {});
|
||||
|
||||
// ===== 动态状态 =====
|
||||
cmd.setRasterizerDiscardEnable(VK_FALSE);
|
||||
|
||||
cmd.setDepthTestEnable(VK_TRUE);
|
||||
cmd.setDepthWriteEnable(VK_TRUE);
|
||||
cmd.setDepthCompareOp(vk::CompareOp::eLess);
|
||||
cmd.setDepthBoundsTestEnable(VK_FALSE);
|
||||
|
||||
cmd.setStencilTestEnable(VK_FALSE);
|
||||
cmd.setDepthBiasEnable(VK_FALSE);
|
||||
cmd.setPolygonModeEXT(vk::PolygonMode::eFill);
|
||||
cmd.setCullMode(vk::CullModeFlagBits::eNone);
|
||||
cmd.setFrontFace(vk::FrontFace::eCounterClockwise);
|
||||
cmd.setPrimitiveTopology(vk::PrimitiveTopology::eTriangleList);
|
||||
cmd.setPrimitiveRestartEnable(VK_FALSE);
|
||||
|
||||
// 顶点输入
|
||||
vk::VertexInputBindingDescription2EXT binding;
|
||||
binding.setBinding(0)
|
||||
.setStride(sizeof(f32) * 6)
|
||||
.setInputRate(vk::VertexInputRate::eVertex)
|
||||
.setDivisor(1);
|
||||
|
||||
std::array<vk::VertexInputAttributeDescription2EXT, 2> attributes;
|
||||
attributes[0].setLocation(0)
|
||||
.setBinding(0)
|
||||
.setFormat(vk::Format::eR32G32B32Sfloat)
|
||||
.setOffset(0);
|
||||
attributes[1].setLocation(1)
|
||||
.setBinding(0)
|
||||
.setFormat(vk::Format::eR32G32B32Sfloat)
|
||||
.setOffset(sizeof(f32) * 3);
|
||||
|
||||
cmd.setVertexInputEXT(binding, attributes);
|
||||
|
||||
cmd.setRasterizationSamplesEXT(vk::SampleCountFlagBits::e1);
|
||||
vk::SampleMask sampleMask = 0xFFFFFFFF;
|
||||
cmd.setSampleMaskEXT(vk::SampleCountFlagBits::e1, sampleMask);
|
||||
cmd.setAlphaToCoverageEnableEXT(VK_FALSE);
|
||||
cmd.setAlphaToOneEnableEXT(VK_FALSE);
|
||||
|
||||
vk::Viewport viewport(0.0f, 0.0f,
|
||||
static_cast<float>(m_Extent.width),
|
||||
static_cast<float>(m_Extent.height),
|
||||
0.0f, 1.0f);
|
||||
cmd.setViewportWithCount(viewport);
|
||||
|
||||
vk::Rect2D scissor({0, 0}, m_Extent);
|
||||
cmd.setScissorWithCount(scissor);
|
||||
|
||||
vk::Bool32 blendEnable = VK_FALSE;
|
||||
cmd.setColorBlendEnableEXT(0, blendEnable);
|
||||
|
||||
vk::ColorBlendEquationEXT blendEquation;
|
||||
blendEquation.setSrcColorBlendFactor(vk::BlendFactor::eOne)
|
||||
.setDstColorBlendFactor(vk::BlendFactor::eZero)
|
||||
.setColorBlendOp(vk::BlendOp::eAdd)
|
||||
.setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
|
||||
.setDstAlphaBlendFactor(vk::BlendFactor::eZero)
|
||||
.setAlphaBlendOp(vk::BlendOp::eAdd);
|
||||
cmd.setColorBlendEquationEXT(0, blendEquation);
|
||||
|
||||
vk::ColorComponentFlags colorWriteMask =
|
||||
vk::ColorComponentFlagBits::eR |
|
||||
vk::ColorComponentFlagBits::eG |
|
||||
vk::ColorComponentFlagBits::eB |
|
||||
vk::ColorComponentFlagBits::eA;
|
||||
cmd.setColorWriteMaskEXT(0, colorWriteMask);
|
||||
|
||||
// 绑定顶点缓冲并绘制
|
||||
cmd.bindVertexBuffers(0, m_VertexBuffer->Get(), {0});
|
||||
cmd.bindIndexBuffer(m_IndexBuffer->Get(), 0, vk::IndexType::eUint32);
|
||||
// cmd.draw(3, 1, 0, 0);
|
||||
cmd.drawIndexed(36, 1, 0, 0, 0);
|
||||
|
||||
cmd.endRendering();
|
||||
}
|
||||
|
||||
void Renderer::TransitionImageLayout(vk::CommandBuffer cmd, vk::Image image,
|
||||
vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
|
||||
{
|
||||
vk::ImageMemoryBarrier2 barrier;
|
||||
barrier.setSrcStageMask(vk::PipelineStageFlagBits2::eColorAttachmentOutput)
|
||||
.setSrcAccessMask(vk::AccessFlagBits2::eColorAttachmentWrite)
|
||||
.setDstStageMask(vk::PipelineStageFlagBits2::eColorAttachmentOutput)
|
||||
.setDstAccessMask(vk::AccessFlagBits2::eColorAttachmentWrite)
|
||||
.setOldLayout(oldLayout)
|
||||
.setNewLayout(newLayout)
|
||||
.setImage(image)
|
||||
.setSubresourceRange({
|
||||
vk::ImageAspectFlagBits::eColor,
|
||||
0, 1, 0, 1
|
||||
});
|
||||
|
||||
vk::DependencyInfo dependencyInfo;
|
||||
dependencyInfo.setImageMemoryBarriers(barrier);
|
||||
|
||||
cmd.pipelineBarrier2(dependencyInfo);
|
||||
}
|
||||
} // namespace Engine
|
||||
Reference in New Issue
Block a user