Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ ENGINE_NAME := quark
GLSLC ?= glslc
SHADERS_OUT_DIR := shaders/bin

SHADER_SRC_DIR := src/backend/shaders
SHADER_INC_DIR := $(SHADER_SRC_DIR)/include

SHADER_VERT := $(SHADER_SRC_DIR)/shader.vert
SHADER_FRAG := $(SHADER_SRC_DIR)/shader.frag
SHADER_COMMON := $(SHADER_INC_DIR)/common.glsl

SHADER_VERT_SPV := $(SHADERS_OUT_DIR)/shader.vert.spv
SHADER_FRAG_SPV := $(SHADERS_OUT_DIR)/shader.frag.spv

# PIN TO A HASH IN A BETTER WAY THAN THIS?
VCPKG_COMMIT := 11bbc873e00e9e58d4e9dffb30b7a5493a030e0b

Expand Down Expand Up @@ -86,10 +96,16 @@ format-check:
-print0 | xargs -0 clang-format -n -Werror

# TODO: make obsolete by vulkan's internal API
shaders:
shaders: $(SHADER_VERT_SPV) $(SHADER_FRAG_SPV)

$(SHADERS_OUT_DIR):
@mkdir -p $(SHADERS_OUT_DIR)
@$(GLSLC) src/backend/shaders/shader.vert -o $(SHADERS_OUT_DIR)/shader.vert.spv
@$(GLSLC) src/backend/shaders/shader.frag -o $(SHADERS_OUT_DIR)/shader.frag.spv

$(SHADER_VERT_SPV): $(SHADER_VERT) $(SHADER_COMMON) | $(SHADERS_OUT_DIR)
@$(GLSLC) -I$(SHADER_INC_DIR) $(SHADER_VERT) -o $@

$(SHADER_FRAG_SPV): $(SHADER_FRAG) $(SHADER_COMMON) | $(SHADERS_OUT_DIR)
@$(GLSLC) -I$(SHADER_INC_DIR) $(SHADER_FRAG) -o $@

clean:
rm -rf $(BUILD_DIR)
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The engine shall support

Advanced possible supports
- Virtualized Geometry
- Global Illumination

The game that shall be made with this engine is a game with movement inspired by quake.
The game shall feature older-quake-like graphics and will likely have a single player,
Expand All @@ -28,17 +29,25 @@ The focus of this game engine is to make a game playable on all devices with lit
- [x] Albedos (start of PBR)
- [x] Diffuse option
- [x] material SSBO (PBR)
- [ ] gITF imports
- [x] gITF imports
- [x] mesh import
- [x] base texture/material
- [ ] normals
- [ ] other PBR
- [ ] PBR API for non imports
- [x] normals
- [x] other PBR
- [x] lighting
- [x] PBR API for non imports
- [x] Vulkan Memory Allocator (VMA) refactor
- [ ] Mipmaps
- [ ] Depth pre-pass
- [ ] Forward+ lighting
- [ ] offscreen intermediate pass

## MVP 2
- [ ] Editor
- [ ] Job System
- Basic Multithreading for uploader [x]
- Dynamic picking of threads for jobs [ ]
- [ ] ECS
- [ ] Mipmaps

