1
0
Fork 0

Compare commits

..

1 Commits

Author SHA1 Message Date
May B. a774e99d7b WIP: Vulkan skybox (bug on intel mesa ???) 2020-10-11 11:59:32 +02:00
28 changed files with 495 additions and 302 deletions

BIN
resource/content/shaders/Sky.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.geo.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.ins.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.fs.spv (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.geo.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.ins.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.spv (Stored with Git LFS)

Binary file not shown.

View File

@ -1,9 +1,9 @@
#version 450 core
layout(push_constant) uniform PushConstants {
mat4 View;
mat4 Projection;
} Push;
layout(binding = 0) uniform UniformBufferObject {
mat4 view;
mat4 proj;
} ubo;
layout (location = 0) in vec3 Position_modelspace;
@ -11,5 +11,7 @@ layout (location = 0) out vec3 UV;
void main(){
UV = Position_modelspace;
gl_Position = (Push.Projection * Push.View * vec4(Position_modelspace, 1.0)).xyww;
mat4 view = ubo.view;
view[3] = vec4(0.0f, 0.0f, 0.0f, 1.0f);
gl_Position = (ubo.proj * view * vec4(Position_modelspace, 1.0)).xyww;
}

View File

@ -2,10 +2,12 @@
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
layout(push_constant) uniform PushConst {
mat4 model;
} Push;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
@ -15,7 +17,7 @@ layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
gl_Position = ubo.proj * ubo.view * Push.model * vec4(inPosition, 1.0);
fragColor = inColor;
fragTexCoord = inTexCoord;
}

View File

@ -10,26 +10,18 @@ layout (constant_id = 4) const bool BLEND = true;
layout (constant_id = 16) const int UNIT_SIZE = 8;
layout (binding = 0) uniform UniformBufferObject {
vec3 FogColor;
float FogDepth;
mat4 Proj;
mat4 View;
vec3 LightInvDirection_worldspace;
vec3 FogColor;
float FogDepth;
} UBO;
layout (binding = 1) uniform sampler2DArray TextureAtlas;
layout (binding = 2) uniform sampler2DArray NormalAtlas;
layout (binding = 3) uniform sampler2DArray HOSAtlas;
layout(push_constant) uniform PushConstants {
mat4 Proj;
mat4 View;
#ifndef INSTANCED
mat4 Model;
#endif
vec4 SphereProj;
float Curvature;
} Push;
#ifdef GEOMETRY
layout (location = 0) in GeometryData
#else
@ -189,7 +181,7 @@ if(PBR) {
vec3 TextureAmbientColor = vec3(.1) * TextureDiffuseColor * texHOS.y;
vec3 TextureSpecularColor = vec3(.8) * texHOS.z;
vec3 Normal_cameraspace = normalize((Push.View * vec4(worldNormal,0)).xyz);
vec3 Normal_cameraspace = normalize((UBO.View * vec4(worldNormal,0)).xyz);
// Light emission properties
// You probably want to put them as uniforms

View File

@ -8,15 +8,16 @@ layout (constant_id = 5) const bool DO_CURVATURE = false;
layout (constant_id = 6) const bool CURV_DEPTH = true;
layout (binding = 0) uniform UniformBufferObject {
vec3 FogColor;
float FogDepth;
mat4 Proj;
mat4 View;
vec3 LightInvDirection_worldspace;
vec3 FogColor;
float FogDepth;
} UBO;
layout(push_constant) uniform PushConstants {
mat4 Proj; //MAYBE: move Proj View to UBO
mat4 View;
#ifndef INSTANCED
mat4 Model;
#endif
@ -63,8 +64,8 @@ if(DO_CURVATURE) {
}
}
vec4 Position_cameraspace = Push.View * Model * vec4(vs.Position_modelspace, 1);
gl_Position = Push.Proj * Position_cameraspace;
vec4 Position_cameraspace = UBO.View * Model * vec4(vs.Position_modelspace, 1);
gl_Position = UBO.Proj * Position_cameraspace;
if(FOG) {
vs.Depth = length(Position_cameraspace.xyz) / UBO.FogDepth;
@ -82,6 +83,6 @@ if(PBR) {
vs.EyeDirection_cameraspace = vec3(0,0,0) - Position_cameraspace.xyz;
// Vector that goes from the vertex to the light, in camera space
vs.LightDirection_cameraspace = (Push.View * vec4(UBO.LightInvDirection_worldspace,0)).xyz;
vs.LightDirection_cameraspace = (UBO.View * vec4(UBO.LightInvDirection_worldspace,0)).xyz;
}
}

View File

@ -14,6 +14,7 @@ void Camera::updateProjection() {
void Camera::update() {
const auto &offset = origin->position.offset;
// FIXME: up inverted after backflip
const auto axis = origin->getAxis();
// Camera matrix
ViewMatrix = glm::lookAt(

View File

@ -73,23 +73,24 @@ public:
};
struct requirement: properties {
requirement(const properties& props, Layout layout, Usage usage, Aspect aspect,
int samples = 1, uint32_t depth = 1, uint32_t layers = 1, bool optimal = true):
int samples = 1, uint32_t layers = 1, bool cube = false, bool optimal = true):
properties(props), layout(layout), usage(usage), aspect(aspect), samples(samples),
depth(depth), layers(layers), optimal(optimal)
layers(layers), cube(cube), optimal(optimal)
{
assert(samples > 0 && (std::ceil(std::log2(samples)) == std::floor(std::log2(samples))) && "Samples must be pow2");
assert(!cube || layers == 6);
}
Layout layout;
Usage usage;
Aspect aspect;
//NOTE: matches VkSampleCountFlagBits
int samples;
uint32_t depth;
uint32_t layers;
bool cube;
bool optimal;
static requirement Texture(const properties &props, bool cube = false, uint32_t arraySize = 1) {
return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR, 1, cube ? 6 : 1, arraySize); }
static requirement Texture(const properties &props, uint32_t arraySize = 1, bool cube = false) {
return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR, 1, arraySize, cube); }
};
static std::optional<properties> Read(const std::string&, std::vector<unsigned char>& data);

