Compare commits
2 Commits
906290edfa
...
5b9be907ba
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b9be907ba | |||
| f19e59f819 |
@@ -32,8 +32,11 @@ endfunction()
|
|||||||
add_executable(vk_expe
|
add_executable(vk_expe
|
||||||
src/Vulkan/Context.cpp
|
src/Vulkan/Context.cpp
|
||||||
src/Vulkan/Swapchain.cpp
|
src/Vulkan/Swapchain.cpp
|
||||||
|
src/Vulkan/Memory.cpp
|
||||||
|
src/Vulkan/Buffer.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/utils.cpp
|
src/utils.cpp
|
||||||
|
src/Simplex.cpp
|
||||||
src/Logger.cpp
|
src/Logger.cpp
|
||||||
src/Planet.cpp
|
src/Planet.cpp
|
||||||
src/VkExpe.cpp
|
src/VkExpe.cpp
|
||||||
|
|||||||
141
src/Simplex.cpp
Normal file
141
src/Simplex.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
#include <Simplex.h>
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 polyhedron_support(Vector3AV polyhedron, const Vector3& direction) {
|
||||||
|
assert(polyhedron.size() > 0);
|
||||||
|
|
||||||
|
Index best = 0;
|
||||||
|
Real best_dot = polyhedron[0].dot(direction);
|
||||||
|
|
||||||
|
for (Index index = 1; index < polyhedron.size(); index += 1) {
|
||||||
|
Real dot = polyhedron[index].dot(direction);
|
||||||
|
if (dot > best_dot) {
|
||||||
|
best = index;
|
||||||
|
best_dot = dot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return polyhedron[best];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Simplex::Simplex() = default;
|
||||||
|
Simplex::Simplex(const Vector3& point)
|
||||||
|
: m_points{ point, Vector3{}, Vector3{}, Vector3{} }
|
||||||
|
, m_point_count(1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Gjk::Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction)
|
||||||
|
: m_polyhedron0(polyhedron0)
|
||||||
|
, m_polyhedron1(polyhedron1)
|
||||||
|
, m_direction(direction)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Gjk::~Gjk() = default;
|
||||||
|
|
||||||
|
const Vector3& Gjk::direction() const {
|
||||||
|
return m_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::operator()() {
|
||||||
|
while (true) {
|
||||||
|
m_simplex.push(support(m_direction));
|
||||||
|
|
||||||
|
if (m_simplex.last().dot(m_direction) < Real(0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (nextSimplex())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::nextSimplex() {
|
||||||
|
switch(m_simplex.point_count()) {
|
||||||
|
case 1: return nextFromPoint();
|
||||||
|
case 2: return nextFromLine();
|
||||||
|
case 3: return nextFromTriangle();
|
||||||
|
case 4: return nextFromTetrahedron();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::nextFromPoint() {
|
||||||
|
m_direction = -m_simplex.last();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::nextFromLine() {
|
||||||
|
Vector3 v01 = m_simplex.point(1) - m_simplex.point(0);
|
||||||
|
Vector3 v1o = -m_simplex.point(1);
|
||||||
|
|
||||||
|
m_direction = v01.cross(v1o).cross(v01);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::nextFromTriangle() {
|
||||||
|
Vector3 v20 = m_simplex.point(0) - m_simplex.point(2);
|
||||||
|
Vector3 v21 = m_simplex.point(1) - m_simplex.point(2);
|
||||||
|
Vector3 v2o = -m_simplex.point(2);
|
||||||
|
|
||||||
|
Vector3 n = v20.cross(v21);
|
||||||
|
Vector3 n0 = n.cross(v21);
|
||||||
|
Vector3 n1 = v20.cross(n);
|
||||||
|
|
||||||
|
if(n0.dot(v2o) > Real(0)) {
|
||||||
|
m_simplex.pop(0);
|
||||||
|
m_direction = n0;
|
||||||
|
}
|
||||||
|
else if(n1.dot(v2o) > Real(0)) {
|
||||||
|
m_simplex.pop(1);
|
||||||
|
m_direction = n1;
|
||||||
|
}
|
||||||
|
else if(n.dot(v2o) > Real(0)) {
|
||||||
|
m_direction = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_simplex.swap(0, 1);
|
||||||
|
m_direction = -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gjk::nextFromTetrahedron() {
|
||||||
|
Vector3 v30 = m_simplex.point(0) - m_simplex.point(3);
|
||||||
|
Vector3 v31 = m_simplex.point(1) - m_simplex.point(3);
|
||||||
|
Vector3 v32 = m_simplex.point(2) - m_simplex.point(3);
|
||||||
|
Vector3 v3o = -m_simplex.point(3);
|
||||||
|
|
||||||
|
Vector3 n[3] = {
|
||||||
|
v31.cross(v32),
|
||||||
|
v32.cross(v30),
|
||||||
|
v30.cross(v31),
|
||||||
|
};
|
||||||
|
|
||||||
|
Real d[3] = {
|
||||||
|
n[0].dot(v3o),
|
||||||
|
n[1].dot(v3o),
|
||||||
|
n[2].dot(v3o),
|
||||||
|
};
|
||||||
|
|
||||||
|
Index best = (d[0] > d[1])? ((d[0] > d[2])? 0: 2):
|
||||||
|
((d[1] > d[2])? 1: 2);
|
||||||
|
|
||||||
|
if(d[best] <= Real(0))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
m_simplex.pop(best);
|
||||||
|
m_direction = n[best];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Gjk::support(const Vector3& direction) const
|
||||||
|
{
|
||||||
|
return polyhedron_support(m_polyhedron0, direction)
|
||||||
|
- polyhedron_support(m_polyhedron1, -direction);
|
||||||
|
}
|
||||||
75
src/Simplex.h
Normal file
75
src/Simplex.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <core.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Simplex {
|
||||||
|
public:
|
||||||
|
Simplex();
|
||||||
|
Simplex(const Vector3& point);
|
||||||
|
|
||||||
|
inline Index point_count() const {
|
||||||
|
return m_point_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vector3& point(Index index) const {
|
||||||
|
assert(index < m_point_count);
|
||||||
|
return m_points[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vector3& last() const {
|
||||||
|
assert(m_point_count > 0);
|
||||||
|
return point(m_point_count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void push(const Vector3& point) {
|
||||||
|
assert(m_point_count < MaxPointCount);
|
||||||
|
m_points[m_point_count] = point;
|
||||||
|
m_point_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void pop(Index index) {
|
||||||
|
assert(index < m_point_count);
|
||||||
|
for(Index i = index; i + 1 < m_point_count; i += 1)
|
||||||
|
m_points[i] = m_points[i + 1];
|
||||||
|
m_point_count -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swap(Index index0, Index index1) {
|
||||||
|
using std::swap;
|
||||||
|
swap(m_points[index0], m_points[index1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr Index MaxPointCount = 4;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 m_points[MaxPointCount];
|
||||||
|
Index m_point_count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Gjk {
|
||||||
|
public:
|
||||||
|
Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction=Vector3::UnitX());
|
||||||
|
~Gjk();
|
||||||
|
|
||||||
|
const Vector3& direction() const;
|
||||||
|
|
||||||
|
bool operator()();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool nextSimplex();
|
||||||
|
bool nextFromPoint();
|
||||||
|
bool nextFromLine();
|
||||||
|
bool nextFromTriangle();
|
||||||
|
bool nextFromTetrahedron();
|
||||||
|
|
||||||
|
Vector3 support(const Vector3& direction) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3AV m_polyhedron0;
|
||||||
|
Vector3AV m_polyhedron1;
|
||||||
|
Simplex m_simplex;
|
||||||
|
Vector3 m_direction;
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
|
||||||
void SdlWindowDeleter::operator()(SDL_Window* window) const {
|
void SdlWindowDeleter::operator()(SDL_Window* window) const {
|
||||||
@@ -25,7 +26,7 @@ void VkExpe::initialize() {
|
|||||||
auto const window = SDL_CreateWindow(
|
auto const window = SDL_CreateWindow(
|
||||||
"vk_expe",
|
"vk_expe",
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
800, 600,
|
1920, 1080,
|
||||||
SDL_WINDOW_VULKAN
|
SDL_WINDOW_VULKAN
|
||||||
| SDL_WINDOW_ALLOW_HIGHDPI
|
| SDL_WINDOW_ALLOW_HIGHDPI
|
||||||
| SDL_WINDOW_SHOWN
|
| SDL_WINDOW_SHOWN
|
||||||
@@ -60,6 +61,8 @@ void VkExpe::run() {
|
|||||||
m_running = false;
|
m_running = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto last_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while(m_running) {
|
while(m_running) {
|
||||||
while(SDL_PollEvent(&event)) {
|
while(SDL_PollEvent(&event)) {
|
||||||
@@ -72,17 +75,88 @@ void VkExpe::run() {
|
|||||||
m_running = false;
|
m_running = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SDL_MOUSEMOTION: {
|
||||||
|
m_mouse_offset += Vector2(
|
||||||
|
event.motion.xrel,
|
||||||
|
event.motion.yrel
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
switch(event.window.event) {
|
switch(event.window.event) {
|
||||||
case SDL_WINDOWEVENT_RESIZED: {
|
case SDL_WINDOWEVENT_RESIZED: {
|
||||||
m_vulkan.invalidate_swapchain();
|
m_vulkan.invalidate_swapchain();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_GAINED: {
|
||||||
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_LOST: {
|
||||||
|
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto new_time = std::chrono::high_resolution_clock::now();
|
||||||
|
const auto elapsed = new_time - last_time;
|
||||||
|
last_time = new_time;
|
||||||
|
|
||||||
|
update(std::chrono::duration<double>(elapsed).count());
|
||||||
|
|
||||||
|
m_vulkan.set_camera(m_camera_position, m_camera_z, m_camera_y);
|
||||||
m_vulkan.draw_frame();
|
m_vulkan.draw_frame();
|
||||||
// m_running = false;
|
|
||||||
|
m_mouse_offset = Vector2::Zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkExpe::update(double elapsed) {
|
||||||
|
int key_count = 0;
|
||||||
|
const auto keys = SDL_GetKeyboardState(&key_count);
|
||||||
|
|
||||||
|
const auto test_key = [key_count, keys](int scan_code) {
|
||||||
|
return scan_code < key_count && keys[scan_code];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!m_mouse_offset.isZero()) {
|
||||||
|
const Real x_sensi = 0.001;
|
||||||
|
const Real y_sensi = -0.001;
|
||||||
|
|
||||||
|
const Vector3 camera_x = m_camera_y.cross(m_camera_z);
|
||||||
|
Vector3 axis =
|
||||||
|
x_sensi * m_mouse_offset[0] * m_camera_y +
|
||||||
|
y_sensi * m_mouse_offset[1] * camera_x;
|
||||||
|
Real rot_norm = axis.norm();
|
||||||
|
AngleAxis rot(rot_norm, axis / rot_norm);
|
||||||
|
m_camera_y = rot * m_camera_y;
|
||||||
|
m_camera_z = rot * m_camera_z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 walk_direction = Vector3::Zero();
|
||||||
|
if(test_key(SDL_SCANCODE_W))
|
||||||
|
walk_direction += Vector3::UnitZ();
|
||||||
|
if(test_key(SDL_SCANCODE_S))
|
||||||
|
walk_direction -= Vector3::UnitZ();
|
||||||
|
if(test_key(SDL_SCANCODE_A))
|
||||||
|
walk_direction -= Vector3::UnitX();
|
||||||
|
if(test_key(SDL_SCANCODE_D))
|
||||||
|
walk_direction += Vector3::UnitX();
|
||||||
|
if(test_key(SDL_SCANCODE_SPACE))
|
||||||
|
walk_direction -= Vector3::UnitY();
|
||||||
|
if(test_key(SDL_SCANCODE_LCTRL))
|
||||||
|
walk_direction += Vector3::UnitY();
|
||||||
|
|
||||||
|
if(!walk_direction.isZero()) {
|
||||||
|
walk_direction.normalize();
|
||||||
|
const Real base_velocity = 1;
|
||||||
|
|
||||||
|
Matrix3 camera_basis;
|
||||||
|
camera_basis << m_camera_y.cross(m_camera_z), m_camera_y, m_camera_z;
|
||||||
|
m_camera_position += elapsed * base_velocity * (camera_basis * walk_direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/VkExpe.h
10
src/VkExpe.h
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <core.h>
|
||||||
#include <VulkanTutorial.h>
|
#include <VulkanTutorial.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
@@ -26,8 +27,17 @@ public:
|
|||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
void update(double elapsed);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VulkanTutorial m_vulkan;
|
VulkanTutorial m_vulkan;
|
||||||
|
|
||||||
|
Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f);
|
||||||
|
Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f);
|
||||||
|
Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
WindowUP m_window;
|
WindowUP m_window;
|
||||||
bool m_running = false;
|
bool m_running = false;
|
||||||
|
|
||||||
|
Vector2 m_mouse_offset = Vector2::Zero();
|
||||||
};
|
};
|
||||||
|
|||||||
186
src/Vulkan/Buffer.cpp
Normal file
186
src/Vulkan/Buffer.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include <Vulkan/Buffer.h>
|
||||||
|
#include <Vulkan/Context.h>
|
||||||
|
#include <Logger.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
|
||||||
|
Buffer::Buffer() noexcept {
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::Buffer(
|
||||||
|
Context& context,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkBufferUsageFlags usage
|
||||||
|
)
|
||||||
|
: m_context(&context)
|
||||||
|
{
|
||||||
|
assert(*m_context);
|
||||||
|
|
||||||
|
VkBufferCreateInfo create_info {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
|
.size = size,
|
||||||
|
.usage = usage,
|
||||||
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
};
|
||||||
|
if(vkCreateBuffer(
|
||||||
|
m_context->device(),
|
||||||
|
&create_info,
|
||||||
|
nullptr,
|
||||||
|
&m_buffer
|
||||||
|
) != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("failed to create buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::Buffer(
|
||||||
|
Context& context,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkBufferUsageFlags usage,
|
||||||
|
VkMemoryPropertyFlags memory_properties
|
||||||
|
)
|
||||||
|
: Buffer(context, size, usage)
|
||||||
|
{
|
||||||
|
allocate_and_bind_memory(memory_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::Buffer(Buffer&& other) noexcept
|
||||||
|
: m_context(other.m_context)
|
||||||
|
, m_buffer(other.m_buffer)
|
||||||
|
, m_memory(std::move(other.m_memory))
|
||||||
|
{
|
||||||
|
other.m_context = nullptr;
|
||||||
|
other.m_buffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::~Buffer() noexcept {
|
||||||
|
if(is_valid()) {
|
||||||
|
logger.warning() << "Buffer deleted before being destroyed";
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer& Buffer::operator=(Buffer&& other) noexcept {
|
||||||
|
if(&other != this) {
|
||||||
|
using std::swap;
|
||||||
|
swap(m_context, other.m_context);
|
||||||
|
swap(m_buffer, other.m_buffer);
|
||||||
|
swap(m_memory, other.m_memory);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkMemoryRequirements Buffer::memory_requirements() const noexcept {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(*m_context);
|
||||||
|
|
||||||
|
VkMemoryRequirements memory_requirements;
|
||||||
|
vkGetBufferMemoryRequirements(
|
||||||
|
m_context->device(),
|
||||||
|
m_buffer,
|
||||||
|
&memory_requirements
|
||||||
|
);
|
||||||
|
|
||||||
|
return memory_requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::bind_memory(const MemoryBlock& memory_block, VkDeviceSize offset) {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(*m_context);
|
||||||
|
assert(memory_block);
|
||||||
|
|
||||||
|
// m_memory = std::move(memory_block);
|
||||||
|
if(vkBindBufferMemory(
|
||||||
|
m_context->device(),
|
||||||
|
m_buffer,
|
||||||
|
memory_block.device_memory(),
|
||||||
|
memory_block.offset() + offset
|
||||||
|
) != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("failed to bind buffer memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::bind_memory(MemoryBlock&& memory_block) {
|
||||||
|
bind_memory(memory_block);
|
||||||
|
m_memory = std::move(memory_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::allocate_and_bind_memory(VkMemoryPropertyFlags memory_properties) {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(*m_context);
|
||||||
|
|
||||||
|
const auto memory_requirements = this->memory_requirements();
|
||||||
|
m_memory = m_context->allocator().allocate(
|
||||||
|
memory_requirements.size,
|
||||||
|
memory_requirements.memoryTypeBits,
|
||||||
|
memory_properties
|
||||||
|
);
|
||||||
|
|
||||||
|
bind_memory(m_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::upload(size_t size, void* src_buffer, uint32_t dst_queue_family) {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(*m_context);
|
||||||
|
|
||||||
|
const bool use_staging_buffer =
|
||||||
|
(m_memory.memory_type_info(*m_context).propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0;
|
||||||
|
|
||||||
|
if(use_staging_buffer) {
|
||||||
|
auto staging_buffer = Buffer(
|
||||||
|
*m_context,
|
||||||
|
size,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||||
|
);
|
||||||
|
|
||||||
|
void* dst_buffer = staging_buffer.memory().map(*m_context);
|
||||||
|
std::memcpy(dst_buffer, src_buffer, size);
|
||||||
|
staging_buffer.memory().unmap(*m_context);
|
||||||
|
|
||||||
|
m_context->copy_buffer(
|
||||||
|
m_buffer,
|
||||||
|
staging_buffer,
|
||||||
|
dst_queue_family,
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
staging_buffer.destroy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
void* dst_buffer = m_memory.map(*m_context);
|
||||||
|
std::memcpy(dst_buffer, src_buffer, size);
|
||||||
|
m_memory.unmap(*m_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::destroy() noexcept {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(*m_context);
|
||||||
|
|
||||||
|
if(m_memory) {
|
||||||
|
m_memory.free();
|
||||||
|
m_memory = MemoryBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyBuffer(
|
||||||
|
m_context->device(),
|
||||||
|
m_buffer,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
m_context = nullptr;
|
||||||
|
m_buffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
87
src/Vulkan/Buffer.h
Normal file
87
src/Vulkan/Buffer.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils.h>
|
||||||
|
|
||||||
|
#include <Vulkan/forward.h>
|
||||||
|
#include <Vulkan/Memory.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
|
||||||
|
class Buffer {
|
||||||
|
public:
|
||||||
|
Buffer() noexcept;
|
||||||
|
Buffer(
|
||||||
|
Context& context,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkBufferUsageFlags usage
|
||||||
|
);
|
||||||
|
Buffer(
|
||||||
|
Context& context,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkBufferUsageFlags usage,
|
||||||
|
VkMemoryPropertyFlags memory_properties
|
||||||
|
);
|
||||||
|
Buffer(const Buffer&) = delete;
|
||||||
|
Buffer(Buffer&& other) noexcept;
|
||||||
|
~Buffer() noexcept;
|
||||||
|
|
||||||
|
Buffer& operator=(const Buffer&) = delete;
|
||||||
|
Buffer& operator=(Buffer&& other) noexcept;
|
||||||
|
|
||||||
|
inline explicit operator bool() const {
|
||||||
|
return is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid() const {
|
||||||
|
return m_buffer != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Context* context() noexcept {
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Context* context() const noexcept {
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator VkBuffer() const noexcept {
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkBuffer buffer() const noexcept {
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const MemoryBlock& memory() const noexcept {
|
||||||
|
return m_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MemoryBlock& memory() noexcept {
|
||||||
|
return m_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements memory_requirements() const noexcept;
|
||||||
|
|
||||||
|
void bind_memory(const MemoryBlock& memory_block, VkDeviceSize offset=0);
|
||||||
|
void bind_memory(MemoryBlock&& memory_block);
|
||||||
|
void allocate_and_bind_memory(VkMemoryPropertyFlags memory_properties);
|
||||||
|
|
||||||
|
void upload(size_t size, void* src_buffer, uint32_t dst_queue_family);
|
||||||
|
|
||||||
|
void destroy() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Context* m_context = nullptr;
|
||||||
|
VkBuffer m_buffer = VK_NULL_HANDLE;
|
||||||
|
MemoryBlock m_memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <Vulkan/Context.h>
|
#include <Vulkan/Context.h>
|
||||||
|
#include <Vulkan/Memory.h>
|
||||||
|
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
@@ -122,6 +123,8 @@ void Context::initialize(const ContextSettings& settings) {
|
|||||||
choose_physical_device(settings);
|
choose_physical_device(settings);
|
||||||
create_device(settings);
|
create_device(settings);
|
||||||
create_internal_objects();
|
create_internal_objects();
|
||||||
|
|
||||||
|
m_allocator.reset(new Allocator(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::shutdown() {
|
void Context::shutdown() {
|
||||||
@@ -133,6 +136,9 @@ void Context::shutdown() {
|
|||||||
for(auto& callback: m_context_destruction_callbacks)
|
for(auto& callback: m_context_destruction_callbacks)
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
|
m_allocator->free_all_pages();
|
||||||
|
m_allocator.reset();
|
||||||
|
|
||||||
destroy_fence(m_transfer_fence);
|
destroy_fence(m_transfer_fence);
|
||||||
destroy_command_pool(m_transfer_command_pool);
|
destroy_command_pool(m_transfer_command_pool);
|
||||||
|
|
||||||
@@ -274,124 +280,6 @@ VkShaderModule Context::create_shader_module_from_file(const char* path) {
|
|||||||
return VK_NULL_HANDLE;
|
return VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Context::find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) {
|
|
||||||
for(uint32_t type_index = 0; type_index < m_memory_properties.memoryTypeCount; type_index += 1) {
|
|
||||||
if(((1 << type_index) & type_filter) &&
|
|
||||||
(m_memory_properties.memoryTypes[type_index].propertyFlags & properties) == properties)
|
|
||||||
return type_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceMemory Context::allocate_memory(VkDeviceSize size, uint32_t type_filter, VkMemoryPropertyFlags properties) {
|
|
||||||
uint32_t memory_type = find_memory_type(type_filter, properties);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo malloc_info {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
||||||
.allocationSize = size,
|
|
||||||
.memoryTypeIndex = memory_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
if(vkAllocateMemory(m_device, &malloc_info, nullptr, &memory) != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("failed to allocate device memory");
|
|
||||||
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<VkBuffer, VkDeviceMemory> Context::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_properties) {
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkBufferCreateInfo buffer_info {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
||||||
.size = size,
|
|
||||||
.usage = usage,
|
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
||||||
};
|
|
||||||
|
|
||||||
if(vkCreateBuffer(
|
|
||||||
m_device,
|
|
||||||
&buffer_info,
|
|
||||||
nullptr,
|
|
||||||
&buffer
|
|
||||||
) != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("failed to create buffer");
|
|
||||||
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetBufferMemoryRequirements(
|
|
||||||
m_device,
|
|
||||||
buffer,
|
|
||||||
&memory_requirements
|
|
||||||
);
|
|
||||||
|
|
||||||
memory = allocate_memory(
|
|
||||||
memory_requirements.size,
|
|
||||||
memory_requirements.memoryTypeBits,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
||||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
|
||||||
);
|
|
||||||
|
|
||||||
vkBindBufferMemory(m_device, buffer, memory, 0);
|
|
||||||
|
|
||||||
return { buffer, memory };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<VkBuffer, VkDeviceMemory> Context::create_buffer(
|
|
||||||
VkDeviceSize size, char* data,
|
|
||||||
VkBufferUsageFlags usage,
|
|
||||||
VkMemoryPropertyFlags memory_properties,
|
|
||||||
uint32_t dst_queue_family
|
|
||||||
) {
|
|
||||||
VkBuffer tmp_buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory tmp_buffer_memory = VK_NULL_HANDLE;
|
|
||||||
std::tie(tmp_buffer, tmp_buffer_memory) = create_buffer(
|
|
||||||
size,
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
||||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
|
||||||
);
|
|
||||||
auto const tmp_buffer_guard = make_guard([&] {
|
|
||||||
free_memory(tmp_buffer_memory);
|
|
||||||
destroy_buffer(tmp_buffer);
|
|
||||||
});
|
|
||||||
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory buffer_memory = VK_NULL_HANDLE;
|
|
||||||
std::tie(buffer, buffer_memory) = create_buffer(
|
|
||||||
size,
|
|
||||||
usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
memory_properties
|
|
||||||
);
|
|
||||||
|
|
||||||
void* device_buffer = nullptr;
|
|
||||||
vkMapMemory(
|
|
||||||
m_device,
|
|
||||||
tmp_buffer_memory,
|
|
||||||
0,
|
|
||||||
size,
|
|
||||||
0,
|
|
||||||
&device_buffer
|
|
||||||
);
|
|
||||||
|
|
||||||
memcpy(device_buffer, data, size_t(size));
|
|
||||||
|
|
||||||
vkUnmapMemory(
|
|
||||||
m_device,
|
|
||||||
tmp_buffer_memory
|
|
||||||
);
|
|
||||||
|
|
||||||
copy_buffer(
|
|
||||||
buffer,
|
|
||||||
tmp_buffer,
|
|
||||||
dst_queue_family,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
return std::make_tuple(buffer, buffer_memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size) {
|
void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size) {
|
||||||
VkCommandBufferAllocateInfo alloc_info {
|
VkCommandBufferAllocateInfo alloc_info {
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
|
#include <Vulkan/forward.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
@@ -61,6 +62,14 @@ public:
|
|||||||
|
|
||||||
Context& operator=(const Context&) = delete;
|
Context& operator=(const Context&) = delete;
|
||||||
|
|
||||||
|
explicit inline operator bool() const {
|
||||||
|
return is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid() const {
|
||||||
|
return m_instance != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
VkInstance instance();
|
VkInstance instance();
|
||||||
VkPhysicalDevice physical_device();
|
VkPhysicalDevice physical_device();
|
||||||
VkDevice device();
|
VkDevice device();
|
||||||
@@ -70,11 +79,19 @@ public:
|
|||||||
VkQueue queue(size_t queue_index);
|
VkQueue queue(size_t queue_index);
|
||||||
VkQueue presentation_queue();
|
VkQueue presentation_queue();
|
||||||
|
|
||||||
|
inline VkPhysicalDeviceMemoryProperties memory_properties() const noexcept {
|
||||||
|
return m_memory_properties;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Window* window();
|
SDL_Window* window();
|
||||||
VkSurfaceKHR surface();
|
VkSurfaceKHR surface();
|
||||||
VkSurfaceFormatKHR surface_format() const;
|
VkSurfaceFormatKHR surface_format() const;
|
||||||
VkPresentModeKHR present_mode() const;
|
VkPresentModeKHR present_mode() const;
|
||||||
|
|
||||||
|
inline Allocator& allocator() noexcept {
|
||||||
|
return *m_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void initialize(const ContextSettings& settings);
|
void initialize(const ContextSettings& settings);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
@@ -100,18 +117,6 @@ public:
|
|||||||
VkShaderModule create_shader_module(const std::vector<char> bytecode);
|
VkShaderModule create_shader_module(const std::vector<char> bytecode);
|
||||||
VkShaderModule create_shader_module_from_file(const char* path);
|
VkShaderModule create_shader_module_from_file(const char* path);
|
||||||
|
|
||||||
int32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties);
|
|
||||||
VkDeviceMemory allocate_memory(VkDeviceSize size, uint32_t type_filter, VkMemoryPropertyFlags properties);
|
|
||||||
|
|
||||||
std::tuple<VkBuffer, VkDeviceMemory> create_buffer(
|
|
||||||
VkDeviceSize size,
|
|
||||||
VkBufferUsageFlags usage,
|
|
||||||
VkMemoryPropertyFlags memory_properties);
|
|
||||||
std::tuple<VkBuffer, VkDeviceMemory> create_buffer(
|
|
||||||
VkDeviceSize size, char* buffer,
|
|
||||||
VkBufferUsageFlags usage,
|
|
||||||
VkMemoryPropertyFlags memory_properties,
|
|
||||||
uint32_t dst_queue_family);
|
|
||||||
void copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size);
|
void copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size);
|
||||||
|
|
||||||
|
|
||||||
@@ -189,6 +194,8 @@ private:
|
|||||||
VkFence m_transfer_fence = VK_NULL_HANDLE;
|
VkFence m_transfer_fence = VK_NULL_HANDLE;
|
||||||
|
|
||||||
std::vector<ContextDestructionCallback> m_context_destruction_callbacks;
|
std::vector<ContextDestructionCallback> m_context_destruction_callbacks;
|
||||||
|
|
||||||
|
std::unique_ptr<Allocator> m_allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
375
src/Vulkan/Memory.cpp
Normal file
375
src/Vulkan/Memory.cpp
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
#include <Vulkan/Memory.h>
|
||||||
|
#include <Vulkan/Context.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock() noexcept {
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock(
|
||||||
|
VkDeviceMemory device_memory,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkDeviceSize offset,
|
||||||
|
MemoryPage* memory_page,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept
|
||||||
|
: m_size(size)
|
||||||
|
, m_offset(offset)
|
||||||
|
, m_device_memory(device_memory)
|
||||||
|
, m_memory_page(memory_page)
|
||||||
|
, m_memory_type(memory_type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock(MemoryBlock&& other) noexcept
|
||||||
|
: m_size(other.m_size)
|
||||||
|
, m_offset(other.m_offset)
|
||||||
|
, m_device_memory(other.m_device_memory)
|
||||||
|
, m_memory_page(other.m_memory_page)
|
||||||
|
, m_memory_type(other.m_memory_type)
|
||||||
|
{
|
||||||
|
other.m_size = 0;
|
||||||
|
other.m_offset = 0;
|
||||||
|
other.m_device_memory = VK_NULL_HANDLE;
|
||||||
|
other.m_memory_page = nullptr;
|
||||||
|
other.m_memory_type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::~MemoryBlock() noexcept {
|
||||||
|
if(is_valid()) {
|
||||||
|
logger.warning() << "MemoryBlock deleted before being freed";
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock& MemoryBlock::operator=(MemoryBlock&& other) noexcept {
|
||||||
|
if(&other != this) {
|
||||||
|
using std::swap;
|
||||||
|
swap(m_size, other.m_size);
|
||||||
|
swap(m_offset, other.m_offset);
|
||||||
|
swap(m_device_memory, other.m_device_memory);
|
||||||
|
swap(m_memory_page, other.m_memory_page);
|
||||||
|
swap(m_memory_type, other.m_memory_type);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkMemoryType MemoryBlock::memory_type_info(Context& context) const noexcept {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
return context.memory_properties().memoryTypes[m_memory_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MemoryBlock::free() noexcept {
|
||||||
|
assert(is_valid());
|
||||||
|
|
||||||
|
m_memory_page->p_free(*this);
|
||||||
|
|
||||||
|
m_size = 0;
|
||||||
|
m_offset = 0;
|
||||||
|
m_device_memory = VK_NULL_HANDLE;
|
||||||
|
m_memory_page = nullptr;
|
||||||
|
m_memory_type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* MemoryBlock::map(Context& context) {
|
||||||
|
return map(context, 0, m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size) {
|
||||||
|
assert(is_valid());
|
||||||
|
assert(context);
|
||||||
|
assert(offset + size <= m_size);
|
||||||
|
|
||||||
|
void* ptr;
|
||||||
|
if(vkMapMemory(
|
||||||
|
context.device(),
|
||||||
|
m_device_memory,
|
||||||
|
m_offset + offset,
|
||||||
|
size,
|
||||||
|
0,
|
||||||
|
&ptr
|
||||||
|
) != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("failed to map memory");
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::unmap(Context& context) noexcept {
|
||||||
|
assert(is_valid());
|
||||||
|
|
||||||
|
vkUnmapMemory(
|
||||||
|
context.device(),
|
||||||
|
m_device_memory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MemoryBlock::flush(Context& context) {
|
||||||
|
assert(is_valid());
|
||||||
|
|
||||||
|
VkMappedMemoryRange range {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||||
|
.memory = m_device_memory,
|
||||||
|
.offset = m_offset,
|
||||||
|
.size = m_size,
|
||||||
|
};
|
||||||
|
if(vkFlushMappedMemoryRanges(
|
||||||
|
context.device(),
|
||||||
|
1,
|
||||||
|
&range
|
||||||
|
) != VK_SUCCESS)
|
||||||
|
std::runtime_error("failed to flush memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::invalidate(Context& context) {
|
||||||
|
assert(is_valid());
|
||||||
|
|
||||||
|
VkMappedMemoryRange range {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||||
|
.memory = m_device_memory,
|
||||||
|
.offset = m_offset,
|
||||||
|
.size = m_size,
|
||||||
|
};
|
||||||
|
if(vkInvalidateMappedMemoryRanges(
|
||||||
|
context.device(),
|
||||||
|
1,
|
||||||
|
&range
|
||||||
|
) != VK_SUCCESS)
|
||||||
|
std::runtime_error("failed to invalidate memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MemoryPage::MemoryPage(
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkDeviceMemory device_memory,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept
|
||||||
|
: m_size(size)
|
||||||
|
, m_device_memory(device_memory)
|
||||||
|
, m_blocks{
|
||||||
|
Block{ 0, true },
|
||||||
|
Block{ m_size, false },
|
||||||
|
}
|
||||||
|
, m_memory_type(memory_type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
MemoryPage::MemoryPage(MemoryPage&&) = default;
|
||||||
|
MemoryPage::~MemoryPage() = default;
|
||||||
|
|
||||||
|
MemoryPage& MemoryPage::operator=(MemoryPage&&) = default;
|
||||||
|
|
||||||
|
MemoryBlock MemoryPage::allocate(VkDeviceSize size) noexcept {
|
||||||
|
const auto block_it = find_free_block(size);
|
||||||
|
if(block_it == m_blocks.end())
|
||||||
|
return MemoryBlock();
|
||||||
|
|
||||||
|
block_it[0].is_free = false;
|
||||||
|
if (block_it[0].offset != block_it[1].offset) {
|
||||||
|
m_blocks.emplace(std::next(block_it), Block{
|
||||||
|
block_it[0].offset + size, true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemoryBlock(m_device_memory, size, block_it[0].offset, this, m_memory_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPage::p_free(MemoryBlock& block) noexcept {
|
||||||
|
assert(block.device_memory() == m_device_memory);
|
||||||
|
|
||||||
|
const auto offset = block.offset();
|
||||||
|
const auto block_it = std::lower_bound(
|
||||||
|
m_blocks.begin(),
|
||||||
|
m_blocks.end(),
|
||||||
|
Block{ offset, false },
|
||||||
|
[] (const Block& lhs, const Block& rhs) {
|
||||||
|
return lhs.offset < rhs.offset;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert(block_it != m_blocks.end() && block_it->offset == offset);
|
||||||
|
|
||||||
|
// Merge with next block if also free
|
||||||
|
if (block_it[1].is_free) {
|
||||||
|
m_blocks.erase(std::next(block_it));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge with previous block if also free
|
||||||
|
if (block_it != m_blocks.begin() && block_it[-1].is_free) {
|
||||||
|
m_blocks.erase(block_it);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
block_it->is_free = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryPage::free_device_memory(Context& context) noexcept {
|
||||||
|
vkFreeMemory(
|
||||||
|
context.device(),
|
||||||
|
m_device_memory,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
m_size = 0;
|
||||||
|
m_device_memory = VK_NULL_HANDLE;
|
||||||
|
m_blocks.clear();
|
||||||
|
m_memory_type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MemoryPage::BlockList::iterator MemoryPage::find_free_block(VkDeviceSize size) {
|
||||||
|
const auto block_end = std::prev(m_blocks.end());
|
||||||
|
for(auto block_it = m_blocks.begin(); block_it != block_end; ++block_it) {
|
||||||
|
if(block_it[0].is_free && block_it[1].offset - block_it[0].offset >= size)
|
||||||
|
return block_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_blocks.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Allocator::Allocator(Context* context) noexcept
|
||||||
|
: m_context(context)
|
||||||
|
, m_memory_properties{}
|
||||||
|
, m_page_map{}
|
||||||
|
{
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(
|
||||||
|
m_context->physical_device(),
|
||||||
|
&m_memory_properties
|
||||||
|
);
|
||||||
|
|
||||||
|
for(auto& next_page_size: m_next_page_sizes)
|
||||||
|
next_page_size = BasePageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator::~Allocator() = default;
|
||||||
|
|
||||||
|
|
||||||
|
int32_t Allocator::find_memory_type(
|
||||||
|
uint32_t type_mask,
|
||||||
|
VkMemoryPropertyFlags required_properties
|
||||||
|
) noexcept {
|
||||||
|
for(uint32_t type_index = 0;
|
||||||
|
type_index < m_memory_properties.memoryTypeCount;
|
||||||
|
type_index += 1
|
||||||
|
) {
|
||||||
|
if((type_mask & (1 << type_index)) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto memory_properties =
|
||||||
|
m_memory_properties.memoryTypes[type_index].propertyFlags;
|
||||||
|
if((memory_properties & required_properties) == required_properties)
|
||||||
|
return type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Allocator::find_memory_type(
|
||||||
|
uint32_t type_mask,
|
||||||
|
std::initializer_list<VkMemoryPropertyFlags> properties_list
|
||||||
|
) noexcept {
|
||||||
|
for(const auto& properties: properties_list) {
|
||||||
|
const auto memory_type = find_memory_type(type_mask, properties);
|
||||||
|
if(memory_type >= 0)
|
||||||
|
return memory_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock Allocator::allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept {
|
||||||
|
assert(memory_type < VK_MAX_MEMORY_TYPES);
|
||||||
|
|
||||||
|
auto& pages = m_page_map[memory_type];
|
||||||
|
|
||||||
|
for(auto& page: pages) {
|
||||||
|
auto block = page.allocate(size);
|
||||||
|
if(block)
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkDeviceSize new_page_size = std::max(
|
||||||
|
size,
|
||||||
|
m_next_page_sizes[memory_type]
|
||||||
|
);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocate_info {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.allocationSize = new_page_size,
|
||||||
|
.memoryTypeIndex = memory_type,
|
||||||
|
};
|
||||||
|
VkDeviceMemory device_memory;
|
||||||
|
vkAllocateMemory(
|
||||||
|
m_context->device(),
|
||||||
|
&allocate_info,
|
||||||
|
nullptr,
|
||||||
|
&device_memory
|
||||||
|
);
|
||||||
|
|
||||||
|
pages.emplace_back(
|
||||||
|
new_page_size,
|
||||||
|
device_memory,
|
||||||
|
memory_type
|
||||||
|
);
|
||||||
|
|
||||||
|
if(new_page_size == m_next_page_sizes[memory_type])
|
||||||
|
m_next_page_sizes[memory_type] *= 2;
|
||||||
|
|
||||||
|
return pages.back().allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock Allocator::allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t type_mask,
|
||||||
|
VkMemoryPropertyFlags properties
|
||||||
|
) noexcept {
|
||||||
|
const auto memory_type = find_memory_type(
|
||||||
|
type_mask,
|
||||||
|
properties
|
||||||
|
);
|
||||||
|
if(memory_type < 0)
|
||||||
|
return MemoryBlock();
|
||||||
|
|
||||||
|
return allocate(size, uint32_t(memory_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock Allocator::allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t type_mask,
|
||||||
|
std::initializer_list<VkMemoryPropertyFlags> properties_list
|
||||||
|
) noexcept {
|
||||||
|
const auto memory_type = find_memory_type(
|
||||||
|
type_mask,
|
||||||
|
properties_list
|
||||||
|
);
|
||||||
|
if(memory_type < 0)
|
||||||
|
return MemoryBlock();
|
||||||
|
|
||||||
|
return allocate(size, uint32_t(memory_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Allocator::free_all_pages() noexcept {
|
||||||
|
for(uint32_t memory_type = 0; memory_type < VK_MAX_MEMORY_TYPES; memory_type += 1) {
|
||||||
|
for(auto& page: m_page_map[memory_type])
|
||||||
|
page.free_device_memory(*m_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
185
src/Vulkan/Memory.h
Normal file
185
src/Vulkan/Memory.h
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Vulkan/forward.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryBlock {
|
||||||
|
public:
|
||||||
|
MemoryBlock() noexcept;
|
||||||
|
MemoryBlock(
|
||||||
|
VkDeviceMemory device_memory,
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkDeviceSize offset,
|
||||||
|
MemoryPage* memory_page,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept;
|
||||||
|
MemoryBlock(const MemoryBlock&) = delete;
|
||||||
|
MemoryBlock(MemoryBlock&& other) noexcept;
|
||||||
|
~MemoryBlock() noexcept;
|
||||||
|
|
||||||
|
MemoryBlock& operator=(const MemoryBlock&) = delete;
|
||||||
|
MemoryBlock& operator=(MemoryBlock&& other) noexcept;
|
||||||
|
|
||||||
|
inline explicit operator bool() const noexcept {
|
||||||
|
return m_size != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid() const noexcept {
|
||||||
|
return m_size != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDeviceSize size() const noexcept {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDeviceSize offset() const noexcept {
|
||||||
|
return m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDeviceMemory device_memory() const noexcept {
|
||||||
|
return m_device_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t memory_type() const noexcept {
|
||||||
|
return m_memory_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MemoryPage* memory_page() const noexcept {
|
||||||
|
return m_memory_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryType memory_type_info(Context& context) const noexcept;
|
||||||
|
|
||||||
|
void free() noexcept;
|
||||||
|
|
||||||
|
void* map(Context& context);
|
||||||
|
void* map(Context& context, VkDeviceSize offset, VkDeviceSize size);
|
||||||
|
void unmap(Context& context) noexcept;
|
||||||
|
|
||||||
|
void flush(Context& context);
|
||||||
|
void invalidate(Context& context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDeviceSize m_size = 0;
|
||||||
|
VkDeviceSize m_offset = 0;
|
||||||
|
VkDeviceMemory m_device_memory = VK_NULL_HANDLE;
|
||||||
|
MemoryPage* m_memory_page = nullptr;
|
||||||
|
uint32_t m_memory_type = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryPage {
|
||||||
|
public:
|
||||||
|
MemoryPage(
|
||||||
|
VkDeviceSize size,
|
||||||
|
VkDeviceMemory device_memory,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept;
|
||||||
|
MemoryPage(const MemoryPage&) = delete;
|
||||||
|
MemoryPage(MemoryPage&&);
|
||||||
|
~MemoryPage();
|
||||||
|
|
||||||
|
MemoryPage& operator=(const MemoryPage&) = delete;
|
||||||
|
MemoryPage& operator=(MemoryPage&&);
|
||||||
|
|
||||||
|
explicit inline operator bool() const noexcept {
|
||||||
|
return is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid() const noexcept {
|
||||||
|
return m_size != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDeviceSize size() const noexcept {
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkDeviceMemory device_memory() const noexcept {
|
||||||
|
return m_device_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t memory_type() const noexcept {
|
||||||
|
return m_memory_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock allocate(VkDeviceSize size) noexcept;
|
||||||
|
void p_free(MemoryBlock& block) noexcept;
|
||||||
|
|
||||||
|
void free_device_memory(Context& context) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Block {
|
||||||
|
VkDeviceSize offset;
|
||||||
|
bool is_free;
|
||||||
|
};
|
||||||
|
using BlockList = std::vector<Block>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BlockList::iterator find_free_block(VkDeviceSize size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDeviceSize m_size = 0;
|
||||||
|
VkDeviceMemory m_device_memory = VK_NULL_HANDLE;
|
||||||
|
BlockList m_blocks;
|
||||||
|
uint32_t m_memory_type = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Allocator {
|
||||||
|
public:
|
||||||
|
Allocator(Context* context) noexcept;
|
||||||
|
Allocator(const Allocator&) = delete;
|
||||||
|
Allocator(Allocator&&) = delete;
|
||||||
|
~Allocator();
|
||||||
|
|
||||||
|
Allocator& operator=(const Allocator&) = delete;
|
||||||
|
Allocator& operator=(Allocator&) = delete;
|
||||||
|
|
||||||
|
int32_t find_memory_type(
|
||||||
|
uint32_t type_mask,
|
||||||
|
VkMemoryPropertyFlags properties
|
||||||
|
) noexcept;
|
||||||
|
int32_t find_memory_type(
|
||||||
|
uint32_t type_mask,
|
||||||
|
std::initializer_list<VkMemoryPropertyFlags> properties_list
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
MemoryBlock allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t memory_type
|
||||||
|
) noexcept;
|
||||||
|
MemoryBlock allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t type_mask,
|
||||||
|
VkMemoryPropertyFlags properties
|
||||||
|
) noexcept;
|
||||||
|
MemoryBlock allocate(
|
||||||
|
VkDeviceSize size,
|
||||||
|
uint32_t type_mask,
|
||||||
|
std::initializer_list<VkMemoryPropertyFlags> properties_list
|
||||||
|
) noexcept;
|
||||||
|
|
||||||
|
void free_all_pages() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using PageList = std::vector<MemoryPage>;
|
||||||
|
|
||||||
|
static constexpr VkDeviceSize BasePageSize = 1 << 24;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Context* m_context = nullptr;
|
||||||
|
VkPhysicalDeviceMemoryProperties m_memory_properties;
|
||||||
|
PageList m_page_map[VK_MAX_MEMORY_TYPES];
|
||||||
|
VkDeviceSize m_next_page_sizes[VK_MAX_MEMORY_TYPES];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
18
src/Vulkan/forward.h
Normal file
18
src/Vulkan/forward.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryPage;
|
||||||
|
class MemoryBlock;
|
||||||
|
class Allocator;
|
||||||
|
|
||||||
|
using MemoryPageSP = std::shared_ptr<MemoryBlock>;
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
class ContextSettings;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -180,12 +180,9 @@ void VulkanTutorial::shutdown() {
|
|||||||
|
|
||||||
destroy_swapchain_objects();
|
destroy_swapchain_objects();
|
||||||
|
|
||||||
m_context.free_memory(m_vertex_buffer_memory);
|
|
||||||
m_context.destroy_command_pool(m_command_pool);
|
m_context.destroy_command_pool(m_command_pool);
|
||||||
m_context.free_memory(m_index_buffer_memory);
|
m_index_buffer.destroy();
|
||||||
m_context.destroy_buffer(m_index_buffer);
|
m_vertex_buffer.destroy();
|
||||||
m_context.free_memory(m_vertex_buffer_memory);
|
|
||||||
m_context.destroy_buffer(m_vertex_buffer);
|
|
||||||
m_context.destroy_descriptor_set_layout(m_descriptor_set_layout);
|
m_context.destroy_descriptor_set_layout(m_descriptor_set_layout);
|
||||||
|
|
||||||
for(VkSemaphore semaphore: m_render_done)
|
for(VkSemaphore semaphore: m_render_done)
|
||||||
@@ -196,6 +193,12 @@ void VulkanTutorial::shutdown() {
|
|||||||
m_context.shutdown();
|
m_context.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanTutorial::set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y) {
|
||||||
|
m_camera_position = camera_position;
|
||||||
|
m_camera_z = camera_z;
|
||||||
|
m_camera_y = camera_y;
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanTutorial::draw_frame() {
|
void VulkanTutorial::draw_frame() {
|
||||||
m_swapchain.begin_frame();
|
m_swapchain.begin_frame();
|
||||||
auto const image_index = m_swapchain.current_image_index();
|
auto const image_index = m_swapchain.current_image_index();
|
||||||
@@ -206,15 +209,14 @@ void VulkanTutorial::draw_frame() {
|
|||||||
}
|
}
|
||||||
m_last_frame_time = now;
|
m_last_frame_time = now;
|
||||||
|
|
||||||
const float alpha = SecondsD(m_time).count() * (2.0 * M_PI) / 10.0;
|
Matrix3 linear_view;
|
||||||
const float dist = 2.0f;
|
linear_view <<
|
||||||
const Eigen::Matrix4f view = look_at_matrix(
|
m_camera_y.cross(m_camera_z).transpose(),
|
||||||
// Eigen::Vector3f(0.0f, 0.0f, -dist),
|
m_camera_y.transpose(),
|
||||||
Eigen::Vector3f(0.0f, -dist, -dist),
|
m_camera_z.transpose();
|
||||||
// dist * Eigen::Vector3f(std::cos(alpha), std::sin(alpha), -1.0),
|
Matrix4 view;
|
||||||
Eigen::Vector3f::Zero(),
|
view << linear_view, linear_view * -m_camera_position,
|
||||||
-Eigen::Vector3f::UnitY()
|
Vector4::UnitW().transpose();
|
||||||
);
|
|
||||||
|
|
||||||
const float fov = M_PI / 3.0f;
|
const float fov = M_PI / 3.0f;
|
||||||
const float near = 0.1f;
|
const float near = 0.1f;
|
||||||
@@ -227,12 +229,7 @@ void VulkanTutorial::draw_frame() {
|
|||||||
near, far
|
near, far
|
||||||
);
|
);
|
||||||
|
|
||||||
using Transform = Eigen::Transform<float, 3, Eigen::Affine>;
|
|
||||||
Transform model = Transform::Identity();
|
Transform model = Transform::Identity();
|
||||||
model.rotate(Eigen::AngleAxisf(
|
|
||||||
alpha,
|
|
||||||
Eigen::Vector3f::UnitY()
|
|
||||||
));
|
|
||||||
|
|
||||||
const Uniforms uniforms = {
|
const Uniforms uniforms = {
|
||||||
.scene_from_model = model.matrix(),
|
.scene_from_model = model.matrix(),
|
||||||
@@ -241,20 +238,16 @@ void VulkanTutorial::draw_frame() {
|
|||||||
0.5 * m_swapchain.extent().width,
|
0.5 * m_swapchain.extent().width,
|
||||||
0.5 * m_swapchain.extent().height,
|
0.5 * m_swapchain.extent().height,
|
||||||
},
|
},
|
||||||
.lod = std::cos(alpha) * 0.5f + 0.5f,
|
// .lod = std::cos(alpha) * 0.5f + 0.5f,
|
||||||
};
|
};
|
||||||
|
|
||||||
void* uniform_buffer;
|
void* uniform_buffer = m_uniform_buffer_memory.map(
|
||||||
vkMapMemory(
|
m_context,
|
||||||
m_context.device(),
|
|
||||||
m_uniform_buffer_memory,
|
|
||||||
m_uniform_buffer_offsets[image_index],
|
m_uniform_buffer_offsets[image_index],
|
||||||
sizeof(Uniforms),
|
sizeof(Uniforms)
|
||||||
0,
|
|
||||||
&uniform_buffer
|
|
||||||
);
|
);
|
||||||
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms));
|
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms));
|
||||||
vkUnmapMemory(m_context.device(), m_uniform_buffer_memory);
|
m_uniform_buffer_memory.unmap(m_context);
|
||||||
|
|
||||||
VkSemaphore wait_semaphores[] = {
|
VkSemaphore wait_semaphores[] = {
|
||||||
m_swapchain.ready_to_render(),
|
m_swapchain.ready_to_render(),
|
||||||
@@ -325,10 +318,10 @@ void VulkanTutorial::destroy_swapchain_objects() {
|
|||||||
);
|
);
|
||||||
m_command_buffers.clear();
|
m_command_buffers.clear();
|
||||||
|
|
||||||
for(VkBuffer buffer: m_uniform_buffers)
|
for(auto& buffer: m_uniform_buffers)
|
||||||
m_context.destroy_buffer(buffer);
|
buffer.destroy();
|
||||||
m_uniform_buffers.clear();
|
m_uniform_buffers.clear();
|
||||||
m_context.free_memory(m_uniform_buffer_memory);
|
m_uniform_buffer_memory.free();
|
||||||
|
|
||||||
m_context.destroy_descriptor_pool(m_descriptor_pool);
|
m_context.destroy_descriptor_pool(m_descriptor_pool);
|
||||||
|
|
||||||
@@ -635,58 +628,49 @@ void VulkanTutorial::create_command_pool() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTutorial::create_vertex_buffer() {
|
void VulkanTutorial::create_vertex_buffer() {
|
||||||
if(m_vertex_buffer != VK_NULL_HANDLE)
|
if(m_vertex_buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VkDeviceSize size = sizeof(vertices[0]) * vertices.size();
|
VkDeviceSize size = sizeof(vertices[0]) * vertices.size();
|
||||||
std::tie(m_vertex_buffer, m_vertex_buffer_memory) = m_context.create_buffer(
|
m_vertex_buffer = Vulkan::Buffer(
|
||||||
size, (char*)vertices.data(),
|
m_context,
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
size,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
||||||
m_context.queue_family(GRAPHIC_QUEUE)
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||||
);
|
);
|
||||||
|
m_vertex_buffer.upload(size, vertices.data(), m_context.queue_family(GRAPHIC_QUEUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTutorial::create_index_buffer() {
|
void VulkanTutorial::create_index_buffer() {
|
||||||
if(m_index_buffer != VK_NULL_HANDLE)
|
if(m_index_buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VkDeviceSize size = sizeof(indices[0]) * indices.size();
|
VkDeviceSize size = sizeof(indices[0]) * indices.size();
|
||||||
std::tie(m_index_buffer, m_index_buffer_memory) = m_context.create_buffer(
|
m_index_buffer = Vulkan::Buffer(
|
||||||
size, (char*)indices.data(),
|
m_context,
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
size,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT
|
||||||
m_context.queue_family(GRAPHIC_QUEUE)
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||||
);
|
);
|
||||||
|
m_index_buffer.upload(size, indices.data(), m_context.queue_family(GRAPHIC_QUEUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanTutorial::create_uniform_buffer() {
|
void VulkanTutorial::create_uniform_buffer() {
|
||||||
m_uniform_buffers.assign(m_swapchain.image_count(), VK_NULL_HANDLE);
|
m_uniform_buffers.resize(m_swapchain.image_count());
|
||||||
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) {
|
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) {
|
||||||
VkBufferCreateInfo buffer_info {
|
m_uniform_buffers[index] = Vulkan::Buffer(
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
m_context,
|
||||||
.size = sizeof(Uniforms),
|
sizeof(Uniforms),
|
||||||
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
);
|
||||||
};
|
|
||||||
|
|
||||||
if(vkCreateBuffer(
|
|
||||||
m_context.device(),
|
|
||||||
&buffer_info,
|
|
||||||
nullptr,
|
|
||||||
&m_uniform_buffers[index]
|
|
||||||
) != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("failed to create buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memory_requirements;
|
VkMemoryRequirements memory_requirements =
|
||||||
vkGetBufferMemoryRequirements(
|
m_uniform_buffers[0].memory_requirements();
|
||||||
m_context.device(),
|
|
||||||
m_uniform_buffers[0],
|
|
||||||
&memory_requirements
|
|
||||||
);
|
|
||||||
|
|
||||||
m_uniform_buffer_memory = m_context.allocate_memory(
|
m_uniform_buffer_memory = m_context.allocator().allocate(
|
||||||
memory_requirements.size * m_swapchain.image_count(),
|
memory_requirements.size * m_swapchain.image_count(),
|
||||||
memory_requirements.memoryTypeBits,
|
memory_requirements.memoryTypeBits,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
@@ -696,9 +680,7 @@ void VulkanTutorial::create_uniform_buffer() {
|
|||||||
m_uniform_buffer_offsets.resize(m_uniform_buffers.size());
|
m_uniform_buffer_offsets.resize(m_uniform_buffers.size());
|
||||||
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) {
|
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) {
|
||||||
m_uniform_buffer_offsets[index] = index * memory_requirements.size;
|
m_uniform_buffer_offsets[index] = index * memory_requirements.size;
|
||||||
vkBindBufferMemory(
|
m_uniform_buffers[index].bind_memory(
|
||||||
m_context.device(),
|
|
||||||
m_uniform_buffers[index],
|
|
||||||
m_uniform_buffer_memory,
|
m_uniform_buffer_memory,
|
||||||
m_uniform_buffer_offsets[index]
|
m_uniform_buffer_offsets[index]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <core.h>
|
||||||
|
|
||||||
#include <Vulkan/Context.h>
|
#include <Vulkan/Context.h>
|
||||||
#include <Vulkan/Swapchain.h>
|
#include <Vulkan/Swapchain.h>
|
||||||
|
#include <Vulkan/Buffer.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
@@ -35,6 +38,8 @@ public:
|
|||||||
void initialize(SDL_Window* window);
|
void initialize(SDL_Window* window);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
void set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y);
|
||||||
|
|
||||||
void draw_frame();
|
void draw_frame();
|
||||||
void invalidate_swapchain();
|
void invalidate_swapchain();
|
||||||
|
|
||||||
@@ -66,18 +71,20 @@ private:
|
|||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||||
std::vector<VkFramebuffer> m_framebuffers;
|
std::vector<VkFramebuffer> m_framebuffers;
|
||||||
VkCommandPool m_command_pool = VK_NULL_HANDLE;
|
VkCommandPool m_command_pool = VK_NULL_HANDLE;
|
||||||
VkBuffer m_vertex_buffer = VK_NULL_HANDLE;
|
Vulkan::Buffer m_vertex_buffer;
|
||||||
VkDeviceMemory m_vertex_buffer_memory = VK_NULL_HANDLE;
|
Vulkan::Buffer m_index_buffer;
|
||||||
VkBuffer m_index_buffer = VK_NULL_HANDLE;
|
std::vector<Vulkan::Buffer> m_uniform_buffers;
|
||||||
VkDeviceMemory m_index_buffer_memory = VK_NULL_HANDLE;
|
|
||||||
std::vector<VkBuffer> m_uniform_buffers;
|
|
||||||
std::vector<VkDeviceSize> m_uniform_buffer_offsets;
|
std::vector<VkDeviceSize> m_uniform_buffer_offsets;
|
||||||
VkDeviceMemory m_uniform_buffer_memory = VK_NULL_HANDLE;
|
Vulkan::MemoryBlock m_uniform_buffer_memory;
|
||||||
VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE;
|
VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE;
|
||||||
std::vector<VkDescriptorSet> m_descriptor_sets;
|
std::vector<VkDescriptorSet> m_descriptor_sets;
|
||||||
std::vector<VkCommandBuffer> m_command_buffers;
|
std::vector<VkCommandBuffer> m_command_buffers;
|
||||||
std::vector<VkSemaphore> m_render_done;
|
std::vector<VkSemaphore> m_render_done;
|
||||||
|
|
||||||
|
Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f);
|
||||||
|
Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f);
|
||||||
|
Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
TimePoint m_last_frame_time;
|
TimePoint m_last_frame_time;
|
||||||
Duration m_time = Duration(0);
|
Duration m_time = Duration(0);
|
||||||
};
|
};
|
||||||
|
|||||||
13
src/core.h
13
src/core.h
@@ -8,8 +8,21 @@
|
|||||||
|
|
||||||
using Byte = unsigned char;
|
using Byte = unsigned char;
|
||||||
using Index = uint32_t;
|
using Index = uint32_t;
|
||||||
|
|
||||||
using Real = float;
|
using Real = float;
|
||||||
|
|
||||||
|
using Vector2 = Eigen::Matrix<Real, 2, 1>;
|
||||||
using Vector3 = Eigen::Matrix<Real, 3, 1>;
|
using Vector3 = Eigen::Matrix<Real, 3, 1>;
|
||||||
|
using Vector4 = Eigen::Matrix<Real, 4, 1>;
|
||||||
|
|
||||||
|
using Matrix2 = Eigen::Matrix<Real, 2, 2>;
|
||||||
|
using Matrix3 = Eigen::Matrix<Real, 3, 3>;
|
||||||
|
using Matrix4 = Eigen::Matrix<Real, 4, 4>;
|
||||||
|
|
||||||
|
using Transform = Eigen::Transform<Real, 3, Eigen::Affine>;
|
||||||
|
using AngleAxis = Eigen::AngleAxis<Real>;
|
||||||
|
using Quaternion = Eigen::Quaternion<Real>;
|
||||||
|
|
||||||
using Triangle = Eigen::Array<Index, 3, 1>;
|
using Triangle = Eigen::Array<Index, 3, 1>;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user