- [ ] Basic physics engine
- [ ] Player Controller
Binary file added assets/tree2.glb
Binary file not shown.
95 changes: 89 additions & 6 deletions src/backend/core/vk_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,91 @@ bool VkDeviceCtx::createLogicalDevice() {
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;

VkPhysicalDeviceFeatures deviceFeatures{};
VkPhysicalDeviceVulkan12Features supVk12{};
supVk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;

VkPhysicalDeviceDynamicRenderingFeatures supDyn{};
supDyn.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;

VkPhysicalDeviceFeatures2 supFeats2{};
supFeats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
supFeats2.pNext = &supVk12;
supVk12.pNext = &supDyn;

vkGetPhysicalDeviceFeatures2(m_physicalDevice, &supFeats2);

const bool hasUniformNonUniform =
(supVk12.shaderUniformBufferArrayNonUniformIndexing == VK_TRUE);

const bool hasStorageNonUniform =
(supVk12.shaderStorageBufferArrayNonUniformIndexing == VK_TRUE);

const bool hasSampledImageNonUniform =
(supVk12.shaderSampledImageArrayNonUniformIndexing == VK_TRUE);

const bool hasPartiallyBound =
(supVk12.descriptorBindingPartiallyBound == VK_TRUE);

const bool hasUniformUAB =
(supVk12.descriptorBindingUniformBufferUpdateAfterBind == VK_TRUE);

const bool hasStorageUAB =
(supVk12.descriptorBindingStorageBufferUpdateAfterBind == VK_TRUE);

const bool hasSampledImageUAB =
(supVk12.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE);

const bool hasRuntimeArray = (supVk12.runtimeDescriptorArray == VK_TRUE);

if (!hasUniformNonUniform || !hasStorageNonUniform ||
!hasSampledImageNonUniform || !hasPartiallyBound || !hasUniformUAB ||
!hasStorageUAB || !hasSampledImageUAB) {
LOGE("Bindless textures not supported on this device");
LOGE(" shaderUniformBufferArrayNonUniformIndexing= {}",
hasUniformNonUniform ? "YES" : "NO");
LOGE(" shaderStorageBufferArrayNonUniformIndexing= {}",
hasStorageNonUniform ? "YES" : "NO");
LOGE(" shaderSampledImageArrayNonUniformIndexing = {}",
hasSampledImageNonUniform ? "YES" : "NO");
LOGE(" descriptorBindingPartiallyBound = {}",
hasPartiallyBound ? "YES" : "NO");
LOGE(" descriptorBindingUniformBufferUpdateAfterBind = {}",
hasUniformUAB ? "YES" : "NO");
LOGE(" descriptorBindingStorageBufferUpdateAfterBind= {}",
hasStorageUAB ? "YES" : "NO");
LOGE(" descriptorBindingSampledImageUpdateAfterBind = {}",
hasSampledImageUAB ? "YES" : "NO");
LOGE(" runtimeDescriptorArray = {}", hasRuntimeArray ? "YES" : "NO");
return false;
}

VkPhysicalDeviceDynamicRenderingFeatures dyn{};
dyn.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
dyn.dynamicRendering = VK_TRUE;
VkPhysicalDeviceVulkan12Features enVk12{};
enVk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
enVk12.shaderUniformBufferArrayNonUniformIndexing = VK_TRUE;
enVk12.shaderStorageBufferArrayNonUniformIndexing = VK_TRUE;
enVk12.shaderSampledImageArrayNonUniformIndexing = VK_TRUE;
enVk12.descriptorBindingPartiallyBound = VK_TRUE;
enVk12.descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE;
enVk12.descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE;
enVk12.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE;
enVk12.runtimeDescriptorArray = hasRuntimeArray ? VK_TRUE : VK_FALSE;

VkPhysicalDeviceDynamicRenderingFeatures enDyn{};
enDyn.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
enDyn.dynamicRendering = VK_TRUE;

VkPhysicalDeviceFeatures2 enabledFeats2{};
enabledFeats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
enabledFeats2.pNext = &enVk12;
enVk12.pNext = &enDyn;

enabledFeats2.features = VkPhysicalDeviceFeatures{};

VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pNext = &dyn;
createInfo.pNext = &enabledFeats2;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.pEnabledFeatures = &deviceFeatures;

createInfo.enabledExtensionCount =
static_cast<uint32_t>(kDeviceExtensions.size());
Expand All @@ -293,5 +366,15 @@ bool VkDeviceCtx::createLogicalDevice() {
&m_queues.graphics);
m_queues.graphicsFamily = indices.graphicsFamily.value();

LOGI("Enabled bindless features:");
LOGI(" shaderUniformBufferArrayNonUniformIndexing=YES");
LOGI(" shaderStorageBufferArrayNonUniformIndexing=YES");
LOGI(" shaderSampledImageArrayNonUniformIndexing=YES");
LOGI(" descriptorBindingPartiallyBound=YES");
LOGI(" descriptorBindingUniformBufferUpdateAfterBind=YES");
LOGI(" descriptorBindingStorageBufferUpdateAfterBind=YES");
LOGI(" descriptorBindingSampledImageUpdateAfterBind=YES");
LOGI(" runtimeDescriptorArray={}", hasRuntimeArray ? "YES" : "NO");

return true;
}
1 change: 0 additions & 1 deletion src/backend/core/vk_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
(void)messageTypes;
(void)pUserData;

// TODO: fix
LOGE("Validation layer: {}", pCallbackData->pMessage);
return VK_FALSE;
}
Expand Down
85 changes: 38 additions & 47 deletions src/backend/gpu/descriptors/vk_material_sets.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
#include "backend/gpu/descriptors/vk_material_sets.hpp"

#include "backend/gpu/textures/vk_texture.hpp"
#include "backend/profiling/telemetry/telemetry.hpp"
#include "engine/logging/log.hpp"

#include <cstdint>
#include <iostream>
#include <fmt/format.h>
#include <vulkan/vulkan_core.h>

bool VkMaterialSets::init(VkDevice device, VkDescriptorSetLayout layout,
uint32_t maxMaterials) {
if (device == VK_NULL_HANDLE || layout == VK_NULL_HANDLE ||
maxMaterials == 0) {
std::cerr << "[MaterialSets] Invalid init args\n";
uint32_t maxTextures) {
if (layout == VK_NULL_HANDLE || maxTextures == 0) {
LOGE("Invalid initlization args");
return false;
}

shutdown();

m_device = device;
m_layout = layout;
m_maxTextures = maxTextures;

VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSize.descriptorCount = maxMaterials;
poolSize.descriptorCount = maxTextures;

VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.maxSets = maxMaterials;
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
poolInfo.maxSets = 1;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;

VkResult res = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &m_pool);
if (res != VK_SUCCESS) {
std::cerr << "[MaterialSets] vkCreateDescriptorPool failed: " << res
<< "\n";
LOGE("vkCreateDescriptorPool failed: {}", fmt::underlying(res));
shutdown();
return false;
}

VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = m_pool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &m_layout;

res = vkAllocateDescriptorSets(m_device, &allocInfo, &m_set);
if (res != VK_SUCCESS) {
LOGE("vkAllocateDescriptorSets failed: {}", fmt::underlying(res));
shutdown();
return false;
}

m_sets.reserve(maxMaterials);
return true;
}