View File

@ -257,7 +257,7 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay
submitCmd(graphicsBuffer, graphicsQueue);
}
void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height, uint32_t mipLevels, uint32_t depth, uint32_t arrayLayer) {
void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height, uint32_t mipLevels, uint32_t arrayLayer) {
beginCmd(transferBuffer);
@ -269,8 +269,8 @@ void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, ui
regions[i].imageSubresource.baseArrayLayer = arrayLayer;
regions[i].imageSubresource.layerCount = 1;
regions[i].imageOffset = {0, 0, depth+0};
regions[i].imageExtent = {width >> i, height >> i, depth+1};
regions[i].imageOffset = {0, 0, 0};
regions[i].imageExtent = {width >> i, height >> i, 1};
regions[i].bufferOffset = offset;
regions[i].bufferRowLength = std::max<uint32_t>(4, regions[i].imageExtent.width);

View File

@ -38,7 +38,7 @@ public:
void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, uint32_t arrayLayers);
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1, uint32_t depth = 0, uint32_t arrayLayer = 0);
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1, uint32_t arrayLayer = 0);
void setTracyZone(const char* name);

View File

@ -16,24 +16,38 @@ CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, co
VkCommandPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.queueFamilyIndex = info.queueIndices.graphicsFamily.value();
poolInfo.flags = 0;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
if (vkCreateCommandPool(device, &poolInfo, ALLOC, &graphicsPool) != VK_SUCCESS) {
FATAL("Failed to create graphics pool!");
}
}
{ // Vertex buffers (const)
modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices);
if (!modelBuffer) {
FATAL("Cannot create vertex buffer");
}
modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices);
if (!modelBuffer) {
FATAL("Cannot create vertex buffer");
}
{ // Texture sampler (const)
sampleTexture = Texture::LoadFromFile(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy});
if (!sampleTexture) {
FATAL("Failed to create texture sampler!");
}
sampleTexture = Texture::LoadFromFile(TEXTURES_DIR + opt.textures + "/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy});
if (!sampleTexture) {
FATAL("Failed to create texture sampler!");
}
skyCubeBuffer = Shape::Create({
{-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f},
{-1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f},
{ 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f},
{-1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f},
{-1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, -1.0f}, { 1.0f, 1.0f, 1.0f}, { 1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f},
{-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, -1.0f}, { 1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, { 1.0f, -1.0f, 1.0f}
});
if (!skyCubeBuffer) {
FATAL("Failed to create vertex buffer!");
}
skyboxTexture = TextureCube::LoadFromFiles(TEXTURES_DIR + opt.textures + "/sky/Space_tray.cube", {});
if (!skyboxTexture) {
FATAL("Failed to create texture sampler!");
}
colorFormat = info.getSurfaceFormat().format;
colorSamples = info.samples;
LOG_D("Samples: " << colorSamples);
@ -51,7 +65,7 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
if (colorSamples > 1) {
colorbuffer = Image::Create(Image::requirement({{extent.height, extent.width}, 1, (Image::Format)colorFormat},
Image::Layout::COLOR_ATTACHMENT, Image::Usage::COLOR_ATTACHMENT | Image::Usage::TRANSIENT_ATTACHMENT,
Image::Layout::COLOR_ATTACHMENT, Image::Usage::COLOR_ATTACHMENT | Image::Usage::TRANSIENT_ATTACHMENT, // NOTE: VulkanTutorial#118
Image::Aspect::COLOR, colorSamples));
}
@ -84,16 +98,14 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
}
{ // Uniform buffers
VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject);
std::vector<Buffer::requirement> requirements;
requirements.resize(framebuffers.size(), Buffer::requirement(bufferSize, Buffer::Usage::UNIFORM));
requirements.resize(framebuffers.size(), Buffer::requirement(sizeof(buffer::vk::UniformBufferObject), Buffer::Usage::UNIFORM));
uniformBuffers.allocate(requirements, true);
if (!uniformBuffers) {
FATAL("Failed to allocate UBO");
}
}
{ // Descriptor pool
{ // Voxel Descriptor pool
std::array<VkDescriptorPoolSize, 2> poolSizes{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount = framebuffers.size();
@ -107,24 +119,37 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
poolInfo.maxSets = framebuffers.size();
poolInfo.flags = 0; //VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &voxelDescriptorPool) != VK_SUCCESS) {
FATAL("Failed to create descriptor pool!");
}
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &skyDescriptorPool) != VK_SUCCESS) {
FATAL("Failed to create descriptor pool!");
}
}
{ // Descriptor sets
std::vector<VkDescriptorSetLayout> layouts(framebuffers.size(), pipe.getDescriptorSet());
std::vector<VkDescriptorSetLayout> voxLayouts(framebuffers.size(), pipe.getVoxelDescriptorSet());
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorPool = voxelDescriptorPool;
allocInfo.descriptorSetCount = framebuffers.size();
allocInfo.pSetLayouts = layouts.data();
allocInfo.pSetLayouts = voxLayouts.data();
descriptorSets.resize(framebuffers.size());
if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
voxelDescriptorSets.resize(framebuffers.size());
if (vkAllocateDescriptorSets(device, &allocInfo, voxelDescriptorSets.data()) != VK_SUCCESS) {
FATAL("Failed to allocate descriptor sets!");
}
for (size_t i = 0; i < descriptorSets.size(); i++) {
std::vector<VkDescriptorSetLayout> skyLayouts(framebuffers.size(), pipe.getSkyDescriptorSet());
allocInfo.descriptorPool = skyDescriptorPool;
allocInfo.pSetLayouts = skyLayouts.data();
skyDescriptorSets.resize(framebuffers.size());
if (vkAllocateDescriptorSets(device, &allocInfo, skyDescriptorSets.data()) != VK_SUCCESS) {
FATAL("Failed to allocate descriptor sets!");
}
for (size_t i = 0; i < voxelDescriptorSets.size(); i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = uniformBuffers.at(i);
bufferInfo.offset = 0;
@ -132,7 +157,7 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = descriptorSets[i];
descriptorWrites[0].dstSet = voxelDescriptorSets[i];
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@ -140,7 +165,7 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
descriptorWrites[0].pBufferInfo = &bufferInfo;
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = descriptorSets[i];
descriptorWrites[1].dstSet = voxelDescriptorSets[i];
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@ -148,9 +173,13 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
descriptorWrites[1].pImageInfo = &sampleTexture->getDescriptor();
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
descriptorWrites[0].dstSet = skyDescriptorSets[i];
descriptorWrites[1].dstSet = skyDescriptorSets[i];
descriptorWrites[1].pImageInfo = &skyboxTexture->getDescriptor();
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
}
}
{
graphicsBuffers.resize(framebuffers.size());
VkCommandBufferAllocateInfo allocInfo{};
@ -173,13 +202,14 @@ void CommandCenter::free() {
assert(!freed);
vkFreeCommandBuffers(device, graphicsPool, static_cast<uint32_t>(graphicsBuffers.size()), graphicsBuffers.data());
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkDestroyDescriptorPool(device, voxelDescriptorPool, ALLOC);
vkDestroyDescriptorPool(device, skyDescriptorPool, ALLOC);
colorbuffer.reset();
depthbuffer.reset();
for (size_t i = 0; i < framebuffers.size(); i++) {
vkDestroyFramebuffer(device, framebuffers[i], nullptr);
vkDestroyFramebuffer(device, framebuffers[i], ALLOC);
}
freed = true;
@ -188,14 +218,9 @@ void CommandCenter::free() {
#include <chrono>
#include <memory.h>
void CommandCenter::startRecording(uint32_t idx) {
static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
void CommandCenter::startRecording(uint32_t idx, VkRenderPass renderPass, VkExtent2D extent, const glm::vec4& clear_color, glm::mat4 view, glm::mat4 proj) {
buffer::vk::UniformBufferObject ubo{};
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
ubo.view = view;
ubo.proj = proj;
uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo)));
@ -208,12 +233,10 @@ void CommandCenter::startRecording(uint32_t idx) {
if (vkBeginCommandBuffer(graphicsBuffers[idx], &beginInfo) != VK_SUCCESS) {
FATAL("Failed to begin recording command buffer!");
}
}
void CommandCenter::startWorldPass(uint32_t idx, const Pipeline &pipe, VkExtent2D extent, const glm::vec4& clear_color) {
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = pipe.getRenderPass();
renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = framebuffers[idx];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = extent;
@ -225,8 +248,20 @@ void CommandCenter::startWorldPass(uint32_t idx, const Pipeline &pipe, VkExtent2
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(graphicsBuffers[idx], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline());
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[idx], 0, nullptr);
}
void CommandCenter::startWorldPass(uint32_t idx, const Subpass &worldPass) {
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.pipeline);
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.layout, 0, 1, &voxelDescriptorSets[idx], 0, nullptr);
static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();
buffer::vk::ModelPush push{};
push.model = glm::translate(glm::mat4(1.0f), glm::vec3(98.0f, -2.f, -2.f));
push.model = glm::rotate(push.model, time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
vkCmdPushConstants(graphicsBuffers[idx], worldPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
}
void CommandCenter::recordModel(uint32_t i) {
VkBuffer vertexBuffers[] = {modelBuffer->getVertex()};
@ -236,7 +271,16 @@ void CommandCenter::recordModel(uint32_t i) {
vkCmdDrawIndexed(graphicsBuffers[i], static_cast<uint32_t>(buffer::vk::indices.size()), 1, 0, 0, 0);
}
void CommandCenter::startEntityPass(uint32_t) { }
void CommandCenter::recordPostprocess(uint32_t idx) {
void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox, glm::mat4, glm::mat4) {
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);
if (skybox) {
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.pipeline);
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, skyPass.layout, 0, 1, &skyDescriptorSets[idx], 0, nullptr);
VkBuffer vertexBuffers[] = {skyCubeBuffer->getRef()};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets);
vkCmdDraw(graphicsBuffers[idx], skyCubeBuffer->size, 1, 0, 0);
}
vkCmdEndRenderPass(graphicsBuffers[idx]);
}

