mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Fix subpass dependency and do other things
This commit is contained in:
parent
2f46fe21ef
commit
e1cb168cce
@ -15,6 +15,7 @@ namespace engine::gfx {
|
||||
struct DrawBuffer;
|
||||
struct DescriptorSetLayout;
|
||||
struct DescriptorSet;
|
||||
struct Image;
|
||||
|
||||
enum class MSAALevel {
|
||||
MSAA_OFF,
|
||||
@ -29,13 +30,16 @@ namespace engine::gfx {
|
||||
GraphicsSettings()
|
||||
{
|
||||
// sane defaults
|
||||
enableValidation = true;
|
||||
vsync = true;
|
||||
waitForPresent = true; // not all GPUs/drivers support immediate present with V-sync enabled
|
||||
msaaLevel = MSAALevel::MSAA_OFF;
|
||||
}
|
||||
|
||||
bool enableValidation;
|
||||
bool vsync;
|
||||
bool waitForPresent; // idle CPU after render until the frame has been presented (no affect with V-sync disabled)
|
||||
// idle CPU after render until the frame has been presented (no affect with V-sync disabled)
|
||||
bool waitForPresent;
|
||||
MSAALevel msaaLevel;
|
||||
|
||||
};
|
||||
@ -98,7 +102,7 @@ namespace engine::gfx {
|
||||
struct PipelineInfo {
|
||||
const char* vertShaderPath;
|
||||
const char* fragShaderPath;
|
||||
gfx::VertexFormat vertexFormat;
|
||||
VertexFormat vertexFormat;
|
||||
bool alphaBlending;
|
||||
bool backfaceCulling;
|
||||
std::vector<const DescriptorSetLayout*> descriptorSetLayouts;
|
||||
|
@ -48,6 +48,8 @@ namespace engine {
|
||||
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
|
||||
void destroyBuffer(const gfx::Buffer* buffer);
|
||||
|
||||
gfx::Image* createImage(uint32_t w, uint32_t h, const void* imageData);
|
||||
|
||||
gfx::Texture* createTexture(
|
||||
const void* imageData,
|
||||
uint32_t width,
|
||||
|
@ -10,7 +10,7 @@ void main() {
|
||||
|
||||
gl_FragDepth = 0.9999;
|
||||
//outColor = texture(texSampler, fragUV);
|
||||
outColor = vec4(0.1, 0.1, 0.1, 1.0);
|
||||
outColor = vec4(fragUV, 0.0, 1.0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ namespace engine {
|
||||
VkFence renderFence = VK_NULL_HANDLE;
|
||||
VkSemaphore presentSemaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore renderSemaphore = VK_NULL_HANDLE;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
VkCommandBuffer drawBuf = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
@ -80,9 +81,9 @@ namespace engine {
|
||||
};
|
||||
|
||||
struct gfx::DrawBuffer {
|
||||
FrameData frameData;
|
||||
uint32_t currentFrameIndex; // corresponds to the frameData
|
||||
uint32_t imageIndex; // for swapchain present
|
||||
FrameData frameData{};
|
||||
uint32_t currentFrameIndex = 0; // corresponds to the frameData
|
||||
uint32_t imageIndex = 0; // for swapchain present
|
||||
};
|
||||
|
||||
struct gfx::DescriptorSetLayout {
|
||||
@ -559,6 +560,7 @@ namespace engine {
|
||||
Swapchain swapchain{};
|
||||
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkCommandPool transferCommandPool = VK_NULL_HANDLE;
|
||||
std::array<std::unordered_set<gfx::DescriptorBuffer*>, FRAMES_IN_FLIGHT> descriptorBufferWriteQueues{};
|
||||
|
||||
uint64_t FRAMECOUNT = 0;
|
||||
@ -592,13 +594,7 @@ namespace engine {
|
||||
throw std::runtime_error("The loaded Vulkan version must be at least 1.3");
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
bool useValidation = false;
|
||||
#else
|
||||
bool useValidation = true;
|
||||
#endif
|
||||
|
||||
pimpl->instance = createVulkanInstance(pimpl->window, appName, appVersion, useValidation, MessageSeverity::SEV_WARNING);
|
||||
pimpl->instance = createVulkanInstance(pimpl->window, appName, appVersion, pimpl->graphicsSettings.enableValidation, MessageSeverity::SEV_WARNING);
|
||||
|
||||
if (SDL_Vulkan_CreateSurface(pimpl->window, pimpl->instance.instance, &pimpl->surface) == false) {
|
||||
throw std::runtime_error("Unable to create window surface");
|
||||
@ -607,7 +603,58 @@ namespace engine {
|
||||
DeviceRequirements deviceRequirements{};
|
||||
deviceRequirements.requiredExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
||||
deviceRequirements.requiredFeatures.samplerAnisotropy = VK_TRUE;
|
||||
deviceRequirements.sampledImageLinearFilter = true;
|
||||
deviceRequirements.requiredFeatures.fillModeNonSolid = VK_TRUE;
|
||||
deviceRequirements.formats.push_back(
|
||||
FormatRequirements{
|
||||
.format = VK_FORMAT_R8G8B8A8_SRGB,
|
||||
.properties = VkFormatProperties{
|
||||
.linearTilingFeatures = {},
|
||||
.optimalTilingFeatures = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,
|
||||
.bufferFeatures = {},
|
||||
}
|
||||
}
|
||||
);
|
||||
deviceRequirements.formats.push_back(
|
||||
FormatRequirements{
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.properties = VkFormatProperties{
|
||||
.linearTilingFeatures = {},
|
||||
.optimalTilingFeatures = {},
|
||||
.bufferFeatures = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
|
||||
}
|
||||
}
|
||||
);
|
||||
deviceRequirements.formats.push_back(
|
||||
FormatRequirements{
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.properties = VkFormatProperties{
|
||||
.linearTilingFeatures = {},
|
||||
.optimalTilingFeatures = {},
|
||||
.bufferFeatures = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
|
||||
}
|
||||
}
|
||||
);
|
||||
deviceRequirements.formats.push_back(
|
||||
FormatRequirements{
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.properties = VkFormatProperties{
|
||||
.linearTilingFeatures = {},
|
||||
.optimalTilingFeatures = {},
|
||||
.bufferFeatures = VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
|
||||
}
|
||||
}
|
||||
);
|
||||
deviceRequirements.formats.push_back( // Depth buffer format
|
||||
FormatRequirements{
|
||||
.format = VK_FORMAT_D16_UNORM,
|
||||
.properties = VkFormatProperties{
|
||||
.linearTilingFeatures = {},
|
||||
.optimalTilingFeatures = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
.bufferFeatures = {},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
pimpl->device = createDevice(pimpl->instance.instance, deviceRequirements, pimpl->surface);
|
||||
|
||||
pimpl->allocator = createAllocator(pimpl->instance.instance, pimpl->device.device, pimpl->device.physicalDevice);
|
||||
@ -642,27 +689,44 @@ namespace engine {
|
||||
res = vkCreateSemaphore(pimpl->device.device, &smphInfo, nullptr, &pimpl->frameData[i].renderSemaphore);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create semaphore!");
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0, // Command buffers cannot be individually reset (more performant this way)
|
||||
.queueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily
|
||||
};
|
||||
VKCHECK(vkCreateCommandPool(pimpl->device.device, &poolInfo, nullptr, &pimpl->frameData[i].commandPool));
|
||||
|
||||
VkCommandBufferAllocateInfo cmdAllocInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.commandPool = pimpl->device.commandPools.draw,
|
||||
.commandPool = pimpl->frameData[i].commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1
|
||||
};
|
||||
VKCHECK(vkAllocateCommandBuffers(pimpl->device.device, &cmdAllocInfo, &pimpl->frameData[i].drawBuf));
|
||||
}
|
||||
|
||||
/* create command pool for transfer operations */
|
||||
VkCommandPoolCreateInfo transferPoolInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // These command buffers don't last very long
|
||||
.queueFamilyIndex = pimpl->device.queues.transferQueueFamily
|
||||
};
|
||||
VKCHECK(vkCreateCommandPool(pimpl->device.device, &transferPoolInfo, nullptr, &pimpl->transferCommandPool));
|
||||
|
||||
/* create a global descriptor pool */
|
||||
|
||||
std::vector<VkDescriptorPoolSize> poolSizes{};
|
||||
poolSizes.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 5); // purposely low limit
|
||||
poolSizes.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 100); // purposely low limit
|
||||
|
||||
VkDescriptorPoolCreateInfo descriptorPoolInfo{};
|
||||
descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptorPoolInfo.pNext = nullptr;
|
||||
descriptorPoolInfo.flags = 0;
|
||||
descriptorPoolInfo.maxSets = 5; // purposely low limit
|
||||
descriptorPoolInfo.poolSizeCount = poolSizes.size();
|
||||
descriptorPoolInfo.maxSets = 100; // purposely low limit
|
||||
descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size();
|
||||
descriptorPoolInfo.pPoolSizes = poolSizes.data();
|
||||
VKCHECK(vkCreateDescriptorPool(pimpl->device.device, &descriptorPoolInfo, nullptr, &pimpl->descriptorPool));
|
||||
|
||||
@ -672,8 +736,10 @@ namespace engine {
|
||||
{
|
||||
vkDestroyDescriptorPool(pimpl->device.device, pimpl->descriptorPool, nullptr);
|
||||
|
||||
vkDestroyCommandPool(pimpl->device.device, pimpl->transferCommandPool, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
vkFreeCommandBuffers(pimpl->device.device, pimpl->device.commandPools.draw, 1, &pimpl->frameData[i].drawBuf);
|
||||
vkDestroyCommandPool(pimpl->device.device, pimpl->frameData[i].commandPool, nullptr);
|
||||
vkDestroySemaphore(pimpl->device.device, pimpl->frameData[i].renderSemaphore, nullptr);
|
||||
vkDestroySemaphore(pimpl->device.device, pimpl->frameData[i].presentSemaphore, nullptr);
|
||||
vkDestroyFence(pimpl->device.device, pimpl->frameData[i].renderFence, nullptr);
|
||||
@ -707,10 +773,17 @@ namespace engine {
|
||||
const uint32_t currentFrameIndex = pimpl->FRAMECOUNT % FRAMES_IN_FLIGHT;
|
||||
const FrameData frameData = pimpl->frameData[currentFrameIndex];
|
||||
|
||||
/* wait until the previous frame RENDERING has finished */
|
||||
res = vkWaitForFences(pimpl->device.device, 1, &frameData.renderFence, VK_TRUE, 1000000000LL);
|
||||
VKCHECK(res);
|
||||
res = vkResetFences(pimpl->device.device, 1, &frameData.renderFence);
|
||||
VKCHECK(res);
|
||||
|
||||
/* first empty the descriptor buffer write queue */
|
||||
auto& writeQueue = pimpl->descriptorBufferWriteQueues[currentFrameIndex];
|
||||
//if (writeQueue.empty() == false) vkQueueWaitIdle(pimpl->device.queues.drawQueues[0]);
|
||||
for (gfx::DescriptorBuffer* buffer : writeQueue) {
|
||||
copyBuffer(pimpl->device.device, pimpl->device.commandPools.transfer, pimpl->device.queues.transferQueues[0], buffer->stagingBuffer.buffer, buffer->gpuBuffers[currentFrameIndex].buffer, buffer->stagingBuffer.size);
|
||||
copyBuffer(pimpl->device.device, pimpl->transferCommandPool, pimpl->device.queues.transferQueues[0], buffer->stagingBuffer.buffer, buffer->gpuBuffers[currentFrameIndex].buffer, buffer->stagingBuffer.size);
|
||||
}
|
||||
writeQueue.clear();
|
||||
|
||||
@ -731,14 +804,8 @@ namespace engine {
|
||||
if (res == VK_SUCCESS) pimpl->swapchainIsOutOfDate = false;
|
||||
} while (pimpl->swapchainIsOutOfDate);
|
||||
|
||||
/* wait until the previous frame RENDERING has finished */
|
||||
res = vkWaitForFences(pimpl->device.device, 1, &frameData.renderFence, VK_TRUE, 1000000000LL);
|
||||
VKCHECK(res);
|
||||
res = vkResetFences(pimpl->device.device, 1, &frameData.renderFence);
|
||||
VKCHECK(res);
|
||||
|
||||
/* record command buffer */
|
||||
res = vkResetCommandBuffer(frameData.drawBuf, 0);
|
||||
res = vkResetCommandPool(pimpl->device.device, frameData.commandPool, 0);
|
||||
VKCHECK(res);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{
|
||||
@ -763,10 +830,10 @@ namespace engine {
|
||||
passBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
passBegin.pNext = nullptr;
|
||||
passBegin.renderPass = pimpl->swapchain.renderpass;
|
||||
passBegin.framebuffer = std::get<2>(pimpl->swapchain.images[swapchainImageIndex]);
|
||||
passBegin.framebuffer = pimpl->swapchain.framebuffers[swapchainImageIndex];
|
||||
passBegin.renderArea.extent = pimpl->swapchain.extent;
|
||||
passBegin.renderArea.offset = { 0, 0 };
|
||||
passBegin.clearValueCount = clearValues.size();
|
||||
passBegin.clearValueCount = (uint32_t)clearValues.size();
|
||||
passBegin.pClearValues = clearValues.data();
|
||||
vkCmdBeginRenderPass(frameData.drawBuf, &passBegin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
@ -824,6 +891,7 @@ namespace engine {
|
||||
.pSignalSemaphores = &drawBuffer->frameData.renderSemaphore,
|
||||
};
|
||||
res = vkQueueSubmit(pimpl->device.queues.drawQueues[0], 1, &submitInfo, drawBuffer->frameData.renderFence);
|
||||
assert(res == VK_SUCCESS);
|
||||
// VKCHECK(res); // expensive operation for some reason
|
||||
|
||||
// PRESENT
|
||||
@ -913,10 +981,10 @@ namespace engine {
|
||||
attribDescs.reserve(info.vertexFormat.attributeDescriptions.size());
|
||||
for (const auto& desc : info.vertexFormat.attributeDescriptions) {
|
||||
VkVertexInputAttributeDescription vulkanAttribDesc{};
|
||||
vulkanAttribDesc.binding = 0;
|
||||
vulkanAttribDesc.location = desc.location;
|
||||
vulkanAttribDesc.offset = desc.offset;
|
||||
vulkanAttribDesc.binding = 0;
|
||||
vulkanAttribDesc.format = vkinternal::getVertexAttribFormat(desc.format);
|
||||
vulkanAttribDesc.offset = desc.offset;
|
||||
attribDescs.push_back(vulkanAttribDesc);
|
||||
}
|
||||
|
||||
@ -982,7 +1050,7 @@ namespace engine {
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer{};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.depthClampEnable = VK_FALSE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE; // enabling this will not run the fragment shaders at all
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
if (info.backfaceCulling == true) {
|
||||
@ -1060,7 +1128,7 @@ namespace engine {
|
||||
|
||||
VkPipelineLayoutCreateInfo layoutInfo{};
|
||||
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layoutInfo.setLayoutCount = descriptorSetLayouts.size();
|
||||
layoutInfo.setLayoutCount = (uint32_t)descriptorSetLayouts.size();
|
||||
layoutInfo.pSetLayouts = descriptorSetLayouts.data();
|
||||
layoutInfo.pushConstantRangeCount = 1;
|
||||
layoutInfo.pPushConstantRanges = &pushConstantRange;
|
||||
@ -1119,7 +1187,7 @@ namespace engine {
|
||||
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.bindingCount = bindings.size();
|
||||
info.bindingCount = (uint32_t)bindings.size();
|
||||
info.pBindings = bindings.data();
|
||||
VKCHECK(vkCreateDescriptorSetLayout(pimpl->device.device, &info, nullptr, &out->layout));
|
||||
|
||||
@ -1230,7 +1298,7 @@ namespace engine {
|
||||
VKCHECK(vmaCreateBuffer(pimpl->allocator, &gpuBufferInfo, &gpuAllocationInfo, &out->gpuBuffers[i].buffer, &out->gpuBuffers[i].allocation, nullptr));
|
||||
|
||||
/* copy staging buffer into both */
|
||||
copyBuffer(pimpl->device.device, pimpl->device.commandPools.transfer, pimpl->device.queues.transferQueues[0], out->stagingBuffer.buffer, out->gpuBuffers[i].buffer, out->stagingBuffer.size);
|
||||
copyBuffer(pimpl->device.device, pimpl->transferCommandPool, pimpl->device.queues.transferQueues[0], out->stagingBuffer.buffer, out->gpuBuffers[i].buffer, out->stagingBuffer.size);
|
||||
}
|
||||
|
||||
return out;
|
||||
@ -1320,7 +1388,7 @@ namespace engine {
|
||||
}
|
||||
|
||||
// copy the data from the staging buffer to the gpu buffer
|
||||
copyBuffer(pimpl->device.device, pimpl->device.commandPools.transfer, pimpl->device.queues.transferQueues[0], stagingBuffer, out->buffer, out->size);
|
||||
copyBuffer(pimpl->device.device, pimpl->transferCommandPool, pimpl->device.queues.transferQueues[0], stagingBuffer, out->buffer, out->size);
|
||||
|
||||
// destroy staging buffer
|
||||
vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation);
|
||||
@ -1334,6 +1402,11 @@ namespace engine {
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
gfx::Image* GFXDevice::createImage(uint32_t w, uint32_t h, const void* imageData)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::Texture* GFXDevice::createTexture(
|
||||
const void* imageData,
|
||||
uint32_t width,
|
||||
|
@ -38,7 +38,7 @@ namespace engine {
|
||||
const float NZdistance = glm::abs(subjectCentre.z - object.pos1.z);
|
||||
const std::array<float, 6> distances { PXdistance, NXdistance, PYdistance, NYdistance, PZdistance, NZdistance };
|
||||
const auto minDistance = std::min_element(distances.begin(), distances.end());
|
||||
const int index = minDistance - distances.begin();
|
||||
const int index = static_cast<int>(minDistance - distances.begin());
|
||||
switch (index) {
|
||||
case 0:
|
||||
// P_X
|
||||
@ -97,7 +97,7 @@ namespace engine {
|
||||
|
||||
const glm::vec3 globalPosition = t->worldMatrix[3];
|
||||
const AABB localBoundingBox = c->aabb;
|
||||
AABB globalBoundingBox;
|
||||
AABB globalBoundingBox{};
|
||||
globalBoundingBox.pos1 = globalPosition + localBoundingBox.pos1;
|
||||
globalBoundingBox.pos2 = globalPosition + localBoundingBox.pos2;
|
||||
|
||||
@ -117,8 +117,8 @@ namespace engine {
|
||||
|
||||
// Check every static collider against every dynamic collider, and every dynamic collider against every other one
|
||||
// This technique is inefficient for many entities.
|
||||
for (auto [staticEntity, staticAABB, staticTrigger] : m_staticAABBs) {
|
||||
for (auto [dynamicEntity, dynamicAABB, dynamicTrigger] : m_dynamicAABBs) {
|
||||
for (const auto& [staticEntity, staticAABB, staticTrigger] : m_staticAABBs) {
|
||||
for (const auto& [dynamicEntity, dynamicAABB, dynamicTrigger] : m_dynamicAABBs) {
|
||||
if (checkCollisionFast(staticAABB, dynamicAABB)) {
|
||||
if (staticTrigger || dynamicTrigger) { // only check collisions involved with triggers
|
||||
m_possibleCollisions.emplace_back(
|
||||
@ -131,7 +131,7 @@ namespace engine {
|
||||
}
|
||||
|
||||
// get collision details and submit events
|
||||
for (auto possibleCollision : m_possibleCollisions) {
|
||||
for (const auto& possibleCollision : m_possibleCollisions) {
|
||||
if (possibleCollision.staticTrigger) {
|
||||
CollisionEvent info{};
|
||||
info.isCollisionEnter = true;
|
||||
@ -156,7 +156,7 @@ namespace engine {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [entity, info] : m_collisionInfos) {
|
||||
for (const auto& [entity, info] : m_collisionInfos) {
|
||||
m_scene->events()->queueEvent<CollisionEvent>(EventSubscriberKind::ENTITY, entity, info);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace engine::util {
|
||||
{
|
||||
|
||||
// convert to glm column major
|
||||
glm::mat4 transform;
|
||||
glm::mat4 transform{};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
transform[i][j] = parentNode->mTransformation[j][i];
|
||||
@ -196,7 +196,7 @@ namespace engine::util {
|
||||
const aiMesh* m = scene->mMeshes[i];
|
||||
meshMaterialIndices.push_back(m->mMaterialIndex);
|
||||
std::vector<Vertex> vertices(m->mNumVertices);
|
||||
std::vector<uint32_t> indices(m->mNumFaces * 3);
|
||||
std::vector<uint32_t> indices((size_t)m->mNumFaces * 3);
|
||||
LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size());
|
||||
LOG_TRACE("Mesh {}: index count {}", i, indices.size());
|
||||
|
||||
@ -219,9 +219,9 @@ namespace engine::util {
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < indices.size() / 3; j++) {
|
||||
indices[j * 3 + 0] = m->mFaces[j].mIndices[0];
|
||||
indices[j * 3 + 1] = m->mFaces[j].mIndices[1];
|
||||
indices[j * 3 + 2] = m->mFaces[j].mIndices[2];
|
||||
indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0];
|
||||
indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1];
|
||||
indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2];
|
||||
}
|
||||
meshes.push_back(std::make_shared<resources::Mesh>(parent->app()->gfx(), vertices, indices));
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ namespace engine {
|
||||
return supportsPresent;
|
||||
}
|
||||
|
||||
/* chooses a device, creates it, gets its function pointers, and creates command pools */
|
||||
Device createDevice(VkInstance instance, DeviceRequirements requirements, VkSurfaceKHR surface)
|
||||
/* chooses a device, creates it, gets its function pointers, and retrieves queues */
|
||||
Device createDevice(VkInstance instance, const DeviceRequirements& requirements, VkSurfaceKHR surface)
|
||||
{
|
||||
Device d{};
|
||||
|
||||
@ -187,14 +187,21 @@ namespace engine {
|
||||
if (devFeatures.inheritedQueries == VK_FALSE) continue;
|
||||
}
|
||||
|
||||
if (requirements.sampledImageLinearFilter == true) {
|
||||
// check for linear filtering for mipmaps
|
||||
VkFormatProperties formatProperties{};
|
||||
vkGetPhysicalDeviceFormatProperties(physDev, VK_FORMAT_R8G8B8A8_SRGB, &formatProperties);
|
||||
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
|
||||
continue;
|
||||
bool formatsSupported = true;
|
||||
for (const FormatRequirements& formatRequirements : requirements.formats) {
|
||||
VkFormatFeatureFlags requiredLinearFlags = formatRequirements.properties.linearTilingFeatures;
|
||||
VkFormatFeatureFlags requiredOptimalFlags = formatRequirements.properties.optimalTilingFeatures;
|
||||
VkFormatFeatureFlags requiredBufferFlags = formatRequirements.properties.bufferFeatures;
|
||||
VkFormatProperties deviceFormatProperties{};
|
||||
vkGetPhysicalDeviceFormatProperties(physDev, formatRequirements.format, &deviceFormatProperties);
|
||||
if ((deviceFormatProperties.linearTilingFeatures & requiredLinearFlags) != requiredLinearFlags ||
|
||||
(deviceFormatProperties.optimalTilingFeatures & requiredOptimalFlags) != requiredOptimalFlags ||
|
||||
(deviceFormatProperties.bufferFeatures & requiredBufferFlags) != requiredBufferFlags) {
|
||||
formatsSupported = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (formatsSupported == false) continue;
|
||||
|
||||
/* USE THIS PHYSICAL DEVICE */
|
||||
d.physicalDevice = physDev;
|
||||
@ -223,7 +230,7 @@ namespace engine {
|
||||
if (p.queueCount < 2) continue; // ideally have one queue for presenting and at least one other for rendering
|
||||
|
||||
if (p.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, i)) {
|
||||
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, static_cast<uint32_t>(i))) {
|
||||
graphicsFamily = static_cast<uint32_t>(i);
|
||||
break;
|
||||
}
|
||||
@ -233,7 +240,7 @@ namespace engine {
|
||||
for (size_t i = 0; i < queueFamilies.size(); i++) {
|
||||
VkQueueFamilyProperties p = queueFamilies[i];
|
||||
if (p.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, i)) {
|
||||
if (checkQueueFamilySupportsPresent(d.physicalDevice, surface, static_cast<uint32_t>(i))) {
|
||||
graphicsFamily = static_cast<uint32_t>(i);
|
||||
}
|
||||
}
|
||||
@ -313,7 +320,7 @@ namespace engine {
|
||||
if (transferFamily != graphicsFamily) {
|
||||
vkGetDeviceQueue(d.device, graphicsFamily, 0, &d.queues.presentQueue);
|
||||
if (queueFamilies[graphicsFamily].queueCount >= 2) {
|
||||
d.queues.drawQueues.resize(queueFamilies[graphicsFamily].queueCount - 1);
|
||||
d.queues.drawQueues.resize((size_t)queueFamilies[graphicsFamily].queueCount - 1);
|
||||
for (uint32_t i = 0; i < d.queues.drawQueues.size(); i++) {
|
||||
vkGetDeviceQueue(d.device, graphicsFamily, i + 1, &d.queues.drawQueues[i]);
|
||||
}
|
||||
@ -334,7 +341,7 @@ namespace engine {
|
||||
vkGetDeviceQueue(d.device, graphicsFamily, 1, &d.queues.transferQueues[0]);
|
||||
// use the remaining queues for drawing
|
||||
if (queueCount >= 3) {
|
||||
d.queues.drawQueues.resize(queueCount - 2);
|
||||
d.queues.drawQueues.resize((size_t)queueCount - 2);
|
||||
for (uint32_t i = 0; i < queueCount - 2; i++) {
|
||||
vkGetDeviceQueue(d.device, graphicsFamily, i + 2, &d.queues.drawQueues[i]);
|
||||
}
|
||||
@ -357,37 +364,12 @@ namespace engine {
|
||||
d.queues.presentAndDrawQueueFamily = graphicsFamily;
|
||||
d.queues.transferQueueFamily = transferFamily;
|
||||
|
||||
/* generate command pools */
|
||||
VkCommandPoolCreateInfo poolCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0, // set individually after
|
||||
.queueFamilyIndex = 0, // set individually after
|
||||
};
|
||||
|
||||
// present queue does not need a command pool as it does not use command buffers
|
||||
|
||||
// draw command pools:
|
||||
poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
poolCreateInfo.queueFamilyIndex = graphicsFamily;
|
||||
res = vkCreateCommandPool(d.device, &poolCreateInfo, nullptr, &d.commandPools.draw);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create command pool");
|
||||
|
||||
// transfer command pools:
|
||||
poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; // buffers from this pool are often short-lived,
|
||||
// as is usually the case for transfer operations
|
||||
poolCreateInfo.queueFamilyIndex = transferFamily;
|
||||
res = vkCreateCommandPool(d.device, &poolCreateInfo, nullptr, &d.commandPools.transfer);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create command pool");
|
||||
|
||||
return d;
|
||||
|
||||
}
|
||||
|
||||
void destroyDevice(Device device)
|
||||
{
|
||||
vkDestroyCommandPool(device.device, device.commandPools.transfer, nullptr);
|
||||
vkDestroyCommandPool(device.device, device.commandPools.draw, nullptr);
|
||||
vkDestroyDevice(device.device, nullptr);
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,15 @@
|
||||
|
||||
namespace engine {
|
||||
|
||||
struct FormatRequirements {
|
||||
VkFormat format{};
|
||||
VkFormatProperties properties{};
|
||||
};
|
||||
|
||||
struct DeviceRequirements {
|
||||
std::vector<const char*> requiredExtensions;
|
||||
VkPhysicalDeviceFeatures requiredFeatures;
|
||||
bool sampledImageLinearFilter;
|
||||
std::vector<FormatRequirements> formats{};
|
||||
};
|
||||
|
||||
struct Device {
|
||||
@ -27,13 +32,9 @@ namespace engine {
|
||||
uint32_t transferQueueFamily = UINT32_MAX;
|
||||
} queues{};
|
||||
|
||||
struct CommandPools {
|
||||
VkCommandPool draw = VK_NULL_HANDLE; // use with the drawQueues
|
||||
VkCommandPool transfer = VK_NULL_HANDLE; // use with the transferQueues
|
||||
} commandPools{};
|
||||
};
|
||||
|
||||
Device createDevice(VkInstance instance, DeviceRequirements requirements, VkSurfaceKHR surface);
|
||||
Device createDevice(VkInstance instance, const DeviceRequirements& requirements, VkSurfaceKHR surface);
|
||||
void destroyDevice(Device device);
|
||||
|
||||
}
|
||||
|
@ -131,62 +131,6 @@ namespace engine {
|
||||
vkDestroySwapchainKHR(info.device, scInfo.oldSwapchain, nullptr);
|
||||
}
|
||||
|
||||
{ /* create the depth buffer */
|
||||
|
||||
sc->depthStencil.format = VK_FORMAT_D32_SFLOAT;
|
||||
|
||||
if (sc->depthStencil.image != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(info.device, sc->depthStencil.view, nullptr);
|
||||
vmaDestroyImage(sc->allocator, sc->depthStencil.image, sc->depthStencil.allocation);
|
||||
}
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.pNext = nullptr;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = sc->depthStencil.format;
|
||||
imageInfo.extent.width = sc->extent.width;
|
||||
imageInfo.extent.height = sc->extent.height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageInfo.queueFamilyIndexCount = 0; // ignored
|
||||
imageInfo.pQueueFamilyIndices = nullptr; // ignored
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VmaAllocationCreateInfo allocInfo{};
|
||||
allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
allocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||
allocInfo.priority = 1.0f;
|
||||
|
||||
res = vmaCreateImage(sc->allocator, &imageInfo, &allocInfo, &sc->depthStencil.image, &sc->depthStencil.allocation, nullptr);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create depth buffer image! Code: " + std::to_string(res));
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.pNext = nullptr;
|
||||
viewInfo.flags = 0;
|
||||
viewInfo.image = sc->depthStencil.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = sc->depthStencil.format;
|
||||
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
res = vkCreateImageView(info.device, &viewInfo, nullptr, &sc->depthStencil.view);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
/* create the render pass */
|
||||
if (sc->renderpass != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(sc->device, sc->renderpass, nullptr);
|
||||
@ -204,7 +148,7 @@ namespace engine {
|
||||
};
|
||||
VkAttachmentDescription depthStencilAttachment{
|
||||
.flags = 0,
|
||||
.format = sc->depthStencil.format,
|
||||
.format = sc->depthStencilFormat,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // the depth buffer is not used after the fragment shader
|
||||
@ -234,25 +178,38 @@ namespace engine {
|
||||
.preserveAttachmentCount = 0,
|
||||
.pPreserveAttachments = nullptr,
|
||||
};
|
||||
VkSubpassDependency dependency{
|
||||
VkSubpassDependency attachmentDependencies[2] = {
|
||||
{
|
||||
// Depth buffer
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dependencyFlags = 0,
|
||||
},
|
||||
{
|
||||
// Image Layout Transition
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dependencyFlags = 0
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||
.dependencyFlags = 0,
|
||||
},
|
||||
};
|
||||
VkRenderPassCreateInfo renderPassInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.attachmentCount = attachments.size(),
|
||||
.attachmentCount = (uint32_t)attachments.size(),
|
||||
.pAttachments = attachments.data(),
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpass,
|
||||
.dependencyCount = 1,
|
||||
.pDependencies = &dependency,
|
||||
.dependencyCount = 2,
|
||||
.pDependencies = attachmentDependencies,
|
||||
};
|
||||
res = vkCreateRenderPass(sc->device, &renderPassInfo, nullptr, &sc->renderpass);
|
||||
if (res != EXIT_SUCCESS) throw std::runtime_error("Failed to create renderpass!");
|
||||
@ -266,21 +223,31 @@ namespace engine {
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
/* create image view and framebuffer for each image */
|
||||
sc->images.resize(swapchainImageCount);
|
||||
if (sc->swapchainImages.size() == 0) {
|
||||
sc->swapchainImages.resize(swapchainImageCount);
|
||||
sc->depthImages.resize(swapchainImageCount);
|
||||
sc->framebuffers.resize(swapchainImageCount);
|
||||
}
|
||||
for (uint32_t i = 0; i < swapchainImageCount; i++) {
|
||||
auto& [image, imageView, framebuffer] = sc->images.at(i);
|
||||
auto& [swapchainImage, swapchainImageView] = sc->swapchainImages.at(i);
|
||||
auto& [depthImage, depthAllocation, depthImageView] = sc->depthImages.at(i);
|
||||
auto& framebuffer = sc->framebuffers.at(i);
|
||||
|
||||
if (imageView != VK_NULL_HANDLE) vkDestroyImageView(sc->device, imageView, nullptr);
|
||||
if (swapchainImageView != VK_NULL_HANDLE) vkDestroyImageView(sc->device, swapchainImageView, nullptr);
|
||||
if (depthImageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(sc->device, depthImageView, nullptr);
|
||||
vmaDestroyImage(sc->allocator, depthImage, depthAllocation);
|
||||
}
|
||||
if (framebuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(sc->device, framebuffer, nullptr);
|
||||
|
||||
image = swapchainImages[i];
|
||||
swapchainImage = swapchainImages[i];
|
||||
|
||||
/* make the image view */
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.pNext = nullptr;
|
||||
viewInfo.flags = 0;
|
||||
viewInfo.image = image;
|
||||
viewInfo.image = swapchainImage;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = sc->surfaceFormat.format;
|
||||
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
@ -292,11 +259,59 @@ namespace engine {
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VkResult res = vkCreateImageView(sc->device, &viewInfo, nullptr, &imageView);
|
||||
VkResult res = vkCreateImageView(sc->device, &viewInfo, nullptr, &swapchainImageView);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create image view from swapchain image!");
|
||||
|
||||
/* create the depth buffer */
|
||||
|
||||
VkImageCreateInfo depthImageInfo{};
|
||||
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
depthImageInfo.pNext = nullptr;
|
||||
depthImageInfo.flags = 0;
|
||||
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
depthImageInfo.format = sc->depthStencilFormat;
|
||||
depthImageInfo.extent.width = sc->extent.width;
|
||||
depthImageInfo.extent.height = sc->extent.height;
|
||||
depthImageInfo.extent.depth = 1;
|
||||
depthImageInfo.mipLevels = 1;
|
||||
depthImageInfo.arrayLayers = 1;
|
||||
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
depthImageInfo.queueFamilyIndexCount = 0; // ignored
|
||||
depthImageInfo.pQueueFamilyIndices = nullptr; // ignored
|
||||
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VmaAllocationCreateInfo depthAllocInfo{};
|
||||
depthAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
depthAllocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||
depthAllocInfo.priority = 1.0f;
|
||||
|
||||
res = vmaCreateImage(sc->allocator, &depthImageInfo, &depthAllocInfo, &depthImage, &depthAllocation, nullptr);
|
||||
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create depth buffer image! Code: " + std::to_string(res));
|
||||
|
||||
VkImageViewCreateInfo depthViewInfo{};
|
||||
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
depthViewInfo.pNext = nullptr;
|
||||
depthViewInfo.flags = 0;
|
||||
depthViewInfo.image = depthImage;
|
||||
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthViewInfo.format = sc->depthStencilFormat;
|
||||
depthViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
depthViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
depthViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
depthViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
depthViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthViewInfo.subresourceRange.baseMipLevel = 0;
|
||||
depthViewInfo.subresourceRange.levelCount = 1;
|
||||
depthViewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
depthViewInfo.subresourceRange.layerCount = 1;
|
||||
res = vkCreateImageView(info.device, &depthViewInfo, nullptr, &depthImageView);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
std::array<VkImageView, 2> attachments {
|
||||
imageView, sc->depthStencil.view
|
||||
swapchainImageView, depthImageView
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo fbInfo{};
|
||||
@ -304,7 +319,7 @@ namespace engine {
|
||||
fbInfo.pNext = nullptr;
|
||||
fbInfo.flags = 0;
|
||||
fbInfo.renderPass = sc->renderpass;
|
||||
fbInfo.attachmentCount = attachments.size();
|
||||
fbInfo.attachmentCount = (uint32_t)attachments.size();
|
||||
fbInfo.pAttachments = attachments.data();
|
||||
fbInfo.width = sc->extent.width;
|
||||
fbInfo.height = sc->extent.height;
|
||||
@ -319,13 +334,18 @@ namespace engine {
|
||||
|
||||
void destroySwapchain(const Swapchain& sc)
|
||||
{
|
||||
for (const auto& [image, view, framebuffer] : sc.images) {
|
||||
for (VkFramebuffer framebuffer : sc.framebuffers) {
|
||||
vkDestroyFramebuffer(sc.device, framebuffer, nullptr);
|
||||
}
|
||||
for (const auto& [image, view] : sc.swapchainImages) {
|
||||
vkDestroyImageView(sc.device, view, nullptr);
|
||||
}
|
||||
for (const auto& [image, allocation, view] : sc.depthImages) {
|
||||
vkDestroyImageView(sc.device, view, nullptr);
|
||||
vmaDestroyImage(sc.allocator, image, allocation);
|
||||
}
|
||||
|
||||
vkDestroyRenderPass(sc.device, sc.renderpass, nullptr);
|
||||
vkDestroyImageView(sc.device, sc.depthStencil.view, nullptr);
|
||||
vmaDestroyImage(sc.allocator, sc.depthStencil.image, sc.depthStencil.allocation);
|
||||
vkDestroySwapchainKHR(sc.device, sc.swapchain, nullptr);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,12 @@
|
||||
|
||||
namespace engine {
|
||||
|
||||
struct DepthStencil {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
struct Swapchain {
|
||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||
VkDevice device = VK_NULL_HANDLE; // the associated device
|
||||
@ -20,13 +26,10 @@ namespace engine {
|
||||
VkPresentModeKHR presentMode{};
|
||||
VkExtent2D extent{};
|
||||
VkRenderPass renderpass = VK_NULL_HANDLE;
|
||||
std::vector<std::tuple<VkImage, VkImageView, VkFramebuffer>> images{};
|
||||
struct DepthStencil {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
VkFormat format{};
|
||||
} depthStencil{};
|
||||
const VkFormat depthStencilFormat = VK_FORMAT_D16_UNORM;
|
||||
std::vector<std::pair<VkImage, VkImageView>> swapchainImages{};
|
||||
std::vector<DepthStencil> depthImages{};
|
||||
std::vector<VkFramebuffer> framebuffers{};
|
||||
};
|
||||
|
||||
struct SwapchainInfo {
|
||||
|
@ -161,6 +161,10 @@ void CameraControllerSystem::onUpdate(float ts)
|
||||
m_scene->app()->window()->toggleFullscreen();
|
||||
}
|
||||
|
||||
if (m_scene->app()->inputManager()->getButtonPress("exit")) {
|
||||
m_scene->app()->window()->setCloseFlag();
|
||||
}
|
||||
|
||||
c->justCollided = false;
|
||||
|
||||
}
|
||||
|
@ -21,10 +21,13 @@
|
||||
|
||||
#include "util/model_loader.hpp"
|
||||
|
||||
#include "game.hpp"
|
||||
|
||||
static void configureInputs(engine::InputManager* inputManager)
|
||||
{
|
||||
// user interface mappings
|
||||
inputManager->addInputButton("fullscreen", engine::inputs::Key::K_F11);
|
||||
inputManager->addInputButton("exit", engine::inputs::Key::K_ESCAPE);
|
||||
// game buttons
|
||||
inputManager->addInputButton("fire", engine::inputs::MouseButton::M_LEFT);
|
||||
inputManager->addInputButton("aim", engine::inputs::MouseButton::M_RIGHT);
|
||||
@ -38,17 +41,19 @@ static void configureInputs(engine::InputManager* inputManager)
|
||||
inputManager->addInputAxis("looky", engine::inputs::MouseAxis::Y);
|
||||
}
|
||||
|
||||
void playGame(bool enableFrameLimiter)
|
||||
void playGame(GameSettings settings)
|
||||
{
|
||||
LOG_INFO("FPS limiter: {}", enableFrameLimiter ? "ON" : "OFF");
|
||||
LOG_INFO("FPS limiter: {}", settings.enableFrameLimiter ? "ON" : "OFF");
|
||||
LOG_INFO("Graphics Validation: {}", settings.enableValidation ? "ON" : "OFF");
|
||||
|
||||
engine::gfx::GraphicsSettings graphicsSettings{};
|
||||
graphicsSettings.enableValidation = settings.enableValidation;
|
||||
graphicsSettings.vsync = true;
|
||||
graphicsSettings.waitForPresent = false;
|
||||
graphicsSettings.msaaLevel = engine::gfx::MSAALevel::MSAA_OFF;
|
||||
engine::Application app(PROJECT_NAME, PROJECT_VERSION, graphicsSettings);
|
||||
|
||||
app.setFrameLimiter(enableFrameLimiter);
|
||||
app.setFrameLimiter(settings.enableFrameLimiter);
|
||||
|
||||
// configure window
|
||||
app.window()->setRelativeMouseMode(true);
|
||||
@ -100,8 +105,8 @@ void playGame(bool enableFrameLimiter)
|
||||
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("builtin.skybox"));
|
||||
skyboxRenderable->material->m_texture = spaceTexture;
|
||||
// skyboxRenderable->mesh = genSphereMesh(app.gfx(), 1.0f, 50, true);
|
||||
skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 2.0f, 2.0f, 2.0f, 1.0f, true);
|
||||
myScene->getComponent<engine::TransformComponent>(skybox)->position = { -1.0f, -1.0f, -1.0f };
|
||||
skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 10.0f, 10.0f, 10.0f, 1.0f, true);
|
||||
myScene->getComponent<engine::TransformComponent>(skybox)->position = { -5.0f, -5.0f, -5.0f };
|
||||
}
|
||||
|
||||
/* cube */
|
||||
@ -127,6 +132,8 @@ void playGame(bool enableFrameLimiter)
|
||||
floorCollider->aabb = { { 0.0f, 0.0f, 0.0f }, { 10000.0f, 1.0f, 10000.0f } };
|
||||
}
|
||||
|
||||
//engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/astronaut/astronaut.dae"));
|
||||
|
||||
app.gameLoop();
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
void playGame(bool enableFrameLimiter);
|
||||
struct GameSettings {
|
||||
bool enableFrameLimiter;
|
||||
bool enableValidation;
|
||||
};
|
||||
|
||||
void playGame(GameSettings settings);
|
||||
|
@ -7,14 +7,22 @@
|
||||
|
||||
// standard library
|
||||
#include <exception>
|
||||
#include <unordered_set>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
bool enableFrameLimiter = true;
|
||||
if (argc == 2) {
|
||||
if (strcmp(argv[1], "nofpslimit") == 0) enableFrameLimiter = false;
|
||||
GameSettings settings{};
|
||||
settings.enableFrameLimiter = true;
|
||||
settings.enableValidation = false;
|
||||
if (argc >= 2) {
|
||||
std::unordered_set<std::string> args{};
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
args.insert(std::string(argv[i]));
|
||||
}
|
||||
if (args.contains("nofpslimit")) settings.enableFrameLimiter = false;
|
||||
if (args.contains("gpuvalidation")) settings.enableValidation = true;
|
||||
}
|
||||
|
||||
engine::setupLog(PROJECT_NAME);
|
||||
@ -22,7 +30,7 @@ int main(int argc, char* argv[])
|
||||
LOG_INFO("{} v{}", PROJECT_NAME, PROJECT_VERSION);
|
||||
|
||||
try {
|
||||
playGame(enableFrameLimiter);
|
||||
playGame(settings);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOG_CRITICAL("{}", e.what());
|
||||
|
Loading…
Reference in New Issue
Block a user