We be kinda rendering
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
App::App(): renderer{meshCache} {
|
||||
}
|
||||
|
||||
void App::init(const AppParams& params) {
|
||||
m_params = params;
|
||||
|
||||
@@ -30,11 +33,22 @@ void App::init(const AppParams& params) {
|
||||
}
|
||||
|
||||
gfxDevice.init(window, params.appName, false);
|
||||
renderer.init(gfxDevice, params.renderSize);
|
||||
|
||||
//Read whole file
|
||||
auto file = AssetFS::GetInstance().ReadBytes("engine://assetfstest.txt");
|
||||
std::string fileStr(file.begin(), file.end());
|
||||
spdlog::info("Read from assetfstest.txt: {}", fileStr);
|
||||
testMesh.name = "Test Mesh";
|
||||
testMesh.vertices = vertices;
|
||||
testMesh.indices = indices;
|
||||
|
||||
testMeshID = meshCache.addMesh(gfxDevice, testMesh);
|
||||
spdlog::info("TestMesh uploaded with id: {}", testMeshID);
|
||||
|
||||
float aspectRatio = static_cast<float>(params.renderSize.x) / static_cast<float>(params.renderSize.y);
|
||||
camera.setAspectRatio(aspectRatio);
|
||||
|
||||
}
|
||||
|
||||
void App::run() {
|
||||
@@ -97,8 +111,16 @@ void App::run() {
|
||||
}
|
||||
|
||||
if (!gfxDevice.needsSwapchainRecreate()) {
|
||||
renderer.beginDrawing(gfxDevice);
|
||||
renderer.drawMesh(testMeshID, glm::mat4(1.f), 0);
|
||||
renderer.endDrawing();
|
||||
|
||||
|
||||
auto cmd = gfxDevice.beginFrame();
|
||||
gfxDevice.endFrame(cmd, VImage{}, {});
|
||||
renderer.draw(cmd, gfxDevice, camera, GameRenderer::SceneData{
|
||||
camera, glm::vec3(0.1f), 0.5f, glm::vec3(0.5f), 0.01f
|
||||
});
|
||||
gfxDevice.endFrame(cmd, GPUImage{}, {});
|
||||
}
|
||||
if (frameLimit) {
|
||||
// Delay to not overload the CPU
|
||||
|
||||
195
destrum/src/Graphics/Camera.cpp
Normal file
195
destrum/src/Graphics/Camera.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
#include <destrum/Graphics/Camera.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <glm/gtc/matrix_inverse.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
Camera::Camera(const glm::vec3& position, const glm::vec3& up): m_position{position}, m_up{up} {
|
||||
}
|
||||
|
||||
void Camera::Update(float deltaTime) {
|
||||
// const auto MyWindow = static_cast<Window*>(glfwGetWindowUserPointer(Window::gWindow));
|
||||
//
|
||||
// #pragma region Keyboard Movement
|
||||
// totalPitch = glm::clamp(totalPitch, -glm::half_pi<float>() + 0.01f, glm::half_pi<float>() - 0.01f);
|
||||
//
|
||||
// float MovementSpeed = m_movementSpeed;
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
|
||||
// MovementSpeed *= 2.0f;
|
||||
// }
|
||||
//
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_W) == GLFW_PRESS) {
|
||||
// m_position += m_forward * deltaTime * MovementSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_A) == GLFW_PRESS) {
|
||||
// m_position -= m_right * deltaTime * MovementSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_S) == GLFW_PRESS) {
|
||||
// m_position -= m_forward * deltaTime * MovementSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_D) == GLFW_PRESS) {
|
||||
// m_position += m_right * deltaTime * MovementSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_E) == GLFW_PRESS) {
|
||||
// m_position += m_up * deltaTime * MovementSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_Q) == GLFW_PRESS) {
|
||||
// m_position -= m_up * deltaTime * MovementSpeed;
|
||||
// }
|
||||
//
|
||||
// // Looking around with arrow keys
|
||||
// constexpr float lookSpeed = 1.0f * glm::radians(1.f);
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_UP) == GLFW_PRESS) {
|
||||
// totalPitch += lookSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
||||
// totalPitch -= lookSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_LEFT) == GLFW_PRESS) {
|
||||
// totalYaw -= lookSpeed;
|
||||
// }
|
||||
// if (glfwGetKey(Window::gWindow, GLFW_KEY_RIGHT) == GLFW_PRESS) {
|
||||
// totalYaw += lookSpeed;
|
||||
// }
|
||||
//
|
||||
// totalPitch = glm::clamp(totalPitch, -glm::half_pi<float>(), glm::half_pi<float>());
|
||||
//
|
||||
// const glm::mat4 yawMatrix = glm::rotate(glm::mat4(1.0f), -totalYaw, glm::vec3(0, 1, 0));
|
||||
// const glm::mat4 pitchMatrix = glm::rotate(glm::mat4(1.0f), totalPitch, glm::vec3(0, 0, 1));
|
||||
//
|
||||
// const glm::mat4 rotationMatrix = yawMatrix * pitchMatrix;
|
||||
//
|
||||
// m_forward = glm::vec3(rotationMatrix * glm::vec4(1, 0, 0, 0));
|
||||
// m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0)));
|
||||
// m_up = glm::normalize(glm::cross(m_right, m_forward));
|
||||
// #pragma endregion
|
||||
//
|
||||
// #pragma region Mouse Looking
|
||||
// static bool wasCursorLockedLastFrame = false;
|
||||
// static double lastMouseX = 0.0;
|
||||
// static double lastMouseY = 0.0;
|
||||
// static bool firstMouse = true;
|
||||
//
|
||||
// bool isLocked = MyWindow->isCursorLocked();
|
||||
// if (isLocked) {
|
||||
// double mouseX, mouseY;
|
||||
// glfwGetCursorPos(Window::gWindow, &mouseX, &mouseY);
|
||||
//
|
||||
// // Reset mouse reference when locking the cursor (prevents jump)
|
||||
// if (!wasCursorLockedLastFrame) {
|
||||
// lastMouseX = mouseX;
|
||||
// lastMouseY = mouseY;
|
||||
// firstMouse = false;
|
||||
// }
|
||||
//
|
||||
// float xOffset = static_cast<float>(mouseX - lastMouseX);
|
||||
// float yOffset = static_cast<float>(lastMouseY - mouseY); // Reversed: y goes up
|
||||
//
|
||||
// lastMouseX = mouseX;
|
||||
// lastMouseY = mouseY;
|
||||
//
|
||||
// constexpr float sensitivity = 0.002f;
|
||||
// xOffset *= sensitivity;
|
||||
// yOffset *= sensitivity;
|
||||
//
|
||||
// totalYaw += xOffset;
|
||||
// totalPitch += yOffset;
|
||||
//
|
||||
// totalPitch = glm::clamp(totalPitch, -glm::half_pi<float>() + 0.01f, glm::half_pi<float>() - 0.01f);
|
||||
//
|
||||
// m_frustum.update(m_projectionMatrix * m_viewMatrix);
|
||||
// }
|
||||
//
|
||||
// wasCursorLockedLastFrame = isLocked;
|
||||
// #pragma endregion
|
||||
//
|
||||
// #pragma region Controller Movement
|
||||
//
|
||||
// if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1)) {
|
||||
// GLFWgamepadstate state;
|
||||
// if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1) && glfwGetGamepadState(GLFW_JOYSTICK_1, &state)) {
|
||||
// float moveSpeed = MovementSpeed * deltaTime;
|
||||
// const float rotSpeed = 1.5f * deltaTime;
|
||||
//
|
||||
//
|
||||
// //TODO: god knows what this is
|
||||
// auto deadzone = [] (float value, float threshold = 0.1f) {
|
||||
// if (fabs(value) < threshold)
|
||||
// return 0.0f;
|
||||
// const float sign = (value > 0) ? 1.0f : -1.0f;
|
||||
// return sign * (fabs(value) - threshold) / (1.0f - threshold);
|
||||
// };
|
||||
//
|
||||
// //LT is x2 speed
|
||||
// const bool isLTPressed = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS;
|
||||
// if (isLTPressed) {
|
||||
// moveSpeed *= 3.0f;
|
||||
// }
|
||||
//
|
||||
// const float lx = deadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]);
|
||||
// const float ly = deadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]);
|
||||
// const float rx = deadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]);
|
||||
// const float ry = deadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]);
|
||||
//
|
||||
// m_position += m_forward * (-ly * moveSpeed);
|
||||
// m_position += m_right * (lx * moveSpeed);
|
||||
//
|
||||
// const float lTrigger = (state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) / 2.0f;
|
||||
// const float rTrigger = (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) / 2.0f;
|
||||
// const float vertical = (rTrigger - lTrigger);
|
||||
// m_position += m_up * vertical * moveSpeed;
|
||||
//
|
||||
// totalYaw += rx * rotSpeed;
|
||||
// totalPitch -= ry * rotSpeed;
|
||||
// }
|
||||
// }
|
||||
// #pragma endregion
|
||||
|
||||
CalculateProjectionMatrix();
|
||||
CalculateViewMatrix();
|
||||
}
|
||||
|
||||
void Camera::CalculateViewMatrix() {
|
||||
if (m_useTarget) {
|
||||
m_forward = glm::normalize(m_target - m_position);
|
||||
m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0)));
|
||||
m_up = glm::normalize(glm::cross(m_right, m_forward));
|
||||
m_viewMatrix = glm::lookAt(m_position, m_target, m_up);
|
||||
} else {
|
||||
m_viewMatrix = glm::lookAt(m_position, m_position + m_forward, m_up);
|
||||
}
|
||||
|
||||
m_invMatrix = glm::inverse(m_viewMatrix);
|
||||
}
|
||||
|
||||
void Camera::CalculateProjectionMatrix() {
|
||||
m_projectionMatrix = glm::perspectiveRH_ZO(glm::radians(fovAngle), m_aspectRatio, m_zNear, m_zFar);
|
||||
}
|
||||
|
||||
void Camera::ClearTarget() {
|
||||
m_useTarget = false;
|
||||
m_forward = glm::normalize(m_target - m_position);
|
||||
m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0)));
|
||||
m_up = glm::normalize(glm::cross(m_right, m_forward));
|
||||
}
|
||||
|
||||
void Camera::SetTarget(const glm::vec3& target) {
|
||||
m_target = target;
|
||||
m_useTarget = true;
|
||||
// m_forward = glm::normalize(m_target - m_position);
|
||||
// m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0)));
|
||||
// m_up = glm::normalize(glm::cross(m_right, m_forward));
|
||||
}
|
||||
|
||||
void Camera::Target(const glm::vec3& target) {
|
||||
glm::vec3 directionToTarget = glm::normalize(target - m_position);
|
||||
|
||||
m_forward = glm::normalize(target - m_position);
|
||||
m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0)));
|
||||
m_up = glm::normalize(glm::cross(m_right, m_forward));
|
||||
|
||||
m_viewMatrix = glm::lookAt(m_position, m_position + m_forward, m_up);
|
||||
m_invMatrix = glm::inverse(m_viewMatrix);
|
||||
}
|
||||
565
destrum/src/Graphics/GfxDevice.cpp
Normal file
565
destrum/src/Graphics/GfxDevice.cpp
Normal file
@@ -0,0 +1,565 @@
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
|
||||
#include "destrum/Graphics/Util.h"
|
||||
|
||||
#define VOLK_IMPLEMENTATION
|
||||
#include <volk.h>
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <filesystem>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/Init.h>
|
||||
|
||||
#include "destrum/Graphics/imageLoader.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
GfxDevice::GfxDevice(): imageCache(*this) {
|
||||
}
|
||||
|
||||
void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) {
|
||||
VK_CHECK(volkInitialize());
|
||||
|
||||
instance = vkb::InstanceBuilder{}
|
||||
.set_app_name(appName.c_str())
|
||||
.set_app_version(1, 0, 0)
|
||||
.request_validation_layers()
|
||||
.use_default_debug_messenger()
|
||||
.require_api_version(1, 3, 0)
|
||||
.build()
|
||||
.value();
|
||||
|
||||
volkLoadInstance(instance);
|
||||
|
||||
const auto res = SDL_Vulkan_CreateSurface(window, instance, &surface);
|
||||
if (res != SDL_TRUE) {
|
||||
spdlog::error("Failed to create Vulkan surface: {}", SDL_GetError());
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
constexpr auto deviceFeatures = VkPhysicalDeviceFeatures{
|
||||
.imageCubeArray = VK_TRUE,
|
||||
.geometryShader = VK_TRUE, // for im3d
|
||||
.depthClamp = VK_TRUE,
|
||||
.samplerAnisotropy = VK_TRUE,
|
||||
};
|
||||
|
||||
constexpr auto features12 = VkPhysicalDeviceVulkan12Features{
|
||||
.descriptorIndexing = true,
|
||||
.descriptorBindingSampledImageUpdateAfterBind = true,
|
||||
.descriptorBindingStorageImageUpdateAfterBind = true,
|
||||
.descriptorBindingPartiallyBound = true,
|
||||
.descriptorBindingVariableDescriptorCount = true,
|
||||
.runtimeDescriptorArray = true,
|
||||
.scalarBlockLayout = true,
|
||||
.bufferDeviceAddress = true,
|
||||
};
|
||||
constexpr auto features13 = VkPhysicalDeviceVulkan13Features{
|
||||
.synchronization2 = true,
|
||||
.dynamicRendering = true,
|
||||
};
|
||||
|
||||
physicalDevice = vkb::PhysicalDeviceSelector{instance}
|
||||
.set_minimum_version(1, 3)
|
||||
.set_required_features(deviceFeatures)
|
||||
.set_required_features_12(features12)
|
||||
.set_required_features_13(features13)
|
||||
.set_surface(surface)
|
||||
.select()
|
||||
.value();
|
||||
|
||||
device = vkb::DeviceBuilder{physicalDevice}.build().value();
|
||||
|
||||
graphicsQueueFamily = device.get_queue_index(vkb::QueueType::graphics).value();
|
||||
graphicsQueue = device.get_queue(vkb::QueueType::graphics).value();
|
||||
|
||||
//Vma
|
||||
const auto vulkanFunctions = VmaVulkanFunctions{
|
||||
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
|
||||
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
|
||||
};
|
||||
|
||||
const auto allocatorInfo = VmaAllocatorCreateInfo{
|
||||
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
||||
.physicalDevice = physicalDevice,
|
||||
.device = device,
|
||||
.pVulkanFunctions = &vulkanFunctions,
|
||||
.instance = instance,
|
||||
};
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
|
||||
executor.init(device, graphicsQueueFamily, graphicsQueue);
|
||||
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
swapchainFormat = VK_FORMAT_B8G8R8A8_SRGB;
|
||||
swapchain.createSwapchain(this, swapchainFormat, w, h, vSync);
|
||||
|
||||
swapchain.initSync(device);
|
||||
|
||||
const auto poolCreateInfo = vkinit::commandPoolCreateInfo(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, graphicsQueueFamily);
|
||||
|
||||
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
|
||||
auto& commandPool = frames[i].commandPool;
|
||||
VK_CHECK(vkCreateCommandPool(device, &poolCreateInfo, nullptr, &commandPool));
|
||||
|
||||
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
|
||||
auto& mainCommandBuffer = frames[i].commandBuffer;
|
||||
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
||||
}
|
||||
//
|
||||
// { // create white texture
|
||||
// std::uint32_t pixel = 0xFFFFFFFF;
|
||||
// whiteImageId = createImage(
|
||||
// {
|
||||
// .format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
// .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
// .extent = VkExtent3D{1, 1, 1},
|
||||
// },
|
||||
// "white texture",
|
||||
// &pixel);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void GfxDevice::recreateSwapchain(int width, int height) {
|
||||
assert(width != 0 && height != 0);
|
||||
waitIdle();
|
||||
swapchain.recreateSwapchain(*this, swapchainFormat, width, height, false);
|
||||
}
|
||||
|
||||
VkCommandBuffer GfxDevice::beginFrame() {
|
||||
swapchain.beginFrame(getCurrentFrameIndex());
|
||||
|
||||
const auto& frame = getCurrentFrame();
|
||||
const auto& cmd = frame.commandBuffer;
|
||||
const auto cmdBeginInfo = VkCommandBufferBeginInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props) {
|
||||
// get swapchain image
|
||||
const auto [swapchainImage, swapchainImageIndex] = swapchain.acquireNextImage(getCurrentFrameIndex());
|
||||
if (swapchainImage == VK_NULL_HANDLE) {
|
||||
spdlog::info("Swapchain is freaky, skipping frame...");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fences are reset here to prevent the deadlock in case swapchain becomes dirty
|
||||
swapchain.resetFences(getCurrentFrameIndex());
|
||||
|
||||
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
{
|
||||
// clear swapchain image
|
||||
VkImageSubresourceRange clearRange =
|
||||
vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// if (props.copyImageIntoSwapchain) {
|
||||
// copy from draw image into swapchain
|
||||
// vkutil::transitionImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
|
||||
// VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
vkutil::transitionImage(
|
||||
cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
// const auto filter = props.drawImageLinearBlit ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
const auto filter = VK_FILTER_LINEAR;
|
||||
// // if (props.drawImageBlitRect != glm::ivec4{}) {
|
||||
// vkutil::copyImageToImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// swapchainImage,
|
||||
// drawImage.getExtent2D(),
|
||||
// props.drawImageBlitRect.x,
|
||||
// props.drawImageBlitRect.y,
|
||||
// props.drawImageBlitRect.z,
|
||||
// props.drawImageBlitRect.w,
|
||||
// filter);
|
||||
// } else {
|
||||
// // will stretch image to swapchain
|
||||
// vkutil::copyImageToImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// swapchainImage,
|
||||
// drawImage.getExtent2D(),
|
||||
// getSwapchainExtent(),
|
||||
// filter);
|
||||
// }
|
||||
|
||||
// prepare for present
|
||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VK_CHECK(vkEndCommandBuffer(cmd));
|
||||
|
||||
// swapchain.submitAndPresent(cmd, graphicsQueue, getCurrentFrameIndex(), swapchainImageIndex);
|
||||
swapchain.submitAndPresent(cmd, graphicsQueue, swapchainImageIndex, getCurrentFrameIndex());
|
||||
|
||||
frameNumber++;
|
||||
}
|
||||
|
||||
void GfxDevice::cleanup() {
|
||||
}
|
||||
|
||||
void GfxDevice::waitIdle() {
|
||||
VK_CHECK(vkDeviceWaitIdle(device));
|
||||
}
|
||||
|
||||
void GfxDevice::immediateSubmit(ImmediateExecuteFunction&& f) const {
|
||||
executor.immediateSubmit(std::move(f));
|
||||
}
|
||||
|
||||
GPUBuffer GfxDevice::createBuffer(
|
||||
std::size_t allocSize,
|
||||
VkBufferUsageFlags usage,
|
||||
VmaMemoryUsage memoryUsage) const
|
||||
{
|
||||
const auto bufferInfo = VkBufferCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = allocSize,
|
||||
.usage = usage,
|
||||
};
|
||||
|
||||
const auto allocInfo = VmaAllocationCreateInfo{
|
||||
.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
// TODO: allow to set VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT when needed
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
.usage = memoryUsage,
|
||||
};
|
||||
|
||||
GPUBuffer buffer{};
|
||||
VK_CHECK(vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer.buffer, &buffer.allocation, &buffer.info));
|
||||
if ((usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0) {
|
||||
const auto deviceAdressInfo = VkBufferDeviceAddressInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
||||
.buffer = buffer.buffer,
|
||||
};
|
||||
buffer.address = vkGetBufferDeviceAddress(device, &deviceAdressInfo);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VkDeviceAddress GfxDevice::getBufferAddress(const GPUBuffer& buffer) const
|
||||
{
|
||||
const auto deviceAdressInfo = VkBufferDeviceAddressInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
||||
.buffer = buffer.buffer,
|
||||
};
|
||||
return vkGetBufferDeviceAddress(device, &deviceAdressInfo);
|
||||
}
|
||||
|
||||
void GfxDevice::destroyBuffer(const GPUBuffer& buffer) const
|
||||
{
|
||||
vmaDestroyBuffer(allocator, buffer.buffer, buffer.allocation);
|
||||
}
|
||||
//
|
||||
// GPUImage GfxDevice::loadImageFromFileRaw(
|
||||
// const std::filesystem::path& path,
|
||||
// VkFormat format,
|
||||
// VkImageUsageFlags usage,
|
||||
// bool mipMap) const
|
||||
// {
|
||||
// auto data = util::loadImage(path);
|
||||
// if (!data.pixels) {
|
||||
// fmt::println("[error] failed to load image from '{}'", path.string());
|
||||
// return getImage(errorImageId);
|
||||
// }
|
||||
//
|
||||
// auto image = createImageRaw({
|
||||
// .format = format,
|
||||
// .usage = usage | //
|
||||
// VK_IMAGE_USAGE_TRANSFER_DST_BIT | // for uploading pixel data to image
|
||||
// VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // for generating mips
|
||||
// .extent =
|
||||
// VkExtent3D{
|
||||
// .width = (std::uint32_t)data.width,
|
||||
// .height = (std::uint32_t)data.height,
|
||||
// .depth = 1,
|
||||
// },
|
||||
// .mipMap = mipMap,
|
||||
// });
|
||||
// uploadImageData(image, data.pixels);
|
||||
//
|
||||
// image.debugName = path.string();
|
||||
// vkutil::addDebugLabel(device, image.image, path.string().c_str());
|
||||
//
|
||||
// return image;
|
||||
// }
|
||||
|
||||
ImageID GfxDevice::createImage(
|
||||
const vkutil::CreateImageInfo& createInfo,
|
||||
const std::string& debugName,
|
||||
void* pixelData,
|
||||
ImageID imageId)
|
||||
{
|
||||
auto image = createImageRaw(createInfo);
|
||||
if (!debugName.empty()) {
|
||||
vkutil::addDebugLabel(device, image.image, debugName.c_str());
|
||||
image.debugName = debugName;
|
||||
}
|
||||
if (pixelData) {
|
||||
uploadImageData(image, pixelData);
|
||||
}
|
||||
if (imageId != NULL_IMAGE_ID) {
|
||||
return imageCache.addImage(imageId, std::move(image));
|
||||
} else {
|
||||
return addImageToCache(std::move(image));
|
||||
}
|
||||
}
|
||||
|
||||
ImageID GfxDevice::createDrawImage(
|
||||
VkFormat format,
|
||||
glm::ivec2 size,
|
||||
const std::string& debugName,
|
||||
ImageID imageId)
|
||||
{
|
||||
assert(size.x > 0 && size.y > 0);
|
||||
const auto extent = VkExtent3D{
|
||||
.width = (std::uint32_t)size.x,
|
||||
.height = (std::uint32_t)size.y,
|
||||
.depth = 1,
|
||||
};
|
||||
|
||||
VkImageUsageFlags usages{};
|
||||
usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
usages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
usages |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
const auto createImageInfo = vkutil::CreateImageInfo{
|
||||
.format = format,
|
||||
.usage = usages,
|
||||
.extent = extent,
|
||||
};
|
||||
return createImage(createImageInfo, debugName, nullptr, imageId);
|
||||
}
|
||||
|
||||
ImageID GfxDevice::loadImageFromFile(
|
||||
const std::filesystem::path& path,
|
||||
VkFormat format,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap)
|
||||
{
|
||||
return imageCache.loadImageFromFile(path, format, usage, mipMap);
|
||||
}
|
||||
|
||||
const GPUImage& GfxDevice::getImage(ImageID id) const
|
||||
{
|
||||
return imageCache.getImage(id);
|
||||
}
|
||||
|
||||
ImageID GfxDevice::addImageToCache(GPUImage img)
|
||||
{
|
||||
return imageCache.addImage(std::move(img));
|
||||
}
|
||||
|
||||
GPUImage GfxDevice::createImageRaw(
|
||||
const vkutil::CreateImageInfo& createInfo,
|
||||
std::optional<VmaAllocationCreateInfo> customAllocationCreateInfo) const
|
||||
{
|
||||
std::uint32_t mipLevels = 1;
|
||||
if (createInfo.mipMap) {
|
||||
const auto maxExtent = std::max(createInfo.extent.width, createInfo.extent.height);
|
||||
mipLevels = (std::uint32_t)std::floor(std::log2(maxExtent)) + 1;
|
||||
}
|
||||
|
||||
if (createInfo.isCubemap) {
|
||||
assert(createInfo.numLayers % 6 == 0);
|
||||
assert(!createInfo.mipMap);
|
||||
assert((createInfo.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0);
|
||||
}
|
||||
|
||||
auto imgInfo = VkImageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.flags = createInfo.flags,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = createInfo.format,
|
||||
.extent = createInfo.extent,
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = createInfo.numLayers,
|
||||
.samples = createInfo.samples,
|
||||
.tiling = createInfo.tiling,
|
||||
.usage = createInfo.usage,
|
||||
};
|
||||
|
||||
static const auto defaultAllocInfo = VmaAllocationCreateInfo{
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
};
|
||||
const auto allocInfo = customAllocationCreateInfo.has_value() ?
|
||||
customAllocationCreateInfo.value() :
|
||||
defaultAllocInfo;
|
||||
|
||||
GPUImage image{};
|
||||
image.format = createInfo.format;
|
||||
image.usage = createInfo.usage;
|
||||
image.extent = createInfo.extent;
|
||||
image.mipLevels = mipLevels;
|
||||
image.numLayers = createInfo.numLayers;
|
||||
image.isCubemap = createInfo.isCubemap;
|
||||
|
||||
VK_CHECK(
|
||||
vmaCreateImage(allocator, &imgInfo, &allocInfo, &image.image, &image.allocation, nullptr));
|
||||
|
||||
// create view only when usage flags allow it
|
||||
bool shouldCreateView = ((createInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) ||
|
||||
((createInfo.usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) ||
|
||||
((createInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0) ||
|
||||
((createInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0);
|
||||
|
||||
if (shouldCreateView) {
|
||||
VkImageAspectFlags aspectFlag = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if (createInfo.format == VK_FORMAT_D32_SFLOAT) { // TODO: support other depth formats
|
||||
aspectFlag = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
|
||||
auto viewType =
|
||||
createInfo.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
if (createInfo.isCubemap && createInfo.numLayers == 6) {
|
||||
viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
}
|
||||
|
||||
const auto viewCreateInfo = VkImageViewCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image.image,
|
||||
.viewType = viewType,
|
||||
.format = createInfo.format,
|
||||
.subresourceRange =
|
||||
VkImageSubresourceRange{
|
||||
.aspectMask = aspectFlag,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = createInfo.numLayers,
|
||||
},
|
||||
};
|
||||
|
||||
VK_CHECK(vkCreateImageView(device, &viewCreateInfo, nullptr, &image.imageView));
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void GfxDevice::uploadImageData(const GPUImage& image, void* pixelData, std::uint32_t layer) const
|
||||
{
|
||||
int numChannels = 4;
|
||||
if (image.format == VK_FORMAT_R8_UNORM) {
|
||||
// FIXME: support more types
|
||||
numChannels = 1;
|
||||
}
|
||||
const auto dataSize =
|
||||
image.extent.depth * image.extent.width * image.extent.height * numChannels;
|
||||
|
||||
const auto uploadBuffer = createBuffer(dataSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
||||
memcpy(uploadBuffer.info.pMappedData, pixelData, dataSize);
|
||||
|
||||
executor.immediateSubmit([&](VkCommandBuffer cmd) {
|
||||
assert(
|
||||
(image.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) != 0 &&
|
||||
"Image needs to have VK_IMAGE_USAGE_TRANSFER_DST_BIT to upload data to it");
|
||||
vkutil::transitionImage(
|
||||
cmd, image.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
const auto copyRegion = VkBufferImageCopy{
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = layer,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageExtent = image.extent,
|
||||
};
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
cmd,
|
||||
uploadBuffer.buffer,
|
||||
image.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
©Region);
|
||||
|
||||
if (image.mipLevels > 1) {
|
||||
assert(
|
||||
(image.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) != 0 &&
|
||||
(image.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0 &&
|
||||
"Image needs to have VK_IMAGE_USAGE_TRANSFER_{DST,SRC}_BIT to generate mip maps");
|
||||
// graphics::generateMipmaps(
|
||||
// cmd,
|
||||
// image.image,
|
||||
// VkExtent2D{image.extent.width, image.extent.height},
|
||||
// image.mipLevels);
|
||||
spdlog::warn("Yea dawg, i ain't written this yet :pray:");
|
||||
} else {
|
||||
vkutil::transitionImage(
|
||||
cmd,
|
||||
image.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
});
|
||||
|
||||
destroyBuffer(uploadBuffer);
|
||||
}
|
||||
|
||||
GPUImage GfxDevice::loadImageFromFileRaw(
|
||||
const std::filesystem::path& path,
|
||||
VkFormat format,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap) const
|
||||
{
|
||||
auto data = util::loadImage(path);
|
||||
if (!data.pixels) {
|
||||
fmt::println("[error] failed to load image from '{}'", path.string());
|
||||
return getImage(errorImageId);
|
||||
}
|
||||
|
||||
auto image = createImageRaw({
|
||||
.format = format,
|
||||
.usage = usage | //
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | // for uploading pixel data to image
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // for generating mips
|
||||
.extent =
|
||||
VkExtent3D{
|
||||
.width = (std::uint32_t)data.width,
|
||||
.height = (std::uint32_t)data.height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mipMap = mipMap,
|
||||
});
|
||||
uploadImageData(image, data.pixels);
|
||||
|
||||
image.debugName = path.string();
|
||||
vkutil::addDebugLabel(device, image.image, path.string().c_str());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void GfxDevice::destroyImage(const GPUImage& image) const
|
||||
{
|
||||
vkDestroyImageView(device, image.imageView, nullptr);
|
||||
vmaDestroyImage(allocator, image.image, image.allocation);
|
||||
// TODO: if image has bindless id, update the set
|
||||
}
|
||||
77
destrum/src/Graphics/ImageCache.cpp
Normal file
77
destrum/src/Graphics/ImageCache.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <destrum/Graphics/ImageCache.h>
|
||||
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
|
||||
ImageCache::ImageCache(GfxDevice& gfxDevice) : gfxDevice(gfxDevice)
|
||||
{}
|
||||
|
||||
ImageID ImageCache::loadImageFromFile(
|
||||
const std::filesystem::path& path,
|
||||
VkFormat format,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap)
|
||||
{
|
||||
for (const auto& [id, info] : loadedImagesInfo) {
|
||||
// TODO: calculate some hash to not have to linear search every time?
|
||||
if (info.path == path && info.format == format && info.usage == usage &&
|
||||
info.mipMap == mipMap) {
|
||||
// std::cout << "Already loaded: " << path << std::endl;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
auto image = gfxDevice.loadImageFromFileRaw(path, format, usage, mipMap);
|
||||
if (image.isInitialized() && image.getBindlessId() == errorImageId) {
|
||||
return errorImageId;
|
||||
}
|
||||
|
||||
const auto id = getFreeImageId();
|
||||
addImage(id, std::move(image));
|
||||
|
||||
loadedImagesInfo.emplace(
|
||||
id,
|
||||
LoadedImageInfo{
|
||||
.path = path,
|
||||
.format = format,
|
||||
.usage = usage,
|
||||
.mipMap = mipMap,
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
ImageID ImageCache::addImage(GPUImage image)
|
||||
{
|
||||
return addImage(getFreeImageId(), std::move(image));
|
||||
}
|
||||
|
||||
ImageID ImageCache::addImage(ImageID id, GPUImage image)
|
||||
{
|
||||
image.setBindlessId(static_cast<std::uint32_t>(id));
|
||||
if (id != images.size()) {
|
||||
images[id] = std::move(image); // replacing existing image
|
||||
} else {
|
||||
images.push_back(std::move(image));
|
||||
}
|
||||
// bindlessSetManager.addImage(gfxDevice.getDevice(), id, image.imageView);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
const GPUImage& ImageCache::getImage(ImageID id) const
|
||||
{
|
||||
return images.at(id);
|
||||
}
|
||||
|
||||
ImageID ImageCache::getFreeImageId() const
|
||||
{
|
||||
return images.size();
|
||||
}
|
||||
|
||||
void ImageCache::destroyImages()
|
||||
{
|
||||
for (const auto& image : images) {
|
||||
gfxDevice.destroyImage(image);
|
||||
}
|
||||
images.clear();
|
||||
loadedImagesInfo.clear();
|
||||
}
|
||||
30
destrum/src/Graphics/ImageLoader.cpp
Normal file
30
destrum/src/Graphics/ImageLoader.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <destrum/Graphics/imageLoader.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
ImageData::~ImageData()
|
||||
{
|
||||
if (shouldSTBFree) {
|
||||
stbi_image_free(pixels);
|
||||
stbi_image_free(hdrPixels);
|
||||
}
|
||||
}
|
||||
|
||||
namespace util
|
||||
{
|
||||
ImageData loadImage(const std::filesystem::path& p)
|
||||
{
|
||||
ImageData data;
|
||||
data.shouldSTBFree = true;
|
||||
if (stbi_is_hdr(p.string().c_str())) {
|
||||
data.hdr = true;
|
||||
data.hdrPixels = stbi_loadf(p.string().c_str(), &data.width, &data.height, &data.comp, 4);
|
||||
} else {
|
||||
data.pixels = stbi_load(p.string().c_str(), &data.width, &data.height, &data.channels, 4);
|
||||
}
|
||||
data.channels = 4;
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
86
destrum/src/Graphics/MeshCache.cpp
Normal file
86
destrum/src/Graphics/MeshCache.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <destrum/Graphics/MeshCache.h>
|
||||
|
||||
#include <destrum/Graphics/Resources/Mesh.h>
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
#include <destrum/Graphics/Util.h>
|
||||
// #include <destrum/Math/Util.h>
|
||||
|
||||
MeshID MeshCache::addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh)
|
||||
{
|
||||
auto gpuMesh = GPUMesh{
|
||||
.numVertices = (std::uint32_t)cpuMesh.vertices.size(),
|
||||
.numIndices = (std::uint32_t)cpuMesh.indices.size(),
|
||||
.minPos = cpuMesh.minPos,
|
||||
.maxPos = cpuMesh.maxPos,
|
||||
};
|
||||
|
||||
std::vector<glm::vec3> positions(cpuMesh.vertices.size());
|
||||
for (std::size_t i = 0; i < cpuMesh.vertices.size(); ++i) {
|
||||
positions[i] = cpuMesh.vertices[i].position;
|
||||
}
|
||||
|
||||
uploadMesh(gfxDevice, cpuMesh, gpuMesh);
|
||||
const auto id = meshes.size();
|
||||
meshes.push_back(std::move(gpuMesh));
|
||||
return id;
|
||||
}
|
||||
|
||||
void MeshCache::uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh& gpuMesh) const
|
||||
{
|
||||
// create index buffer
|
||||
const auto indexBufferSize = cpuMesh.indices.size() * sizeof(std::uint32_t);
|
||||
gpuMesh.indexBuffer = gfxDevice.createBuffer(
|
||||
indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||
|
||||
// create vertex buffer
|
||||
const auto vertexBufferSize = cpuMesh.vertices.size() * sizeof(CPUMesh::Vertex);
|
||||
gpuMesh.vertexBuffer = gfxDevice.createBuffer(
|
||||
vertexBufferSize,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
|
||||
|
||||
const auto staging =
|
||||
gfxDevice
|
||||
.createBuffer(vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
||||
|
||||
// copy data
|
||||
void* data = staging.info.pMappedData;
|
||||
memcpy(data, cpuMesh.vertices.data(), vertexBufferSize);
|
||||
memcpy((char*)data + vertexBufferSize, cpuMesh.indices.data(), indexBufferSize);
|
||||
|
||||
gfxDevice.immediateSubmit([&](VkCommandBuffer cmd) {
|
||||
const auto vertexCopy = VkBufferCopy{
|
||||
.srcOffset = 0,
|
||||
.dstOffset = 0,
|
||||
.size = vertexBufferSize,
|
||||
};
|
||||
vkCmdCopyBuffer(cmd, staging.buffer, gpuMesh.vertexBuffer.buffer, 1, &vertexCopy);
|
||||
|
||||
const auto indexCopy = VkBufferCopy{
|
||||
.srcOffset = vertexBufferSize,
|
||||
.dstOffset = 0,
|
||||
.size = indexBufferSize,
|
||||
};
|
||||
vkCmdCopyBuffer(cmd, staging.buffer, gpuMesh.indexBuffer.buffer, 1, &indexCopy);
|
||||
});
|
||||
|
||||
gfxDevice.destroyBuffer(staging);
|
||||
|
||||
const auto vtxBufferName = cpuMesh.name + " (vtx)";
|
||||
const auto idxBufferName = cpuMesh.name + " (idx)";
|
||||
vkutil::addDebugLabel(gfxDevice.getDevice(), gpuMesh.vertexBuffer.buffer, vtxBufferName.c_str());
|
||||
vkutil::addDebugLabel(gfxDevice.getDevice(), gpuMesh.indexBuffer.buffer, idxBufferName.c_str());
|
||||
}
|
||||
|
||||
const GPUMesh& MeshCache::getMesh(MeshID id) const
|
||||
{
|
||||
return meshes.at(id);
|
||||
}
|
||||
|
||||
void MeshCache::cleanup(const GfxDevice& gfxDevice)
|
||||
{
|
||||
for (const auto& mesh : meshes) {
|
||||
gfxDevice.destroyBuffer(mesh.indexBuffer);
|
||||
gfxDevice.destroyBuffer(mesh.vertexBuffer);
|
||||
}
|
||||
}
|
||||
130
destrum/src/Graphics/Pipelines/MeshPipeline.cpp
Normal file
130
destrum/src/Graphics/Pipelines/MeshPipeline.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||
#include <destrum/FS/AssetFS.h>
|
||||
|
||||
MeshPipeline::MeshPipeline() {
|
||||
}
|
||||
|
||||
MeshPipeline::~MeshPipeline() {
|
||||
}
|
||||
|
||||
void MeshPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat) {
|
||||
const auto& device = gfxDevice.getDevice();
|
||||
|
||||
// const auto vertexShader = vkutil::loadShaderModule(AssetFS::GetInstance().GetFullPath("engine://shaders/mesh.vert.spv"), device);
|
||||
// const auto fragShader = vkutil::loadShaderModule(AssetFS::GetInstance().GetFullPath("engine://shaders/mesh.frag.spv"), device);
|
||||
|
||||
|
||||
const auto vertexShader = AssetFS::GetInstance().GetFullPath("engine://shaders/mesh.vert.spv");
|
||||
const auto fragShader = AssetFS::GetInstance().GetFullPath("engine://shaders/mesh.frag.spv");
|
||||
|
||||
|
||||
// vkutil::addDebugLabel(device, vertexShader, "mesh.vert");
|
||||
// vkutil::addDebugLabel(device, vertexShader, "mesh.frag");
|
||||
|
||||
const auto bufferRange = VkPushConstantRange{
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(PushConstants),
|
||||
};
|
||||
|
||||
const auto pushConstantRanges = std::array{bufferRange};
|
||||
// const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()};
|
||||
// m_pipelineLayout = vkutil::createPipelineLayout(device, layouts, pushConstantRanges);
|
||||
// vkutil::addDebugLabel(device, pipelineLayout, "mesh pipeline layout");
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
// pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size());
|
||||
// pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
|
||||
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
|
||||
|
||||
if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
|
||||
throw std::runtime_error("Could not make pipleine layout");
|
||||
}
|
||||
|
||||
PipelineConfigInfo pipelineConfig{};
|
||||
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
||||
pipelineConfig.name = "Mesh Pipeline";
|
||||
pipelineConfig.pipelineLayout = m_pipelineLayout;
|
||||
|
||||
pipelineConfig.vertexAttributeDescriptions = {};
|
||||
pipelineConfig.vertexBindingDescriptions = {};
|
||||
|
||||
pipelineConfig.colorAttachments = {drawImageFormat};
|
||||
pipelineConfig.depthAttachment = depthImageFormat;
|
||||
|
||||
m_pipeline = std::make_unique<Pipeline>(
|
||||
gfxDevice,
|
||||
vertexShader.string(),
|
||||
fragShader.string(),
|
||||
pipelineConfig
|
||||
);
|
||||
}
|
||||
|
||||
void MeshPipeline::draw(VkCommandBuffer cmd,
|
||||
VkExtent2D renderExtent,
|
||||
const GfxDevice& gfxDevice,
|
||||
const MeshCache& meshCache,
|
||||
const MaterialCache& materialCache,
|
||||
const Camera& camera,
|
||||
const GPUBuffer& sceneDataBuffer,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands) {
|
||||
// vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
m_pipeline->bind(cmd);
|
||||
// gfxDevice.bindBindlessDescSet(cmd, pipelineLayout);
|
||||
|
||||
const auto viewport = VkViewport{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = (float)renderExtent.width,
|
||||
.height = (float)renderExtent.height,
|
||||
.minDepth = 0.f,
|
||||
.maxDepth = 1.f,
|
||||
};
|
||||
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||
|
||||
const auto scissor = VkRect2D{
|
||||
.offset = {},
|
||||
.extent = renderExtent,
|
||||
};
|
||||
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||
|
||||
auto prevMeshId = NULL_MESH_ID;
|
||||
|
||||
// const auto frustum = edge::createFrustumFromCamera(camera);
|
||||
|
||||
for (const auto& dcIdx : drawCommands) {
|
||||
// const auto& dc = drawCommands[dcIdx];
|
||||
const auto& dc = dcIdx;
|
||||
|
||||
// if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
const auto& mesh = meshCache.getMesh(dc.meshId);
|
||||
if (dc.meshId != prevMeshId) {
|
||||
prevMeshId = dc.meshId;
|
||||
vkCmdBindIndexBuffer(cmd, mesh.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
}
|
||||
|
||||
assert(dc.materialId != NULL_MATERIAL_ID);
|
||||
const auto pushConstants = PushConstants{
|
||||
.transform = dc.transformMatrix,
|
||||
.sceneDataBuffer = sceneDataBuffer.address,
|
||||
.vertexBuffer = mesh.vertexBuffer.address,
|
||||
.materialId = dc.materialId,
|
||||
};
|
||||
vkCmdPushConstants(
|
||||
cmd,
|
||||
m_pipelineLayout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
0,
|
||||
sizeof(PushConstants),
|
||||
&pushConstants);
|
||||
|
||||
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
149
destrum/src/Graphics/Renderer.cpp
Normal file
149
destrum/src/Graphics/Renderer.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <destrum/Graphics/Renderer.h>
|
||||
|
||||
#include <destrum/Graphics/Util.h>
|
||||
|
||||
GameRenderer::GameRenderer(MeshCache& meshCache): meshCache{meshCache} {
|
||||
}
|
||||
|
||||
void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) {
|
||||
sceneDataBuffer.init(
|
||||
gfxDevice,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
sizeof(GPUSceneData),
|
||||
"scene data");
|
||||
|
||||
createDrawImage(gfxDevice, drawImageSize, true);
|
||||
|
||||
meshPipeline = std::make_unique<MeshPipeline>();
|
||||
meshPipeline->init(gfxDevice, drawImageFormat, depthImageFormat);
|
||||
|
||||
}
|
||||
|
||||
void GameRenderer::beginDrawing(GfxDevice& gfxDevice) {
|
||||
meshDrawCommands.clear();
|
||||
}
|
||||
|
||||
void GameRenderer::endDrawing() {
|
||||
//Sort the drawlist
|
||||
}
|
||||
|
||||
void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData) {
|
||||
const auto gpuSceneData = GPUSceneData{
|
||||
.view = sceneData.camera.GetViewMatrix(),
|
||||
.proj = sceneData.camera.GetProjectionMatrix(),
|
||||
.viewProj = sceneData.camera.GetViewProjectionMatrix(),
|
||||
.cameraPos = glm::vec4{sceneData.camera.m_position, 1.f},
|
||||
.ambientColor = {sceneData.ambientColor},
|
||||
.ambientIntensity = sceneData.ambientIntensity,
|
||||
.fogColor = {sceneData.fogColor},
|
||||
.fogDensity = sceneData.fogDensity,
|
||||
.materialsBuffer = materialCache.getMaterialDataBufferAddress(),
|
||||
};
|
||||
sceneDataBuffer.uploadNewData(
|
||||
cmd, gfxDevice.getCurrentFrameIndex(), (void*)&gpuSceneData, sizeof(GPUSceneData));
|
||||
|
||||
const auto& drawImage = gfxDevice.getImage(drawImageId);
|
||||
const auto& depthImage = gfxDevice.getImage(depthImageId);
|
||||
|
||||
// vkutil::cmdBeginLabel(cmd, "Geometry");
|
||||
vkutil::transitionImage(
|
||||
cmd,
|
||||
drawImage.image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
vkutil::transitionImage(
|
||||
cmd,
|
||||
depthImage.image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
||||
|
||||
const auto renderInfo = vkutil::createRenderingInfo({
|
||||
.renderExtent = drawImage.getExtent2D(),
|
||||
.colorImageView = drawImage.imageView,
|
||||
.colorImageClearValue = glm::vec4{0.f, 0.f, 0.f, 1.f},
|
||||
.depthImageView = depthImage.imageView,
|
||||
.depthImageClearValue = 0.f,
|
||||
});
|
||||
|
||||
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
|
||||
meshPipeline->draw(
|
||||
cmd,
|
||||
drawImage.getExtent2D(),
|
||||
gfxDevice,
|
||||
meshCache,
|
||||
materialCache,
|
||||
camera,
|
||||
sceneDataBuffer.getBuffer(),
|
||||
meshDrawCommands,
|
||||
sortedMeshDrawCommands);
|
||||
|
||||
vkCmdEndRendering(cmd);
|
||||
// vkutil::cmdEndLabel(cmd);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GameRenderer::cleanup() {
|
||||
}
|
||||
|
||||
void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialId materialId) {
|
||||
const auto& mesh = meshCache.getMesh(id);
|
||||
// const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false);
|
||||
assert(materialId != NULL_MATERIAL_ID);
|
||||
|
||||
meshDrawCommands.push_back(MeshDrawCommand{
|
||||
.meshId = id,
|
||||
.transformMatrix = transform,
|
||||
.materialId = materialId,
|
||||
});
|
||||
}
|
||||
|
||||
void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
|
||||
const glm::ivec2& drawImageSize,
|
||||
bool firstCreate)
|
||||
{
|
||||
const VkExtent3D drawImageExtent{
|
||||
.width = (std::uint32_t)drawImageSize.x,
|
||||
.height = (std::uint32_t)drawImageSize.y,
|
||||
.depth = 1,
|
||||
};
|
||||
|
||||
constexpr VkSampleCountFlagBits noMsaa = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
{ // setup draw image (single-sampled)
|
||||
VkImageUsageFlags usages{};
|
||||
usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
usages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
usages |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
auto createImageInfo = vkutil::CreateImageInfo{
|
||||
.format = drawImageFormat,
|
||||
.usage = usages,
|
||||
.extent = drawImageExtent,
|
||||
.samples = noMsaa,
|
||||
};
|
||||
|
||||
// reuse the same id if creating again
|
||||
drawImageId = gfxDevice.createImage(createImageInfo, "draw image", nullptr, drawImageId);
|
||||
|
||||
if (firstCreate) {
|
||||
// Optional: a separate post-fx target (ping-pong)
|
||||
// postFXDrawImageId = gfxDevice.createImage(createImageInfo, "post FX draw image");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // setup depth image (single-sampled)
|
||||
auto createInfo = vkutil::CreateImageInfo{
|
||||
.format = depthImageFormat,
|
||||
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
.extent = drawImageExtent,
|
||||
.samples = noMsaa,
|
||||
};
|
||||
|
||||
depthImageId = gfxDevice.createImage(createInfo, "depth image", nullptr, depthImageId);
|
||||
|
||||
}
|
||||
}
|
||||
1
destrum/src/Graphics/Resources/GPUImage.cpp
Normal file
1
destrum/src/Graphics/Resources/GPUImage.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include <destrum/Graphics/GPUImage.h>
|
||||
122
destrum/src/Graphics/Resources/NBuffer.cpp
Normal file
122
destrum/src/Graphics/Resources/NBuffer.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <destrum/Graphics/Resources/NBuffer.h>
|
||||
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
#include <destrum/Graphics/Util.h>
|
||||
|
||||
void NBuffer::init(
|
||||
GfxDevice& gfxDevice,
|
||||
VkBufferUsageFlags usage,
|
||||
std::size_t dataSize,
|
||||
const std::string& debugName)
|
||||
{
|
||||
assert(FRAMES_IN_FLIGHT > 0);
|
||||
assert(dataSize > 0);
|
||||
|
||||
framesInFlight = FRAMES_IN_FLIGHT;
|
||||
gpuBufferSize = dataSize;
|
||||
|
||||
gpuBuffer = gfxDevice.createBuffer(
|
||||
dataSize, usage | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
|
||||
vkutil::addDebugLabel(gfxDevice.getDevice(), gpuBuffer.buffer, debugName.c_str());
|
||||
|
||||
for (std::size_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
|
||||
stagingBuffers.push_back(gfxDevice.createBuffer(
|
||||
dataSize, usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST));
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void NBuffer::cleanup(GfxDevice& device)
|
||||
{
|
||||
for (const auto& stagingBuffer : stagingBuffers) {
|
||||
device.destroyBuffer(stagingBuffer);
|
||||
}
|
||||
stagingBuffers.clear();
|
||||
|
||||
device.destroyBuffer(gpuBuffer);
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
void NBuffer::uploadNewData(
|
||||
VkCommandBuffer cmd,
|
||||
std::size_t frameIndex,
|
||||
void* newData,
|
||||
std::size_t dataSize,
|
||||
std::size_t offset,
|
||||
bool sync) const
|
||||
{
|
||||
assert(initialized);
|
||||
assert(frameIndex < framesInFlight);
|
||||
assert(offset + dataSize <= gpuBufferSize && "NBuffer::uploadNewData: out of bounds write");
|
||||
|
||||
if (dataSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sync with previous read
|
||||
if (sync) {
|
||||
const auto bufferBarrier = VkBufferMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_READ_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
.buffer = gpuBuffer.buffer,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
};
|
||||
const auto dependencyInfo = VkDependencyInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &bufferBarrier,
|
||||
};
|
||||
vkCmdPipelineBarrier2(cmd, &dependencyInfo);
|
||||
}
|
||||
|
||||
auto& staging = stagingBuffers[frameIndex];
|
||||
auto* mappedData = reinterpret_cast<std::uint8_t*>(staging.info.pMappedData);
|
||||
memcpy((void*)&mappedData[offset], newData, dataSize);
|
||||
|
||||
const auto region = VkBufferCopy2{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2,
|
||||
.srcOffset = (VkDeviceSize)offset,
|
||||
.dstOffset = (VkDeviceSize)offset,
|
||||
.size = dataSize,
|
||||
};
|
||||
const auto bufCopyInfo = VkCopyBufferInfo2{
|
||||
.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2,
|
||||
.srcBuffer = staging.buffer,
|
||||
.dstBuffer = gpuBuffer.buffer,
|
||||
.regionCount = 1,
|
||||
.pRegions = ®ion,
|
||||
};
|
||||
|
||||
vkCmdCopyBuffer2(cmd, &bufCopyInfo);
|
||||
|
||||
if (sync) { // sync write
|
||||
const auto bufferBarrier = VkBufferMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
|
||||
.buffer = gpuBuffer.buffer,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
};
|
||||
const auto dependencyInfo = VkDependencyInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.bufferMemoryBarrierCount = 1,
|
||||
.pBufferMemoryBarriers = &bufferBarrier,
|
||||
};
|
||||
vkCmdPipelineBarrier2(cmd, &dependencyInfo);
|
||||
}
|
||||
}
|
||||
316
destrum/src/Graphics/Util.cpp
Normal file
316
destrum/src/Graphics/Util.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
#include <fstream>
|
||||
#include <destrum/Graphics/Init.h>
|
||||
#include <destrum/Graphics/Util.h>
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
void vkutil::transitionImage(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout) {
|
||||
VkImageAspectFlags aspectMask =
|
||||
(currentLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
|
||||
newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
|
||||
newLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) ?
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT :
|
||||
VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkImageMemoryBarrier2 imageBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
|
||||
.oldLayout = currentLayout,
|
||||
.newLayout = newLayout,
|
||||
.image = image,
|
||||
.subresourceRange = vkinit::imageSubresourceRange(aspectMask),
|
||||
};
|
||||
|
||||
VkDependencyInfo depInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageBarrier,
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier2(cmd, &depInfo);
|
||||
}
|
||||
|
||||
void vkutil::copyImageToImage(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize, VkFilter filter) {
|
||||
copyImageToImage(cmd, source, destination, srcSize, 0, 0, dstSize.width, dstSize.height, filter);
|
||||
}
|
||||
|
||||
void vkutil::copyImageToImage(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, int destX, int destY, int destW, int destH, VkFilter filter) {
|
||||
const auto blitRegion = VkImageBlit2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
|
||||
.srcSubresource =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffsets =
|
||||
{
|
||||
{},
|
||||
{(std::int32_t)srcSize.width, (std::int32_t)srcSize.height, 1},
|
||||
},
|
||||
.dstSubresource =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.dstOffsets =
|
||||
{
|
||||
{(std::int32_t)destX, (std::int32_t)destY},
|
||||
{(std::int32_t)(destX + destW), (std::int32_t)(destY + destH), 1},
|
||||
},
|
||||
};
|
||||
|
||||
const auto blitInfo = VkBlitImageInfo2{
|
||||
.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
|
||||
.srcImage = source,
|
||||
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.dstImage = destination,
|
||||
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.regionCount = 1,
|
||||
.pRegions = &blitRegion,
|
||||
.filter = filter,
|
||||
};
|
||||
|
||||
vkCmdBlitImage2(cmd, &blitInfo);
|
||||
}
|
||||
|
||||
void vkutil::addDebugLabel(VkDevice device, VkImage image, const char* label) {
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_IMAGE,
|
||||
.objectHandle = (std::uint64_t)image,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void vkutil::addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_BUFFER,
|
||||
.objectHandle = (std::uint64_t)buffer,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
vkutil::RenderInfo vkutil::createRenderingInfo(const RenderingInfoParams& params) {
|
||||
assert(
|
||||
(params.colorImageView || params.depthImageView != nullptr) &&
|
||||
"Either draw or depth image should be present");
|
||||
assert(
|
||||
params.renderExtent.width != 0.f && params.renderExtent.height != 0.f &&
|
||||
"renderExtent not specified");
|
||||
|
||||
RenderInfo ri;
|
||||
if (params.colorImageView) {
|
||||
ri.colorAttachment = VkRenderingAttachmentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||
.imageView = params.colorImageView,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.loadOp = params.colorImageClearValue ? VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
};
|
||||
if (params.colorImageClearValue) {
|
||||
const auto col = params.colorImageClearValue.value();
|
||||
ri.colorAttachment.clearValue.color = {col[0], col[1], col[2], col[3]};
|
||||
}
|
||||
}
|
||||
|
||||
if (params.depthImageView) {
|
||||
ri.depthAttachment = VkRenderingAttachmentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||
.imageView = params.depthImageView,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
|
||||
.loadOp = params.depthImageClearValue ? VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
};
|
||||
if (params.depthImageClearValue) {
|
||||
ri.depthAttachment.clearValue.depthStencil.depth = params.depthImageClearValue.value();
|
||||
}
|
||||
}
|
||||
|
||||
ri.renderingInfo = VkRenderingInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||
.renderArea =
|
||||
VkRect2D{
|
||||
.offset = {},
|
||||
.extent = params.renderExtent,
|
||||
},
|
||||
.layerCount = 1,
|
||||
.colorAttachmentCount = params.colorImageView ? 1u : 0u,
|
||||
.pColorAttachments = params.colorImageView ? &ri.colorAttachment : nullptr,
|
||||
.pDepthAttachment = params.depthImageView ? &ri.depthAttachment : nullptr,
|
||||
};
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
VkShaderModule vkutil::loadShaderModule(const std::filesystem::path& path, VkDevice device) {
|
||||
std::ifstream file(path, std::ios::ate | std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
spdlog::error("failed to open shader");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const auto fileSize = file.tellg();
|
||||
std::vector<std::uint32_t> buffer(fileSize / sizeof(std::uint32_t));
|
||||
|
||||
file.seekg(0);
|
||||
file.read((char*)buffer.data(), fileSize);
|
||||
file.close();
|
||||
|
||||
auto info = VkShaderModuleCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = buffer.size() * sizeof(std::uint32_t),
|
||||
.pCode = buffer.data(),
|
||||
};
|
||||
|
||||
VkShaderModule shaderModule;
|
||||
if (vkCreateShaderModule(device, &info, nullptr, &shaderModule) != VK_SUCCESS) {
|
||||
spdlog::error("Failed to load");
|
||||
std::exit(1);
|
||||
}
|
||||
return shaderModule;
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkImage image, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_IMAGE,
|
||||
.objectHandle = (std::uint64_t)image,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_IMAGE_VIEW,
|
||||
.objectHandle = (std::uint64_t)imageView,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
|
||||
.objectHandle = (std::uint64_t)shaderModule,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_PIPELINE,
|
||||
.objectHandle = (std::uint64_t)pipeline,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_PIPELINE_LAYOUT,
|
||||
.objectHandle = (std::uint64_t)layout,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_BUFFER,
|
||||
.objectHandle = (std::uint64_t)buffer,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label)
|
||||
{
|
||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_SAMPLER,
|
||||
.objectHandle = (std::uint64_t)sampler,
|
||||
.pObjectName = label,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||
}
|
||||
|
||||
vkutil::RenderInfo createRenderingInfo(const vkutil::RenderingInfoParams& params)
|
||||
{
|
||||
assert(
|
||||
(params.colorImageView || params.depthImageView != nullptr) &&
|
||||
"Either draw or depth image should be present");
|
||||
assert(
|
||||
params.renderExtent.width != 0.f && params.renderExtent.height != 0.f &&
|
||||
"renderExtent not specified");
|
||||
|
||||
vkutil::RenderInfo ri;
|
||||
if (params.colorImageView) {
|
||||
ri.colorAttachment = VkRenderingAttachmentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||
.imageView = params.colorImageView,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.loadOp = params.colorImageClearValue ? VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
};
|
||||
if (params.colorImageClearValue) {
|
||||
const auto col = params.colorImageClearValue.value();
|
||||
ri.colorAttachment.clearValue.color = {col[0], col[1], col[2], col[3]};
|
||||
}
|
||||
}
|
||||
|
||||
if (params.depthImageView) {
|
||||
ri.depthAttachment = VkRenderingAttachmentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||
.imageView = params.depthImageView,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
|
||||
.loadOp = params.depthImageClearValue ? VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
};
|
||||
if (params.depthImageClearValue) {
|
||||
ri.depthAttachment.clearValue.depthStencil.depth = params.depthImageClearValue.value();
|
||||
}
|
||||
}
|
||||
|
||||
ri.renderingInfo = VkRenderingInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||
.renderArea =
|
||||
VkRect2D{
|
||||
.offset = {},
|
||||
.extent = params.renderExtent,
|
||||
},
|
||||
.layerCount = 1,
|
||||
.colorAttachmentCount = params.colorImageView ? 1u : 0u,
|
||||
.pColorAttachments = params.colorImageView ? &ri.colorAttachment : nullptr,
|
||||
.pDepthAttachment = params.depthImageView ? &ri.depthAttachment : nullptr,
|
||||
};
|
||||
|
||||
return ri;
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
#include <destrum/Graphics/GfxDevice.h>
|
||||
|
||||
#include "destrum/Graphics/Util.h"
|
||||
|
||||
#define VOLK_IMPLEMENTATION
|
||||
#include <volk.h>
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/Init.h>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
GfxDevice::GfxDevice() {
|
||||
}
|
||||
|
||||
void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) {
|
||||
VK_CHECK(volkInitialize());
|
||||
|
||||
instance = vkb::InstanceBuilder{}
|
||||
.set_app_name(appName.c_str())
|
||||
.set_app_version(1, 0, 0)
|
||||
.request_validation_layers()
|
||||
.use_default_debug_messenger()
|
||||
.require_api_version(1, 3, 0)
|
||||
.build()
|
||||
.value();
|
||||
|
||||
volkLoadInstance(instance);
|
||||
|
||||
const auto res = SDL_Vulkan_CreateSurface(window, instance, &surface);
|
||||
if (res != SDL_TRUE) {
|
||||
spdlog::error("Failed to create Vulkan surface: {}", SDL_GetError());
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
constexpr auto deviceFeatures = VkPhysicalDeviceFeatures{
|
||||
.imageCubeArray = VK_TRUE,
|
||||
.geometryShader = VK_TRUE, // for im3d
|
||||
.depthClamp = VK_TRUE,
|
||||
.samplerAnisotropy = VK_TRUE,
|
||||
};
|
||||
|
||||
constexpr auto features12 = VkPhysicalDeviceVulkan12Features{
|
||||
.descriptorIndexing = true,
|
||||
.descriptorBindingSampledImageUpdateAfterBind = true,
|
||||
.descriptorBindingStorageImageUpdateAfterBind = true,
|
||||
.descriptorBindingPartiallyBound = true,
|
||||
.descriptorBindingVariableDescriptorCount = true,
|
||||
.runtimeDescriptorArray = true,
|
||||
.scalarBlockLayout = true,
|
||||
.bufferDeviceAddress = true,
|
||||
};
|
||||
constexpr auto features13 = VkPhysicalDeviceVulkan13Features{
|
||||
.synchronization2 = true,
|
||||
.dynamicRendering = true,
|
||||
};
|
||||
|
||||
physicalDevice = vkb::PhysicalDeviceSelector{instance}
|
||||
.set_minimum_version(1, 3)
|
||||
.set_required_features(deviceFeatures)
|
||||
.set_required_features_12(features12)
|
||||
.set_required_features_13(features13)
|
||||
.set_surface(surface)
|
||||
.select()
|
||||
.value();
|
||||
|
||||
device = vkb::DeviceBuilder{physicalDevice}.build().value();
|
||||
|
||||
graphicsQueueFamily = device.get_queue_index(vkb::QueueType::graphics).value();
|
||||
graphicsQueue = device.get_queue(vkb::QueueType::graphics).value();
|
||||
|
||||
//Vma
|
||||
const auto vulkanFunctions = VmaVulkanFunctions{
|
||||
.vkGetInstanceProcAddr = vkGetInstanceProcAddr,
|
||||
.vkGetDeviceProcAddr = vkGetDeviceProcAddr,
|
||||
};
|
||||
|
||||
const auto allocatorInfo = VmaAllocatorCreateInfo{
|
||||
.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
||||
.physicalDevice = physicalDevice,
|
||||
.device = device,
|
||||
.pVulkanFunctions = &vulkanFunctions,
|
||||
.instance = instance,
|
||||
};
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
|
||||
executor.init(device, graphicsQueueFamily, graphicsQueue);
|
||||
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
swapchainFormat = VK_FORMAT_B8G8R8A8_SRGB;
|
||||
swapchain.createSwapchain(this, swapchainFormat, w, h, vSync);
|
||||
|
||||
swapchain.initSync(device);
|
||||
|
||||
const auto poolCreateInfo = vkinit::commandPoolCreateInfo(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, graphicsQueueFamily);
|
||||
|
||||
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
|
||||
auto& commandPool = frames[i].commandPool;
|
||||
VK_CHECK(vkCreateCommandPool(device, &poolCreateInfo, nullptr, &commandPool));
|
||||
|
||||
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
|
||||
auto& mainCommandBuffer = frames[i].commandBuffer;
|
||||
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
||||
}
|
||||
//
|
||||
// { // create white texture
|
||||
// std::uint32_t pixel = 0xFFFFFFFF;
|
||||
// whiteImageId = createImage(
|
||||
// {
|
||||
// .format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
// .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
// .extent = VkExtent3D{1, 1, 1},
|
||||
// },
|
||||
// "white texture",
|
||||
// &pixel);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void GfxDevice::recreateSwapchain(int width, int height) {
|
||||
assert(width != 0 && height != 0);
|
||||
waitIdle();
|
||||
swapchain.recreateSwapchain(*this, swapchainFormat, width, height, false);
|
||||
}
|
||||
|
||||
VkCommandBuffer GfxDevice::beginFrame() {
|
||||
swapchain.beginFrame(getCurrentFrameIndex());
|
||||
|
||||
const auto& frame = getCurrentFrame();
|
||||
const auto& cmd = frame.commandBuffer;
|
||||
const auto cmdBeginInfo = VkCommandBufferBeginInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void GfxDevice::endFrame(VkCommandBuffer cmd, const VImage& drawImage, const EndFrameProps& props) {
|
||||
// get swapchain image
|
||||
const auto [swapchainImage, swapchainImageIndex] = swapchain.acquireNextImage(getCurrentFrameIndex());
|
||||
if (swapchainImage == VK_NULL_HANDLE) {
|
||||
std::printf("Swapchain is dirty, skipping frame...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fences are reset here to prevent the deadlock in case swapchain becomes dirty
|
||||
swapchain.resetFences(getCurrentFrameIndex());
|
||||
|
||||
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
{
|
||||
// clear swapchain image
|
||||
VkImageSubresourceRange clearRange =
|
||||
vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
VkClearColorValue clearValue;
|
||||
static int superFrameNumber = 0;
|
||||
superFrameNumber += 1;
|
||||
if (superFrameNumber > 255) {
|
||||
superFrameNumber = 0;
|
||||
}
|
||||
float flash = std::abs(std::sin(superFrameNumber * 0.1f));
|
||||
clearValue = { { 0.0f, 0.0f, flash, 1.0f } };
|
||||
|
||||
// const auto clearValue = props.clearColor;
|
||||
vkCmdClearColorImage(cmd, swapchainImage, VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange);
|
||||
}
|
||||
|
||||
// if (props.copyImageIntoSwapchain) {
|
||||
// copy from draw image into swapchain
|
||||
// vkutil::transitionImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
|
||||
// VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
vkutil::transitionImage(
|
||||
cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
// const auto filter = props.drawImageLinearBlit ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||
const auto filter = VK_FILTER_LINEAR;
|
||||
// // if (props.drawImageBlitRect != glm::ivec4{}) {
|
||||
// vkutil::copyImageToImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// swapchainImage,
|
||||
// drawImage.getExtent2D(),
|
||||
// props.drawImageBlitRect.x,
|
||||
// props.drawImageBlitRect.y,
|
||||
// props.drawImageBlitRect.z,
|
||||
// props.drawImageBlitRect.w,
|
||||
// filter);
|
||||
// } else {
|
||||
// // will stretch image to swapchain
|
||||
// vkutil::copyImageToImage(
|
||||
// cmd,
|
||||
// drawImage.getImage(),
|
||||
// swapchainImage,
|
||||
// drawImage.getExtent2D(),
|
||||
// getSwapchainExtent(),
|
||||
// filter);
|
||||
// }
|
||||
|
||||
// prepare for present
|
||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VK_CHECK(vkEndCommandBuffer(cmd));
|
||||
|
||||
// swapchain.submitAndPresent(cmd, graphicsQueue, getCurrentFrameIndex(), swapchainImageIndex);
|
||||
swapchain.submitAndPresent(cmd, graphicsQueue, swapchainImageIndex, getCurrentFrameIndex());
|
||||
|
||||
frameNumber++;
|
||||
}
|
||||
|
||||
void GfxDevice::cleanup() {
|
||||
}
|
||||
|
||||
void GfxDevice::waitIdle() {
|
||||
VK_CHECK(vkDeviceWaitIdle(device));
|
||||
}
|
||||
|
||||
void GfxDevice::immediateSubmit(ImmediateExecuteFunction&& f) const {
|
||||
executor.immediateSubmit(std::move(f));
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include <destrum/Graphics/MeshCache.h>
|
||||
@@ -1,79 +0,0 @@
|
||||
#include <destrum/Graphics/Init.h>
|
||||
#include <destrum/Graphics/Util.h>
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
void vkutil::transitionImage(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout) {
|
||||
VkImageAspectFlags aspectMask =
|
||||
(currentLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
|
||||
newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
|
||||
newLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) ?
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT :
|
||||
VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkImageMemoryBarrier2 imageBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
|
||||
.oldLayout = currentLayout,
|
||||
.newLayout = newLayout,
|
||||
.image = image,
|
||||
.subresourceRange = vkinit::imageSubresourceRange(aspectMask),
|
||||
};
|
||||
|
||||
VkDependencyInfo depInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageBarrier,
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier2(cmd, &depInfo);
|
||||
}
|
||||
|
||||
void vkutil::copyImageToImage(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize, VkFilter filter) {
|
||||
copyImageToImage(cmd, source, destination, srcSize, 0, 0, dstSize.width, dstSize.height, filter);
|
||||
}
|
||||
|
||||
void vkutil::copyImageToImage(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, int destX, int destY, int destW, int destH, VkFilter filter) {
|
||||
const auto blitRegion = VkImageBlit2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
|
||||
.srcSubresource =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffsets =
|
||||
{
|
||||
{},
|
||||
{(std::int32_t)srcSize.width, (std::int32_t)srcSize.height, 1},
|
||||
},
|
||||
.dstSubresource =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.dstOffsets =
|
||||
{
|
||||
{(std::int32_t)destX, (std::int32_t)destY},
|
||||
{(std::int32_t)(destX + destW), (std::int32_t)(destY + destH), 1},
|
||||
},
|
||||
};
|
||||
|
||||
const auto blitInfo = VkBlitImageInfo2{
|
||||
.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
|
||||
.srcImage = source,
|
||||
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.dstImage = destination,
|
||||
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.regionCount = 1,
|
||||
.pRegions = &blitRegion,
|
||||
.filter = filter,
|
||||
};
|
||||
|
||||
vkCmdBlitImage2(cmd, &blitInfo);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include <destrum/Graphics/VImage.h>
|
||||
Reference in New Issue
Block a user