View File

@ -10,18 +10,19 @@
namespace render::vk {
class SwapChain;
class Pipeline;
struct Subpass;
class CommandCenter final {
public:
CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
~CommandCenter();
void startRecording(uint32_t idx);
void startWorldPass(uint32_t idx, const Pipeline &, VkExtent2D, const glm::vec4 &clear);
void startRecording(uint32_t idx, VkRenderPass, VkExtent2D, const glm::vec4& clear, glm::mat4 view, glm::mat4 proj);
void startWorldPass(uint32_t idx, const Subpass&);
void recordModel(uint32_t idx);
void startEntityPass(uint32_t idx);
//void recordModel(uint32_t idx);
void recordPostprocess(uint32_t idx);
void recordPostprocess(uint32_t idx, const Subpass&, bool skybox, glm::mat4 view, glm::mat4 proj);
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
void allocate(const std::vector<VkImageView>&, const Pipeline&, VkExtent2D);
@ -42,18 +43,19 @@ private:
VkCommandPool graphicsPool;
std::vector<VkCommandBuffer> graphicsBuffers;
VkDescriptorPool descriptorPool;
std::vector<VkDescriptorSet> descriptorSets;
BufferGroup uniformBuffers;
VkDescriptorPool voxelDescriptorPool;
std::vector<VkDescriptorSet> voxelDescriptorSets;
std::unique_ptr<Texture> sampleTexture;
std::unique_ptr<ShortIndexedVertexBuffer> modelBuffer;
std::unique_ptr<Texture> sampleTexture;
VkDescriptorPool skyDescriptorPool;
std::vector<VkDescriptorSet> skyDescriptorSets;
std::unique_ptr<TextureCube> skyboxTexture;
std::unique_ptr<Shape> skyCubeBuffer;
glm::mat4 proj;
BufferGroup uniformBuffers;
bool freed = true;
};

View File

@ -4,6 +4,7 @@
#include "../../../core/data/file.hpp"
#include "../Renderer.hpp"
#include "buffer/VertexData.hpp"
#include "api/Models.hpp"
#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"
@ -58,24 +59,41 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
colorAttachmentResolveRef.attachment = 2;
colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
//TODO: subpasses (world, entities, colors, sky, ui)
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
VkSubpassDescription colorDepthSubpass{};
colorDepthSubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
colorDepthSubpass.colorAttachmentCount = 1;
colorDepthSubpass.pColorAttachments = &colorAttachmentRef;
colorDepthSubpass.pDepthStencilAttachment = &depthAttachmentRef;
if (hasSamples) {
subpass.pResolveAttachments = &colorAttachmentResolveRef;
colorDepthSubpass.pResolveAttachments = &colorAttachmentResolveRef;
}
std::array<VkSubpassDescription, 2> subpasses = {colorDepthSubpass, colorDepthSubpass};
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
std::array<VkSubpassDependency, 3> dependencies{};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = 0;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = 0;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = 1;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[2].srcSubpass = 0;
dependencies[2].dstSubpass = 1;
dependencies[2].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[2].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[2].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[2].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
//FIXME: probably needs depth dependency and/or 1->external
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
@ -85,16 +103,16 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
}
renderPassInfo.attachmentCount = attachments.size();
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
renderPassInfo.subpassCount = subpasses.size();
renderPassInfo.pSubpasses = subpasses.data();
renderPassInfo.dependencyCount = dependencies.size();
renderPassInfo.pDependencies = dependencies.data();
if (vkCreateRenderPass(device, &renderPassInfo, ALLOC, &renderPass) != VK_SUCCESS) {
FATAL("Failed to create render pass!");
}
}
{
{ // Voxel descriptor
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
@ -108,61 +126,172 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &descriptorSetLayout) != VK_SUCCESS) {
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &voxelDescriptorSet) != VK_SUCCESS) {
FATAL("Failed to create descriptor set layout!");
}
}
{
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
pipelineLayoutInfo.pushConstantRangeCount = 0;
pipelineLayoutInfo.pPushConstantRanges = nullptr;
{ // Sky descriptor
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, ALLOC, &pipelineLayout) != VK_SUCCESS) {
FATAL("Failed to create pipeline layout!");
std::vector<VkDescriptorSetLayoutBinding> bindings = {buffer::vk::UniformBufferObject::getLayoutBinding(), samplerLayoutBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &skyDescriptorSet) != VK_SUCCESS) {
FATAL("Failed to create descriptor set layout!");
}
}
{ // Pipeline
{ // Modules
data::file_content vsFile({SHADER_DIR "Tris.vs.spv"});
data::file_content fsFile({SHADER_DIR "Tris.fs.spv"});
auto createShaderModule = [&](const data::file_content &code) {
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());
VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, ALLOC, &shaderModule) != VK_SUCCESS) {
FATAL("Failed to create shader module!");
}
return shaderModule;
};
vsShader = createShaderModule(vsFile);
fsShader = createShaderModule(fsFile);
}
// Common pipeline settings
auto setShaders = [&](Subpass &pass, const std::string &shaderName) -> std::vector<VkPipelineShaderStageCreateInfo> {
auto createShaderModule = [&](const data::file_content &code) {
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());
VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, ALLOC, &shaderModule) != VK_SUCCESS) {
FATAL("Failed to create shader module!");
}
return shaderModule;
};
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vsShader;
data::file_content vsFile({SHADER_DIR + shaderName + ".vs.spv"});
vertShaderStageInfo.module = pass.vsShader = createShaderModule(vsFile);
vertShaderStageInfo.pName = "main";
vertShaderStageInfo.pSpecializationInfo = nullptr; //TODO: pass constants
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fsShader;
data::file_content fsFile({SHADER_DIR + shaderName + ".fs.spv"});
fragShaderStageInfo.module = pass.fsShader = createShaderModule(fsFile);
fragShaderStageInfo.pName = "main";
fragShaderStageInfo.pSpecializationInfo = nullptr; //TODO: pass constants
//TODO: geometry
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
return {vertShaderStageInfo, fragShaderStageInfo};
};
auto setLayout = [&](Subpass& pass, const std::vector<VkDescriptorSetLayout>& layout, const std::vector<VkPushConstantRange>& push = {}) {
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = layout.size();
pipelineLayoutInfo.pSetLayouts = layout.data();
pipelineLayoutInfo.pushConstantRangeCount = push.size();
pipelineLayoutInfo.pPushConstantRanges = push.data();
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, ALLOC, &pass.layout) != VK_SUCCESS) {
FATAL("Failed to create pipeline layout!");
}
};
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
depthStencil.depthBoundsTestEnable = VK_FALSE; // Restrict sub depth area
depthStencil.minDepthBounds = 0.0f;
depthStencil.maxDepthBounds = 1.0f;
depthStencil.stencilTestEnable = VK_FALSE;
// Stencil options front/back
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
if constexpr (BLENDING) {
colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
} else {
colorBlendAttachment.blendEnable = VK_FALSE;
}
VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1; //NOTE: For multitarget
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
VkPipelineInputAssemblyStateCreateInfo trisInputAssembly{};
trisInputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
trisInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
trisInputAssembly.primitiveRestartEnable = VK_FALSE;
// Viewport
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)info.swapDetails.capabilities.currentExtent.width;
viewport.height = (float)info.swapDetails.capabilities.currentExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = info.swapDetails.capabilities.currentExtent;
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f;
rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 0.0f;
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = info.samples;
//MAYBE: add option
multisampling.sampleShadingEnable = info.features.sampleRateShading && hasSamples;
multisampling.minSampleShading = .2f;
multisampling.pSampleMask = nullptr;
multisampling.alphaToCoverageEnable = VK_FALSE;
multisampling.alphaToOneEnable = VK_FALSE;
{ // World pipeline
/*struct Push {
alignas(16) glm::mat4 Model;
alignas(16) glm::vec4 SphereProj;
alignas(4) float Curvature;
};*/
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(buffer::vk::ModelPush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(worldPass, {voxelDescriptorSet}, {pushRange});
auto shaderStages = setShaders(worldPass, "Tris");
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@ -174,108 +303,12 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;
// Viewport
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)info.swapDetails.capabilities.currentExtent.width;
viewport.height = (float)info.swapDetails.capabilities.currentExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = info.swapDetails.capabilities.currentExtent;
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f;
rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 0.0f;
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = info.samples;
//MAYBE: add option
multisampling.sampleShadingEnable = info.features.sampleRateShading && hasSamples;
multisampling.minSampleShading = .2f;
multisampling.pSampleMask = nullptr;
multisampling.alphaToCoverageEnable = VK_FALSE;
multisampling.alphaToOneEnable = VK_FALSE;
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; //FIXME: LEQUAL for skybox
depthStencil.depthBoundsTestEnable = VK_FALSE; // Restrict sub depth area
depthStencil.minDepthBounds = 0.0f;
depthStencil.maxDepthBounds = 1.0f;
depthStencil.stencilTestEnable = VK_FALSE;
// Stencil options front/back
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
if constexpr (BLENDING) {
colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
} else {
colorBlendAttachment.blendEnable = VK_FALSE;
}
VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1; //MAYBE: deferred multitarget
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
/* MAYBE: dynamic state
VkDynamicState dynamicStates[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_LINE_WIDTH};
VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = 2;
dynamicState.pDynamicStates = dynamicStates;
*/
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pInputAssemblyState = &trisInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
@ -283,24 +316,73 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.layout = worldPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &graphicsPipeline) != VK_SUCCESS) {
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &worldPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
{ // Sky pipeline
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(buffer::vk::SkyPush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(skyPass, {skyDescriptorSet}, {pushRange});
auto shaderStages = setShaders(skyPass, "Sky");
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Shape::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescription = Shape::getAttributeDescription();
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription;
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &trisInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = skyPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 1;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &skyPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
}
Pipeline::~Pipeline() {
vkDestroyPipeline(device, graphicsPipeline, ALLOC);
vkDestroyPipelineLayout(device, pipelineLayout, ALLOC);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, ALLOC);
vkDestroyRenderPass(device, renderPass, ALLOC);
auto destroy = [&](Subpass &pass) {
vkDestroyShaderModule(device, pass.fsShader, ALLOC);
vkDestroyShaderModule(device, pass.vsShader, ALLOC);
vkDestroyPipeline(device, pass.pipeline, ALLOC);
vkDestroyPipelineLayout(device, pass.layout, ALLOC);
};
vkDestroyShaderModule(device, fsShader, ALLOC);
vkDestroyShaderModule(device, vsShader, ALLOC);
destroy(worldPass);
destroy(skyPass);
vkDestroyDescriptorSetLayout(device, voxelDescriptorSet, ALLOC);
vkDestroyDescriptorSetLayout(device, skyDescriptorSet, ALLOC);
vkDestroyRenderPass(device, renderPass, ALLOC);
}

View File

@ -4,26 +4,36 @@
namespace render::vk {
struct Subpass {
VkShaderModule vsShader;
VkShaderModule fsShader;
VkPipelineLayout layout;
VkPipeline pipeline;
};
class Pipeline final {
public:
Pipeline(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
~Pipeline();
// Universe renderpass
constexpr VkRenderPass getRenderPass() const { return renderPass; }
constexpr VkPipeline getPipeline() const { return graphicsPipeline; }
constexpr VkPipelineLayout getLayout() const { return pipelineLayout; }
constexpr VkDescriptorSetLayout getDescriptorSet() const { return descriptorSetLayout; }
// Voxels (world & entity) passes descriptor set
constexpr VkDescriptorSetLayout getVoxelDescriptorSet() const { return voxelDescriptorSet; }
constexpr const Subpass& getWorldPass() const { return worldPass; }
constexpr VkDescriptorSetLayout getSkyDescriptorSet() const { return skyDescriptorSet; }
constexpr const Subpass& getSkyPass() const { return skyPass; }
private:
VkDevice device;
VkShaderModule vsShader;
VkShaderModule fsShader;
VkRenderPass renderPass;
VkDescriptorSetLayout descriptorSetLayout;
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
};
VkDescriptorSetLayout voxelDescriptorSet;
VkDescriptorSetLayout skyDescriptorSet;
Subpass worldPass;
Subpass skyPass;
};
}

View File

@ -2,6 +2,7 @@
#include "UI.hpp"
#include "../../Window.hpp"
#include "../../control/Camera.hpp"
#include "PhysicalDeviceInfo.hpp"
#include "Allocator.hpp"
#include "SwapChain.hpp"
@ -34,7 +35,7 @@ Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInf
if constexpr(VALIDATION_LAYER) {
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = debugValidationCallback;
createInfo.pUserData = nullptr;
@ -409,7 +410,8 @@ void Renderer::beginFrame() {
if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) {
currentImage = newImage.value();
commandCenter->startRecording(currentImage);
commandCenter->startRecording(currentImage, pipeline->getRenderPass(),
getInfos().swapDetails.capabilities.currentExtent, options.clear_color, ViewMatrix, ProjectionMatrix);
allocator->setTracyZone("Submit");
} else {
recreateSwapChain();
@ -420,8 +422,7 @@ void Renderer::beginFrame() {
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> Renderer::beginWorldPass() {
assert(currentImage < swapChain->getImageViews().size());
commandCenter->startWorldPass(currentImage, *pipeline.get(),
getInfos().swapDetails.capabilities.currentExtent, options.clear_color);
commandCenter->startWorldPass(currentImage, pipeline->getWorldPass());
commandCenter->recordModel(currentImage);
return [&](render::LodModel *const, glm::mat4, glm::vec4, float) {
return 0; //WorldPass->setup(this, model);
@ -445,7 +446,7 @@ size_t Renderer::drawIndicatorCube(glm::mat4) {
}
void Renderer::postProcess() {
commandCenter->recordPostprocess(currentImage/*, options.skybox*/);
commandCenter->recordPostprocess(currentImage, pipeline->getSkyPass(), options.skybox, ViewMatrix, ProjectionMatrix);
}
void Renderer::endFrame() {
@ -475,10 +476,11 @@ void Renderer::reloadTextures(const std::string&, float, float) {
loadTextures(texturePath, mipMapLOD, anisotropy);*/
}
void Renderer::lookFrom(const Camera&) {
/*ProjectionMatrix = camera.getProjectionMatrix();
void Renderer::lookFrom(const Camera& camera) {
ProjectionMatrix = camera.getProjectionMatrix();
ProjectionMatrix[1][1] *= -1;
ViewMatrix = camera.getViewMatrix();
FogDepth = camera.getDepth();*/
FogDepth = camera.getDepth();
}
void Renderer::setClearColor(glm::vec4 c) {

View File

@ -65,5 +65,9 @@ private:
bool framebufferResized = false;
void recreateSwapChain();
void destroySwapChain();
glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix;
float FogDepth;
};
}

View File

@ -2,6 +2,7 @@
#include "Buffers.hpp"
#include "../Allocator.hpp"
#include "../../../../core/utils/logger.hpp"
#include <algorithm>
using namespace render::vk;
@ -19,10 +20,10 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
VkImageCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = req.depth > 1 ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
info.imageType = VK_IMAGE_TYPE_2D;
info.extent.width = req.size.width;
info.extent.height = req.size.height;
info.extent.depth = req.depth;
info.extent.depth = 1;
info.mipLevels = req.mipmapLevels;
info.arrayLayers = req.layers;
info.format = static_cast<VkFormat>(req.format);
@ -32,6 +33,12 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.samples = static_cast<VkSampleCountFlagBits>(req.samples);
info.flags = 0;
if (req.cube) {
info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
} else if (req.layers > 1) {
info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
}
if (!datas.empty()) {
info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
@ -52,6 +59,7 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
}
if (!datas.empty()) {
assert(datas.size() <= req.layers);
const auto maxSize = [&] {
size_t max = 0;
for (auto& data: datas)
@ -61,15 +69,12 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
if(auto staging = WritableBuffer::Create(maxSize)) {
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, req.mipmapLevels, req.layers);
info.initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
size_t i = 0;
for (size_t layer = 0; layer < req.layers && i < datas.size(); layer++) {
for (size_t depth = 0; depth < req.depth && i < datas.size(); depth++) {
if(datas[i].isUsable()) {
staging->write(datas[i], 0);
alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels, depth, layer);
for (size_t layer = 0; layer < req.layers && layer < datas.size(); layer++) {
if(datas[layer].isUsable()) {
staging->write(datas[layer], 0);
alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height, req.mipmapLevels, layer);
}
i++;
}}
}
} else {
LOG_E("Cannot allocate staging memory");
return memory::GetNull();
@ -80,8 +85,13 @@ memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags pro
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = out.ref;
viewInfo.viewType = req.layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY :
(req.depth == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D);
if (req.cube) {
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
} else if (req.layers > 1) {
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
} else {
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
}
viewInfo.format = static_cast<VkFormat>(req.format);
viewInfo.subresourceRange.aspectMask = static_cast<VkImageAspectFlags>(req.aspect);
viewInfo.subresourceRange.baseMipLevel = 0;
@ -187,7 +197,7 @@ std::unique_ptr<TextureCube> TextureCube::LoadFromFiles(const std::array<std::st
}
vk::Image::info img;
auto mem = createImage(requirement::Texture(header, true),
auto mem = createImage(requirement::Texture(header, paths.size(), true),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, views, img);
if(!mem) {
FATAL("Cannot create texture cube image");
@ -195,6 +205,20 @@ std::unique_ptr<TextureCube> TextureCube::LoadFromFiles(const std::array<std::st
return std::unique_ptr<TextureCube>(new TextureCube(createSampler(props, header.mipmapLevels), img.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem)));
}
std::unique_ptr<TextureCube> TextureCube::LoadFromFiles(const std::string& prefix, const sampling& props) {
const std::array<std::string, 6> faces {
"right",
"left",
"top",
"bottom",
"front",
"back"
};
std::array<std::string, 6> paths;
std::transform(faces.begin(), faces.end(), paths.begin(),
[prefix](const std::string &face) -> std::string { return prefix + "." + face + ".dds"; });
return LoadFromFiles(paths, props);
}
std::unique_ptr<TextureArray> TextureArray::LoadFromFiles(const std::vector<std::string>& paths, const sampling& props) {
std::vector<std::vector<unsigned char>> datas;
@ -217,7 +241,7 @@ std::unique_ptr<TextureArray> TextureArray::LoadFromFiles(const std::vector<std:
}
vk::Image::info img;
auto mem = createImage(requirement::Texture(header, false, paths.size()),
auto mem = createImage(requirement::Texture(header, paths.size()),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, views, img);
if(!mem) {
FATAL("Cannot create texture cube image");

View File

@ -44,16 +44,18 @@ protected:
const VkDescriptorImageInfo descriptor;
};
class TextureCube: public render::TextureCube, Texture {
class TextureCube: public render::TextureCube, public Texture {
public:
static std::unique_ptr<TextureCube> LoadFromFiles(const std::array<std::string, 6>&, const sampling&);
/// Looks for .right.dds, .left.dds, .top.dds, .bottom.dds, .front.dds, .back.dds
static std::unique_ptr<TextureCube> LoadFromFiles(const std::string& prefix, const sampling&);
static std::unique_ptr<TextureCube> LoadFromFiles(const std::array<std::string, 6>& paths, const sampling&);
protected:
TextureCube(VkSampler sampler, VkImageView view, VkImageLayout layout, VkImage ref, memory::ptr memory):
Texture(sampler, view, layout, ref, std::move(memory)) { }
};
class TextureArray: public render::TextureArray, Texture {
class TextureArray: public render::TextureArray, public Texture {
public:
static std::unique_ptr<TextureArray> LoadFromFiles(const std::vector<std::string>&, const sampling&);

View File

@ -6,12 +6,28 @@
namespace render::vk {
/// Positions only buffer
class Shape final: Buffer {
class Shape final: public Buffer {
public:
const size_t size;
static std::unique_ptr<Shape> Create(const std::vector<glm::vec3>&);
static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription description{};
description.binding = 0;
description.stride = sizeof(glm::vec3);
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return description;
}
static VkVertexInputAttributeDescription getAttributeDescription() {
VkVertexInputAttributeDescription attributeDescription{};
attributeDescription.binding = 0;
attributeDescription.location = 0;
attributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescription.offset = 0;
return attributeDescription;
}
protected:
Shape(VkBuffer ref, memory::ptr mem, size_t size):
Buffer(ref, std::move(mem)), size(size) { }

View File

@ -54,7 +54,6 @@ const std::vector<uint16_t> indices = {
};
struct UniformBufferObject {
alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
@ -69,4 +68,13 @@ struct UniformBufferObject {
}
};
struct ModelPush {
alignas(16) glm::mat4 model;
};
struct SkyPush {
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
};
}