Vertex buffers
- Fix RenderObject comparator for storing in set - RenderObjects get ID on register - Transfer queue family and queue - Command buffers for transfer queue - PipelineFactory constructor parameters combined in PipelineBinding structure - GPU_Vertex and GPU_Buffer structures to map GPU memory data - Vertex buffers for world and UI RenderObjects with staging
This commit is contained in:
parent
16bd65c35a
commit
2e0369ee2b
Binary file not shown.
@ -24,6 +24,7 @@ list(TRANSFORM SOURCES PREPEND "src/")
|
||||
find_package(Boost REQUIRED COMPONENTS lockfree)
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
find_package(Vulkan REQUIRED)
|
||||
find_package(RmlUi CONFIG REQUIRED)
|
||||
|
||||
@ -37,6 +38,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Boost::lockfree)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE p7)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE glfw)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE glm::glm)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE RmlUi::RmlUi)
|
||||
|
||||
|
||||
@ -7,6 +7,19 @@
|
||||
#define PIPELINE_CREATE_NEW 0
|
||||
#define PIPELINE_CREATE_DERIVED (1 << 0)
|
||||
|
||||
struct PipelineBinding
|
||||
{
|
||||
const AssetMaterial *baseMaterial;
|
||||
|
||||
const VkRenderPass *baseRenderPass;
|
||||
const VkDevice *device;
|
||||
const VkExtent2D *surfaceExtent;
|
||||
|
||||
const VkVertexInputBindingDescription *vertexBindingConfig;
|
||||
uint32_t vertexAttributesCount;
|
||||
const VkVertexInputAttributeDescription *vertexAttributesConfig;
|
||||
};
|
||||
|
||||
struct PipelineConfig
|
||||
{
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputConfig;
|
||||
@ -42,19 +55,22 @@ struct Pipeline
|
||||
class PipelineFactory
|
||||
{
|
||||
public:
|
||||
PipelineFactory(const AssetMaterial &baseMaterial, const VkRenderPass &baseRenderPass, VkDevice &device, VkExtent2D &surfaceExtent);
|
||||
PipelineFactory(const PipelineBinding &binding);
|
||||
~PipelineFactory();
|
||||
|
||||
Pipeline& Get(const AssetMaterial &material);
|
||||
void Create(const AssetMaterial &material, const VkRenderPass &renderPass, const uint32_t &flags);
|
||||
|
||||
private:
|
||||
PipelineBinding binding;
|
||||
PipelineConfig basePipelineConfig;
|
||||
|
||||
Pipeline basePipeline;
|
||||
std::unordered_map<const AssetMaterial*, Pipeline> pipelines;
|
||||
|
||||
VkDevice &device;
|
||||
VkExtent2D &surfaceExtent;
|
||||
const VkDevice &device;
|
||||
const VkExtent2D &surfaceExtent;
|
||||
|
||||
const VkVertexInputBindingDescription &vertexBindingConfig;
|
||||
|
||||
};
|
||||
@ -2,13 +2,14 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <Boost/lockfree/spsc_queue.hpp>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <RmlUi/Core.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "PipelineFactory.hpp"
|
||||
|
||||
@ -18,6 +19,10 @@
|
||||
#define VALIDATION_LAYER
|
||||
#endif
|
||||
|
||||
#define ATTRIBUTE_FORMAT_VEC2 VK_FORMAT_R32G32_SFLOAT
|
||||
#define ATTRIBUTE_FORMAT_VEC3 VK_FORMAT_R32G32B32_SFLOAT
|
||||
#define ATTRIBUTE_FORMAT_VEC4 VK_FORMAT_R32G32B32A32_SFLOAT
|
||||
|
||||
// GPU properties priority for selection
|
||||
#define GPU_DISCRETE_PRIORITY 1000
|
||||
#define GPU_GRAPHICS_WITH_PRESENT_PRIORITY 500
|
||||
@ -34,17 +39,93 @@ struct Transform
|
||||
float scaleX = 1.0f, scaleY = 1.0f, scaleZ = 1.0f;
|
||||
};
|
||||
|
||||
struct GPU_Vertex
|
||||
{
|
||||
glm::vec2 pos;
|
||||
glm::vec3 color;
|
||||
|
||||
static std::array<VkVertexInputAttributeDescription, 2> GetAttributes()
|
||||
{
|
||||
VkVertexInputAttributeDescription posAttribute = {
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = ATTRIBUTE_FORMAT_VEC2,
|
||||
.offset = offsetof(GPU_Vertex, pos)
|
||||
};
|
||||
VkVertexInputAttributeDescription colorAttribute = {
|
||||
.location = 1,
|
||||
.binding = 0,
|
||||
.format = ATTRIBUTE_FORMAT_VEC3,
|
||||
.offset = offsetof(GPU_Vertex, color)
|
||||
};
|
||||
|
||||
return {posAttribute, colorAttribute};
|
||||
}
|
||||
};
|
||||
|
||||
struct GPU_BufferSlot
|
||||
{
|
||||
size_t position;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
//TODO: move methods definition to the end of file
|
||||
template<typename T> struct GPU_Buffer
|
||||
{
|
||||
T *data;
|
||||
size_t size;
|
||||
const size_t ELEMENT_SIZE;
|
||||
std::vector<GPU_BufferSlot> freeSlots;
|
||||
|
||||
GPU_Buffer() : ELEMENT_SIZE(sizeof(T)) {freeSlots.push_back({.position = 0, .size = size});}
|
||||
|
||||
GPU_BufferSlot* FindFreeSlot(size_t size)
|
||||
{
|
||||
for (auto i = freeSlots.rbegin(); i != freeSlots.rend(); i++)
|
||||
{
|
||||
if (i->size >= size)
|
||||
return &(*i);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t Write(const T *elements, size_t elementsCount)
|
||||
{
|
||||
GPU_BufferSlot *slot = FindFreeSlot(elementsCount);
|
||||
if (slot == nullptr) return 0;
|
||||
|
||||
memcpy(data + slot->position, elements, elementsCount * ELEMENT_SIZE);
|
||||
|
||||
slot->size -= elementsCount;
|
||||
slot->position += elementsCount;
|
||||
if (slot->size == 0)
|
||||
freeSlots.pop_back();
|
||||
|
||||
return slot->position - elementsCount;
|
||||
}
|
||||
|
||||
// void Clear(GPU_BufferSlot range)
|
||||
// {
|
||||
// freeSlots.push_back(range);
|
||||
// //TODO: insert sorted by pos and combine intersections
|
||||
// }
|
||||
};
|
||||
|
||||
struct Mesh
|
||||
{
|
||||
uint32_t vertexCount = 0;
|
||||
size_t verticesBufferPosition = 0;
|
||||
std::vector<GPU_Vertex> vertices;
|
||||
};
|
||||
|
||||
struct RenderObject
|
||||
{
|
||||
uint32_t engineId = UINT32_MAX;
|
||||
|
||||
// Multiple transforms for batching
|
||||
std::vector<Transform> transforms;
|
||||
uint8_t depth = 0;
|
||||
Mesh mesh; //TODO: mesh (vertex/index buffer)
|
||||
Mesh mesh;
|
||||
bool isUI = false;
|
||||
//TODO: texture
|
||||
|
||||
AssetMaterial &material;
|
||||
@ -69,12 +150,14 @@ struct RenderCommand
|
||||
|
||||
struct QueueFamiliesBundle
|
||||
{
|
||||
uint32_t transfer = QUEUE_FAMILY_NO_VALUE;
|
||||
uint32_t graphics = QUEUE_FAMILY_NO_VALUE;
|
||||
uint32_t present = QUEUE_FAMILY_NO_VALUE;
|
||||
};
|
||||
|
||||
struct QueuesBundle
|
||||
{
|
||||
VkQueue transfer;
|
||||
VkQueue graphics;
|
||||
VkQueue present;
|
||||
};
|
||||
@ -115,6 +198,12 @@ struct DrawConfig
|
||||
.swapchainCount = 1,
|
||||
.pResults = nullptr
|
||||
};
|
||||
|
||||
VkVertexInputBindingDescription vertexBindingConfig {
|
||||
.binding = 0,
|
||||
.stride = sizeof(GPU_Vertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
};
|
||||
};
|
||||
|
||||
struct SurfaceInfo
|
||||
@ -131,7 +220,7 @@ struct SurfaceInfo
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
Renderer(GLFWwindow *window, const AssetMaterial& baseMaterial);
|
||||
Renderer(GLFWwindow *window, const AssetMaterial& baseMaterial, const size_t &vertexBufferSize);
|
||||
~Renderer();
|
||||
|
||||
void Start();
|
||||
@ -160,8 +249,16 @@ private:
|
||||
VkDevice device;
|
||||
VkSwapchainKHR swapchain;
|
||||
VkRenderPass baseRenderPass;
|
||||
VkCommandPool commandPool = nullptr;
|
||||
std::vector<VkCommandBuffer> commandBuffers;
|
||||
VkCommandPool graphicsCommandPool = nullptr;
|
||||
VkCommandPool transferCommandPool = nullptr;
|
||||
VkDeviceMemory worldVerticesMemory;
|
||||
VkDeviceMemory stagingWorldVerticesMemory;
|
||||
VkDeviceMemory uiVerticesMemory;
|
||||
VkBuffer worldVertices;
|
||||
VkBuffer stagingWorldVertices;
|
||||
VkBuffer uiVertices;
|
||||
std::vector<VkCommandBuffer> graphicsCommandBuffers;
|
||||
std::vector<VkCommandBuffer> transferCommandBuffers;
|
||||
std::vector<VkImage> frames;
|
||||
std::vector<VkImageView> frameViews;
|
||||
std::vector<VkFramebuffer> baseFrameBuffers;
|
||||
@ -175,14 +272,20 @@ private:
|
||||
QueuesBundle queues;
|
||||
DrawConfig drawConfig;
|
||||
PipelineFactory *pipelineFactory;
|
||||
PipelineBinding pipelineBinding;
|
||||
size_t currentFrame = 0;
|
||||
|
||||
GPU_Buffer<GPU_Vertex> worldVerticesBinded;
|
||||
GPU_Buffer<GPU_Vertex> uiVerticesBinded;
|
||||
|
||||
const float DEFAULT_QUEUE_PRIORITY = 1.0f;
|
||||
const AssetMaterial &baseMaterial;
|
||||
const size_t MAX_FRAMES_IN_FLIGHT = 2;
|
||||
const size_t VERTEX_BUFFER_SIZE;
|
||||
|
||||
std::set<RenderObject> objects;
|
||||
|
||||
Rml::Context *uiContext;
|
||||
//Rml::Context *uiContext;
|
||||
|
||||
void InitVulkan();
|
||||
void SetupDevice();
|
||||
@ -190,10 +293,13 @@ private:
|
||||
void RecreateSwapchain();
|
||||
void ReleaseSwapchain();
|
||||
void SetupRenderPasses();
|
||||
void SetupBuffers();
|
||||
void SetupPipelines();
|
||||
void SetupObjectsBuffers();
|
||||
void SetupRenderBuffers();
|
||||
void SetupSync();
|
||||
|
||||
void Draw();
|
||||
void CopyBuffer(VkBuffer src, size_t offset, VkBuffer dst, VkDeviceSize size);
|
||||
|
||||
void Threading();
|
||||
void Request(const RenderCommand &command);
|
||||
|
||||
@ -22,14 +22,13 @@ PipelineConfig PipelineConfig::Copy() const
|
||||
return copy;
|
||||
}
|
||||
|
||||
PipelineFactory::PipelineFactory(
|
||||
const AssetMaterial &baseMaterial,
|
||||
const VkRenderPass &baseRenderPass,
|
||||
VkDevice &device,
|
||||
VkExtent2D &surfaceExtent
|
||||
) :
|
||||
device(device), surfaceExtent(surfaceExtent)
|
||||
PipelineFactory::PipelineFactory(const PipelineBinding &binding) :
|
||||
device(*binding.device),
|
||||
surfaceExtent(*binding.surfaceExtent),
|
||||
vertexBindingConfig(*binding.vertexBindingConfig)
|
||||
{
|
||||
this->binding = binding;
|
||||
|
||||
basePipelineConfig.dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
|
||||
basePipelineConfig.dynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR);
|
||||
|
||||
@ -47,10 +46,10 @@ PipelineFactory::PipelineFactory(
|
||||
basePipelineConfig.vertexInputConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.vertexBindingDescriptionCount = 0,
|
||||
.pVertexBindingDescriptions = nullptr,
|
||||
.vertexAttributeDescriptionCount = 0,
|
||||
.pVertexAttributeDescriptions = nullptr
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &vertexBindingConfig,
|
||||
.vertexAttributeDescriptionCount = binding.vertexAttributesCount,
|
||||
.pVertexAttributeDescriptions = binding.vertexAttributesConfig
|
||||
};
|
||||
|
||||
basePipelineConfig.inputAssemblyConfig = {
|
||||
@ -146,7 +145,7 @@ PipelineFactory::PipelineFactory(
|
||||
};
|
||||
|
||||
LOG(INFO, "Creating base material pipeline...");
|
||||
Create(baseMaterial, baseRenderPass, PIPELINE_CREATE_NEW);
|
||||
Create(*binding.baseMaterial, *binding.baseRenderPass, PIPELINE_CREATE_NEW);
|
||||
LOG(INFO, "Base material pipeline created");
|
||||
}
|
||||
|
||||
|
||||
@ -11,13 +11,16 @@
|
||||
|
||||
bool operator < (const RenderObject& lhs, const RenderObject& rhs)
|
||||
{
|
||||
return &lhs.material < &rhs.material;
|
||||
if (&lhs.material != &rhs.material)
|
||||
return &lhs.material < &rhs.material;
|
||||
else return lhs.engineId < rhs.engineId;
|
||||
}
|
||||
|
||||
Renderer::Renderer(GLFWwindow *window, const AssetMaterial &baseMaterial) :
|
||||
Renderer::Renderer(GLFWwindow *window, const AssetMaterial &baseMaterial, const size_t &vertexBufferSize) :
|
||||
isRunning(false),
|
||||
isDrawing(false),
|
||||
baseMaterial(baseMaterial)
|
||||
baseMaterial(baseMaterial),
|
||||
VERTEX_BUFFER_SIZE(vertexBufferSize)
|
||||
{
|
||||
this->window = window;
|
||||
int width = -1, height = -1;
|
||||
@ -180,6 +183,7 @@ void Renderer::SetupDevice()
|
||||
queueFamiliesBuffer.present == QUEUE_FAMILY_NO_VALUE
|
||||
)
|
||||
continue;
|
||||
queueFamiliesBuffer.transfer = queueFamiliesBuffer.graphics;
|
||||
|
||||
// Check surface info
|
||||
SurfaceInfo surfaceInfoBuffer {};
|
||||
@ -272,8 +276,10 @@ void Renderer::SetupDevice()
|
||||
}
|
||||
|
||||
// Define queues
|
||||
//TODO: transfer is separate queue for async loading
|
||||
std::vector<VkDeviceQueueCreateInfo> queuesCreateConfigs;
|
||||
std::set<uint32_t> uniqueQueueFamilies {
|
||||
queueFamilies.transfer,
|
||||
queueFamilies.graphics,
|
||||
queueFamilies.present
|
||||
};
|
||||
@ -315,6 +321,7 @@ void Renderer::SetupDevice()
|
||||
else LOG(INFO, "%hs is selected for render with %d priority score", deviceProperties.deviceName, best_priority);
|
||||
|
||||
// Save queues descriptor
|
||||
vkGetDeviceQueue(device, queueFamilies.transfer, 0, &queues.transfer);
|
||||
vkGetDeviceQueue(device, queueFamilies.graphics, 0, &queues.graphics);
|
||||
vkGetDeviceQueue(device, queueFamilies.present, 0, &queues.present);
|
||||
}
|
||||
@ -430,8 +437,8 @@ void Renderer::RecreateSwapchain()
|
||||
|
||||
SetupSwapchain();
|
||||
SetupRenderPasses();
|
||||
pipelineFactory = Allocate<PipelineFactory>(baseMaterial, baseRenderPass, device, surfaceInfo.extent);
|
||||
SetupBuffers();
|
||||
SetupPipelines();
|
||||
SetupRenderBuffers();
|
||||
}
|
||||
|
||||
void Renderer::ReleaseSwapchain()
|
||||
@ -442,9 +449,15 @@ void Renderer::ReleaseSwapchain()
|
||||
}
|
||||
vkFreeCommandBuffers(
|
||||
device,
|
||||
commandPool,
|
||||
static_cast<uint32_t>(commandBuffers.size()),
|
||||
commandBuffers.data()
|
||||
graphicsCommandPool,
|
||||
static_cast<uint32_t>(graphicsCommandBuffers.size()),
|
||||
graphicsCommandBuffers.data()
|
||||
);
|
||||
vkFreeCommandBuffers(
|
||||
device,
|
||||
transferCommandPool,
|
||||
static_cast<uint32_t>(transferCommandBuffers.size()),
|
||||
transferCommandBuffers.data()
|
||||
);
|
||||
|
||||
vkDestroyRenderPass(device, baseRenderPass, nullptr);
|
||||
@ -509,7 +522,162 @@ void Renderer::SetupRenderPasses()
|
||||
LOG(CRITICAL, "Failed to create base render pass. Code: %d", vkResult);
|
||||
}
|
||||
|
||||
void Renderer::SetupBuffers()
|
||||
void Renderer::SetupPipelines()
|
||||
{
|
||||
std::array vertexAttributes = GPU_Vertex::GetAttributes();
|
||||
|
||||
pipelineBinding = {
|
||||
.baseMaterial = &baseMaterial,
|
||||
.baseRenderPass = &baseRenderPass,
|
||||
.device = &device,
|
||||
.surfaceExtent = &surfaceInfo.extent,
|
||||
|
||||
.vertexBindingConfig = &drawConfig.vertexBindingConfig,
|
||||
.vertexAttributesCount = static_cast<uint32_t>(vertexAttributes.size()),
|
||||
.vertexAttributesConfig = vertexAttributes.data()
|
||||
};
|
||||
|
||||
pipelineFactory = Allocate<PipelineFactory>(pipelineBinding);
|
||||
}
|
||||
|
||||
void Renderer::SetupObjectsBuffers()
|
||||
{
|
||||
VkResult vkResult;
|
||||
|
||||
VkBufferCreateInfo worldVertexBufferConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
worldVerticesBinded.size = VERTEX_BUFFER_SIZE;
|
||||
vkResult = vkCreateBuffer(device, &worldVertexBufferConfig, nullptr, &worldVertices);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create buffer for world vertices. Code: %d", vkResult);
|
||||
|
||||
VkBufferCreateInfo stagingWorldVertexBufferConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
vkResult = vkCreateBuffer(device, &stagingWorldVertexBufferConfig, nullptr, &stagingWorldVertices);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create buffer for staging world vertices. Code: %d", vkResult);
|
||||
|
||||
VkBufferCreateInfo uiVertexBufferConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE,
|
||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
uiVerticesBinded.size = VERTEX_BUFFER_SIZE;
|
||||
vkResult = vkCreateBuffer(device, &uiVertexBufferConfig, nullptr, &uiVertices);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create buffer for UI vertices. Code: %d", vkResult);
|
||||
|
||||
VkMemoryRequirements worldMemoryRequirements;
|
||||
vkGetBufferMemoryRequirements(device, worldVertices, &worldMemoryRequirements);
|
||||
VkMemoryRequirements stagingWorldMemoryRequirements;
|
||||
vkGetBufferMemoryRequirements(device, stagingWorldVertices, &stagingWorldMemoryRequirements);
|
||||
VkMemoryRequirements uiMemoryRequirements;
|
||||
vkGetBufferMemoryRequirements(device, uiVertices, &uiMemoryRequirements);
|
||||
|
||||
VkPhysicalDeviceMemoryProperties memoryProps;
|
||||
vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProps);
|
||||
uint32_t optimizedMemTypeIndex = UINT32_MAX, cpuAccessMemTypeIndex = UINT32_MAX;
|
||||
VkMemoryPropertyFlags optimizedMemoryProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
VkMemoryPropertyFlags cpuAccessMemoryProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
for (uint32_t i = 0; i < memoryProps.memoryTypeCount; i++)
|
||||
{
|
||||
if (
|
||||
optimizedMemTypeIndex == UINT32_MAX &&
|
||||
worldMemoryRequirements.memoryTypeBits & (1 << i) &&
|
||||
(memoryProps.memoryTypes[i].propertyFlags & optimizedMemoryProps) == optimizedMemoryProps
|
||||
)
|
||||
optimizedMemTypeIndex = i;
|
||||
if (
|
||||
cpuAccessMemTypeIndex == UINT32_MAX &&
|
||||
stagingWorldMemoryRequirements.memoryTypeBits & (1 << i) &&
|
||||
uiMemoryRequirements.memoryTypeBits & (1 << i) &&
|
||||
(memoryProps.memoryTypes[i].propertyFlags & cpuAccessMemoryProps) == cpuAccessMemoryProps
|
||||
)
|
||||
cpuAccessMemTypeIndex = i;
|
||||
}
|
||||
if (optimizedMemTypeIndex == UINT32_MAX)
|
||||
LOG(CRITICAL, "Failed to find GPU memory available for local data. Code: %d", vkResult);
|
||||
if (cpuAccessMemTypeIndex == UINT32_MAX)
|
||||
LOG(CRITICAL, "Failed to find GPU memory available for transfering data. Code: %d", vkResult);
|
||||
|
||||
VkMemoryAllocateInfo allocateWorldVertices {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.allocationSize = worldMemoryRequirements.size,
|
||||
.memoryTypeIndex = optimizedMemTypeIndex
|
||||
};
|
||||
VkMemoryAllocateInfo allocateStagingWorldVertices {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.allocationSize = stagingWorldMemoryRequirements.size,
|
||||
.memoryTypeIndex = cpuAccessMemTypeIndex
|
||||
};
|
||||
VkMemoryAllocateInfo allocateUiVertices {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.allocationSize = uiMemoryRequirements.size,
|
||||
.memoryTypeIndex = cpuAccessMemTypeIndex
|
||||
};
|
||||
|
||||
vkResult = vkAllocateMemory(device, &allocateWorldVertices, nullptr, &worldVerticesMemory);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to allocate GPU memory for world vertices. Code: %d", vkResult);
|
||||
vkResult = vkAllocateMemory(
|
||||
device, &allocateStagingWorldVertices, nullptr, &stagingWorldVerticesMemory);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to allocate GPU memory for staging world vertices. Code: %d", vkResult);
|
||||
vkResult = vkAllocateMemory(device, &allocateUiVertices, nullptr, &uiVerticesMemory);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to allocate GPU memory for UI vertices. Code: %d", vkResult);
|
||||
|
||||
vkResult = vkBindBufferMemory(device, worldVertices, worldVerticesMemory, 0);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to bind GPU memory for world vertices. Code: %d", vkResult);
|
||||
vkResult = vkBindBufferMemory(device, stagingWorldVertices, stagingWorldVerticesMemory, 0);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to bind GPU memory for staging world vertices. Code: %d", vkResult);
|
||||
vkResult = vkBindBufferMemory(device, uiVertices, uiVerticesMemory, 0);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to bind GPU memory for UI vertices. Code: %d", vkResult);
|
||||
|
||||
vkResult = vkMapMemory(
|
||||
device,
|
||||
stagingWorldVerticesMemory,
|
||||
0,
|
||||
stagingWorldVertexBufferConfig.size,
|
||||
0,
|
||||
reinterpret_cast<void**>(&(worldVerticesBinded.data))
|
||||
);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to map staging world vertices buffer to CPU");
|
||||
vkResult = vkMapMemory(
|
||||
device,
|
||||
uiVerticesMemory,
|
||||
0,
|
||||
uiVertexBufferConfig.size,
|
||||
0,
|
||||
reinterpret_cast<void**>(&uiVerticesBinded.data)
|
||||
);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to map UI buffer vertices to CPU");
|
||||
|
||||
memset(worldVerticesBinded.data, 0, stagingWorldVertexBufferConfig.size);
|
||||
memset(uiVerticesBinded.data, 0, uiVertexBufferConfig.size);
|
||||
}
|
||||
|
||||
void Renderer::SetupRenderBuffers()
|
||||
{
|
||||
VkResult vkResult;
|
||||
|
||||
@ -537,7 +705,7 @@ void Renderer::SetupBuffers()
|
||||
i++;
|
||||
}
|
||||
|
||||
if (commandPool == nullptr)
|
||||
if (graphicsCommandPool == nullptr)
|
||||
{
|
||||
VkCommandPoolCreateInfo commandPoolConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
@ -546,22 +714,48 @@ void Renderer::SetupBuffers()
|
||||
.queueFamilyIndex = queueFamilies.graphics,
|
||||
};
|
||||
|
||||
vkResult = vkCreateCommandPool(device, &commandPoolConfig, nullptr, &commandPool);
|
||||
vkResult = vkCreateCommandPool(device, &commandPoolConfig, nullptr, &graphicsCommandPool);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create command pool. Code: %d", vkResult);
|
||||
LOG(CRITICAL, "Failed to create graphics command pool. Code: %d", vkResult);
|
||||
}
|
||||
|
||||
commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
graphicsCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
VkCommandBufferAllocateInfo allocateConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandPool = commandPool,
|
||||
.commandPool = graphicsCommandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, //TODO: reuse some commands using SECONDARY
|
||||
.commandBufferCount = static_cast<uint32_t>(commandBuffers.size())
|
||||
.commandBufferCount = static_cast<uint32_t>(graphicsCommandBuffers.size())
|
||||
};
|
||||
vkResult = vkAllocateCommandBuffers(device, &allocateConfig, commandBuffers.data());
|
||||
vkResult = vkAllocateCommandBuffers(device, &allocateConfig, graphicsCommandBuffers.data());
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to allocate command buffers. Code: %d", vkResult);
|
||||
LOG(CRITICAL, "Failed to allocate graphics command buffers. Code: %d", vkResult);
|
||||
|
||||
if (transferCommandPool == nullptr)
|
||||
{
|
||||
VkCommandPoolCreateInfo commandPoolConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = queueFamilies.transfer,
|
||||
};
|
||||
|
||||
vkResult = vkCreateCommandPool(device, &commandPoolConfig, nullptr, &transferCommandPool);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create transfer command pool. Code: %d", vkResult);
|
||||
}
|
||||
|
||||
transferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
allocateConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandPool = transferCommandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, //TODO: reuse some commands using SECONDARY
|
||||
.commandBufferCount = static_cast<uint32_t>(transferCommandBuffers.size())
|
||||
};
|
||||
vkResult = vkAllocateCommandBuffers(device, &allocateConfig, transferCommandBuffers.data());
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to allocate transfer command buffers. Code: %d", vkResult);
|
||||
}
|
||||
|
||||
void Renderer::Draw()
|
||||
@ -604,10 +798,10 @@ void Renderer::Draw()
|
||||
}
|
||||
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
|
||||
|
||||
vkResult = vkResetCommandBuffer(commandBuffers[currentFrame], 0);
|
||||
vkResult = vkResetCommandBuffer(graphicsCommandBuffers[currentFrame], 0);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to reset command buffer. Code: %d", vkResult);
|
||||
vkResult = vkBeginCommandBuffer(commandBuffers[currentFrame], &drawConfig.commandBeginConfig);
|
||||
vkResult = vkBeginCommandBuffer(graphicsCommandBuffers[currentFrame], &drawConfig.commandBeginConfig);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to begin command buffer. Code: %d", vkResult);
|
||||
|
||||
@ -619,7 +813,7 @@ void Renderer::Draw()
|
||||
};
|
||||
|
||||
vkCmdBeginRenderPass(
|
||||
commandBuffers[currentFrame],
|
||||
graphicsCommandBuffers[currentFrame],
|
||||
&drawConfig.renderPassBeginConfig,
|
||||
VK_SUBPASS_CONTENTS_INLINE
|
||||
);
|
||||
@ -632,26 +826,41 @@ void Renderer::Draw()
|
||||
if (pipeline != lastPipeline)
|
||||
{
|
||||
vkCmdBindPipeline(
|
||||
commandBuffers[currentFrame],
|
||||
graphicsCommandBuffers[currentFrame],
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline->instance
|
||||
);
|
||||
vkCmdSetViewport(commandBuffers[currentFrame], 0, 1, &pipeline->viewport);
|
||||
vkCmdSetScissor(commandBuffers[currentFrame], 0, 1, &pipeline->scissors);
|
||||
vkCmdSetViewport(graphicsCommandBuffers[currentFrame], 0, 1, &pipeline->viewport);
|
||||
vkCmdSetScissor(graphicsCommandBuffers[currentFrame], 0, 1, &pipeline->scissors);
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
std::vector<VkBuffer> vertexBuffers;
|
||||
vertexBuffers.reserve(1);
|
||||
if (object.isUI)
|
||||
vertexBuffers.push_back(uiVertices);
|
||||
else
|
||||
vertexBuffers.push_back(worldVertices);
|
||||
VkDeviceSize offsets[] = {object.mesh.verticesBufferPosition};
|
||||
vkCmdBindVertexBuffers(
|
||||
graphicsCommandBuffers[currentFrame],
|
||||
0,
|
||||
1,
|
||||
vertexBuffers.data(),
|
||||
offsets
|
||||
);
|
||||
|
||||
vkCmdDraw(
|
||||
commandBuffers[currentFrame],
|
||||
object.mesh.vertexCount,
|
||||
graphicsCommandBuffers[currentFrame],
|
||||
static_cast<uint32_t>(object.mesh.vertices.size()),
|
||||
static_cast<uint32_t>(object.transforms.size()),
|
||||
0, // TODO: batching
|
||||
0 // TODO: batching
|
||||
);
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(commandBuffers[currentFrame]);
|
||||
vkResult = vkEndCommandBuffer(commandBuffers[currentFrame]);
|
||||
vkCmdEndRenderPass(graphicsCommandBuffers[currentFrame]);
|
||||
vkResult = vkEndCommandBuffer(graphicsCommandBuffers[currentFrame]);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to end command buffer. Code: %d", vkResult);
|
||||
|
||||
@ -662,7 +871,7 @@ void Renderer::Draw()
|
||||
drawConfig.submitConfig.pWaitSemaphores = waitSemaphores;
|
||||
//drawConfig.submitConfig.pSignalSemaphores = &renderFinished[currentFrame];
|
||||
drawConfig.submitConfig.pSignalSemaphores =signalSemaphores;
|
||||
drawConfig.submitConfig.pCommandBuffers = &commandBuffers[currentFrame];
|
||||
drawConfig.submitConfig.pCommandBuffers = &graphicsCommandBuffers[currentFrame];
|
||||
drawConfig.submitConfig.pWaitDstStageMask = waitStages;
|
||||
|
||||
vkResult = vkResetFences(device, 1, &inFlightFences[currentFrame]);
|
||||
@ -699,6 +908,54 @@ void Renderer::Draw()
|
||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
void Renderer::CopyBuffer(VkBuffer src, size_t offset, VkBuffer dst, VkDeviceSize size)
|
||||
{
|
||||
VkResult vkResult;
|
||||
|
||||
VkCommandBufferAllocateInfo bufferAllocateConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = transferCommandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkResult = vkAllocateCommandBuffers(device, &bufferAllocateConfig, &commandBuffer);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to allocate temporary command buffer for copy operation. Code: %d", vkResult);
|
||||
|
||||
VkCommandBufferBeginInfo commandBeginConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
||||
};
|
||||
vkResult = vkBeginCommandBuffer(commandBuffer, &commandBeginConfig);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to begin command for copy operation. Code: %d", vkResult);
|
||||
|
||||
VkBufferCopy copyRegion {
|
||||
.srcOffset = offset,
|
||||
.dstOffset = offset,
|
||||
.size = size
|
||||
};
|
||||
vkCmdCopyBuffer(commandBuffer, src, dst, 1, ©Region);
|
||||
|
||||
vkResult = vkEndCommandBuffer(commandBuffer);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to end command for copy operation. Code: %d", vkResult);
|
||||
|
||||
VkSubmitInfo submitConfig {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &commandBuffer
|
||||
};
|
||||
vkQueueSubmit(queues.transfer, 1, &submitConfig, VK_NULL_HANDLE); //TODO: use fence for optimizatoin
|
||||
vkQueueWaitIdle(queues.transfer);
|
||||
|
||||
vkFreeCommandBuffers(device, transferCommandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
void Renderer::SetupSync()
|
||||
{
|
||||
VkResult vkResult;
|
||||
@ -764,10 +1021,10 @@ void Renderer::Init()
|
||||
SetupDevice();
|
||||
SetupSwapchain();
|
||||
SetupRenderPasses();
|
||||
|
||||
pipelineFactory = Allocate<PipelineFactory>(baseMaterial, baseRenderPass, device, surfaceInfo.extent);
|
||||
|
||||
SetupBuffers();
|
||||
SetupPipelines();
|
||||
SetupObjectsBuffers();
|
||||
SetupRenderBuffers();
|
||||
CopyBuffer(stagingWorldVertices, 0, worldVertices, worldVerticesBinded.size * worldVerticesBinded.ELEMENT_SIZE);
|
||||
SetupSync();
|
||||
}
|
||||
|
||||
@ -803,7 +1060,23 @@ void Renderer::ProcessCommand(const RenderCommand &command)
|
||||
|
||||
for (size_t i = 0; i < command.objectsSize; i++)
|
||||
{
|
||||
objects.insert(command.objects[i]);
|
||||
RenderObject &object = command.objects[i];
|
||||
object.engineId = static_cast<uint32_t>(objects.size());
|
||||
if (objects.contains(object)) continue;
|
||||
|
||||
// TODO: combine vertices data and write with one Write out of loop
|
||||
size_t verticesPos = worldVerticesBinded.Write(
|
||||
object.mesh.vertices.data(),
|
||||
object.mesh.vertices.size()
|
||||
) * worldVerticesBinded.ELEMENT_SIZE;
|
||||
object.mesh.verticesBufferPosition = verticesPos;
|
||||
CopyBuffer(
|
||||
stagingWorldVertices,
|
||||
verticesPos,
|
||||
worldVertices,
|
||||
object.mesh.vertices.size() * worldVerticesBinded.ELEMENT_SIZE
|
||||
);
|
||||
objects.insert(object);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -864,6 +1137,17 @@ void Renderer::Release()
|
||||
|
||||
ReleaseSwapchain();
|
||||
|
||||
vkUnmapMemory(device, stagingWorldVerticesMemory);
|
||||
vkUnmapMemory(device, uiVerticesMemory);
|
||||
|
||||
vkDestroyBuffer(device, worldVertices, nullptr);
|
||||
vkDestroyBuffer(device, stagingWorldVertices, nullptr);
|
||||
vkDestroyBuffer(device, uiVertices, nullptr);
|
||||
|
||||
vkFreeMemory(device, worldVerticesMemory, nullptr);
|
||||
vkFreeMemory(device, stagingWorldVerticesMemory, nullptr);
|
||||
vkFreeMemory(device, uiVerticesMemory, nullptr);
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
{
|
||||
vkDestroySemaphore(device, renderFinished[i], nullptr);
|
||||
@ -871,7 +1155,8 @@ void Renderer::Release()
|
||||
vkDestroyFence(device, inFlightFences[i], nullptr);
|
||||
}
|
||||
|
||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||
vkDestroyCommandPool(device, graphicsCommandPool, nullptr);
|
||||
vkDestroyCommandPool(device, transferCommandPool, nullptr);
|
||||
|
||||
vkDestroyDevice(device, nullptr);
|
||||
vkDestroySurfaceKHR(vulkan, surface, nullptr);
|
||||
|
||||
@ -35,7 +35,7 @@ int main(int argc, char **argv)
|
||||
assetManager.LoadAsync(AssetInfo::MATERIAL, "assets/materials/helloworld.mat");
|
||||
AssetHandle baseMaterialHandle = assetManager.Find("assets/materials/helloworld.mat");
|
||||
AssetMaterial baseMaterial = assetManager.Get<AssetMaterial>(baseMaterialHandle);
|
||||
Renderer renderer(window, baseMaterial);
|
||||
Renderer renderer(window, baseMaterial, 1000000); //TODO: buffer sizes
|
||||
renderer.Start();
|
||||
|
||||
//Setup Engine
|
||||
@ -49,11 +49,30 @@ int main(int argc, char **argv)
|
||||
// Test render obj
|
||||
RenderObject triangle {
|
||||
.transforms = {{.x = 0, .y = 0}},
|
||||
.mesh = {.vertexCount = 3},
|
||||
.mesh = {
|
||||
.vertices = {
|
||||
{.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
||||
{.pos = {0.0f, 0.5f}, .color = {0.0f, 0.0f, 0.0f}},
|
||||
{.pos = {-1.0f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}}
|
||||
}
|
||||
},
|
||||
|
||||
.material = baseMaterial,
|
||||
};
|
||||
renderer.RegisterObjects(&triangle, 1);
|
||||
RenderObject triangle2 {
|
||||
.transforms = {{.x = 0, .y = 0}},
|
||||
.mesh = {
|
||||
.vertices = {
|
||||
{.pos = {0.0f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
||||
{.pos = {0.5f, 0.5f}, .color = {0.0f, 1.0f, 0.0f}},
|
||||
{.pos = {-0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}}
|
||||
}
|
||||
},
|
||||
|
||||
.material = baseMaterial,
|
||||
};
|
||||
RenderObject objs[] = {triangle, triangle2};
|
||||
renderer.RegisterObjects(objs, 2);
|
||||
|
||||
// Process GLFW events
|
||||
while(!glfwWindowShouldClose(window))
|
||||
|
||||
@ -1,21 +1,12 @@
|
||||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
);
|
||||
|
||||
vec3 colors[3] = vec3[](
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
fragColor = colors[gl_VertexIndex];
|
||||
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
"entt",
|
||||
"vulkan",
|
||||
"glfw3",
|
||||
"glm",
|
||||
"rmlui",
|
||||
"gtest"
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user