Expand All @@ -49,65 +63,42 @@ void VkMaterialSets::shutdown() noexcept {
}

m_pool = VK_NULL_HANDLE;
m_sets.clear();
m_layout = VK_NULL_HANDLE;
m_set = VK_NULL_HANDLE;
m_device = VK_NULL_HANDLE;
m_maxTextures = 0;
}

uint32_t VkMaterialSets::allocateForTexture(const VkTexture2D &tex) {
if (m_device == VK_NULL_HANDLE || m_pool == VK_NULL_HANDLE ||
m_layout == VK_NULL_HANDLE) {
std::cerr << "[MaterialSets] Not initialized\n";
return UINT32_MAX;
}

if (!tex.valid()) {
std::cerr << "[MaterialSets] Invalid texture\n";
return UINT32_MAX;
}

VkDescriptorSet set = VK_NULL_HANDLE;
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = m_pool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &m_layout;

VkResult res = vkAllocateDescriptorSets(m_device, &allocInfo, &set);
if (res != VK_SUCCESS) {
std::cerr << "[MaterialSets] vkAllocateDescriptorSets failed: " << res
<< "\n";
return UINT32_MAX;
bool VkMaterialSets::writeTexture(uint32_t slot, const VkTexture2D &texture) {
if (!texture.valid() || slot >= m_maxTextures || m_set == VK_NULL_HANDLE) {
return false;
}

VkDescriptorImageInfo imgInfo{};
imgInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imgInfo.imageView = tex.view;
imgInfo.sampler = tex.sampler;
imgInfo.imageView = texture.view;
imgInfo.sampler = texture.sampler;

VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = set;
write.dstSet = m_set;
write.dstBinding = 0;
write.dstArrayElement = slot;
write.descriptorCount = 1;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.pImageInfo = &imgInfo;

vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);

const uint32_t idx = static_cast<uint32_t>(m_sets.size());
m_sets.push_back(set);

return idx;
return true;
}

void VkMaterialSets::bind(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout,
uint32_t setIndex, uint32_t materialIndex) const {
if (materialIndex >= m_sets.size()) {
uint32_t setIndex) const {
if (m_set == VK_NULL_HANDLE) {
return;
}

VkDescriptorSet set = m_sets[materialIndex];
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout,
setIndex, 1, &set, 0, nullptr);
setIndex, 1, &m_set, 0, nullptr);
PROFILE_CPU_INC_DESCRIPTOR_BINDS(1);
}
16 changes: 8 additions & 8 deletions src/backend/gpu/descriptors/vk_material_sets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include <cstdint>
#include <utility>
#include <vector>
#include <vulkan/vulkan_core.h>

class VkMaterialSets {
Expand All @@ -26,22 +25,21 @@ class VkMaterialSets {
m_device = std::exchange(other.m_device, VK_NULL_HANDLE);
m_pool = std::exchange(other.m_pool, VK_NULL_HANDLE);
m_layout = std::exchange(other.m_layout, VK_NULL_HANDLE);
m_sets = std::move(other.m_sets);
m_set = std::move(other.m_set);

return *this;
}

bool init(VkDevice device, VkDescriptorSetLayout layout,
uint32_t maxMaterials);
uint32_t maxTextures);
void shutdown() noexcept;

// TODO: change name to allocateBaseColorMaterial and then add
// allocatePbrMaterial
uint32_t allocateForTexture(const VkTexture2D &tex);
bool writeTexture(uint32_t slot, const VkTexture2D &texture);

void bind(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout,
uint32_t setIndex, uint32_t materialIndex) const;
uint32_t setIndex) const;

[[nodiscard]] VkDescriptorSet set() const noexcept { return m_set; }
[[nodiscard]] VkDescriptorSetLayout layout() const noexcept {
return m_layout;
}
Expand All @@ -50,5 +48,7 @@ class VkMaterialSets {
VkDevice m_device = VK_NULL_HANDLE; // non-owning
VkDescriptorPool m_pool = VK_NULL_HANDLE; // non-owning
VkDescriptorSetLayout m_layout = VK_NULL_HANDLE; // non-owning
std::vector<VkDescriptorSet> m_sets;
VkDescriptorSet m_set = VK_NULL_HANDLE;

uint32_t m_maxTextures = 0; // non-owning
};
Loading