Still works at least
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
*.db filter=lfs diff=lfs merge=lfs -text
|
||||||
@@ -5,9 +5,11 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
|
|
||||||
add_subdirectory(external/glfw)
|
add_subdirectory(external/glfw)
|
||||||
add_subdirectory(external/glm)
|
add_subdirectory(external/glm)
|
||||||
|
add_subdirectory(external/tinygltf)
|
||||||
|
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
|
|
||||||
add_executable(acg_in_gd_lab src/main.cpp)
|
add_executable(acg_in_gd_lab src/main.cpp)
|
||||||
target_link_libraries(acg_in_gd_lab PRIVATE glfw glm::glm ${Vulkan_LIBRARIES})
|
target_link_libraries(acg_in_gd_lab PRIVATE glfw glm::glm ${Vulkan_LIBRARIES})
|
||||||
|
target_link_libraries(acg_in_gd_lab PRIVATE tinygltf)
|
||||||
target_include_directories(acg_in_gd_lab PRIVATE ${Vulkan_INCLUDE_DIR})
|
target_include_directories(acg_in_gd_lab PRIVATE ${Vulkan_INCLUDE_DIR})
|
||||||
+2
-1
@@ -3,4 +3,5 @@
|
|||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
glslc shaders/shader.vert -o shaders/vert.spv
|
glslc shaders/shader.vert -o shaders/vert.spv
|
||||||
glslc shaders/shader.frag -o shaders/frag.spv
|
glslc shaders/shader.frag -o shaders/frag.spv
|
||||||
|
glslangValidator -V FilmicAnamorphSharpen.fx -o FilmicAnamorphSharpen.spv
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
/*------------------.
|
||||||
|
| :: Description :: |
|
||||||
|
'-------------------/
|
||||||
|
|
||||||
|
Filmic Anamorph Sharpen PS (version 1.5.0)
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
This code © 2018-2023 Jakub Maximilian Fober
|
||||||
|
Some changes by ccritchfield https://github.com/ccritchfield
|
||||||
|
|
||||||
|
License:
|
||||||
|
This work is licensed under the Creative Commons
|
||||||
|
Attribution-ShareAlike 4.0 International License.
|
||||||
|
To view a copy of this license, visit
|
||||||
|
http://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*--------------.
|
||||||
|
| :: Commons :: |
|
||||||
|
'--------------*/
|
||||||
|
|
||||||
|
#include "ReShade.fxh"
|
||||||
|
#include "ReShadeUI.fxh"
|
||||||
|
#include "ColorConversion.fxh"
|
||||||
|
#include "LinearGammaWorkflow.fxh"
|
||||||
|
|
||||||
|
/*-----------.
|
||||||
|
| :: Menu :: |
|
||||||
|
'-----------*/
|
||||||
|
|
||||||
|
uniform float Strength
|
||||||
|
< __UNIFORM_SLIDER_FLOAT1
|
||||||
|
ui_label = "Strength";
|
||||||
|
ui_min = 0.0; ui_max = 100.0; ui_step = 0.01;
|
||||||
|
> = 60.0;
|
||||||
|
|
||||||
|
uniform float Offset
|
||||||
|
< __UNIFORM_SLIDER_FLOAT1
|
||||||
|
ui_units = " pixel";
|
||||||
|
ui_label = "Radius";
|
||||||
|
ui_tooltip = "High-pass cross offset in pixels";
|
||||||
|
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
||||||
|
> = 0.1;
|
||||||
|
|
||||||
|
uniform float Clamp
|
||||||
|
< __UNIFORM_SLIDER_FLOAT1
|
||||||
|
ui_label = "Clamping";
|
||||||
|
ui_min = 0.5; ui_max = 1.0; ui_step = 0.001;
|
||||||
|
> = 0.65;
|
||||||
|
|
||||||
|
uniform bool UseMask
|
||||||
|
< __UNIFORM_INPUT_BOOL1
|
||||||
|
ui_label = "Sharpen only center";
|
||||||
|
ui_tooltip = "Sharpen only in center of the image";
|
||||||
|
> = false;
|
||||||
|
|
||||||
|
uniform bool DepthMask
|
||||||
|
< __UNIFORM_INPUT_BOOL1
|
||||||
|
ui_label = "Enable depth rim masking";
|
||||||
|
ui_tooltip = "Depth high-pass mask switch";
|
||||||
|
ui_category = "Depth mask";
|
||||||
|
ui_category_closed = true;
|
||||||
|
> = false;
|
||||||
|
|
||||||
|
uniform int DepthMaskContrast
|
||||||
|
< __UNIFORM_DRAG_INT1
|
||||||
|
ui_label = "Edges mask strength";
|
||||||
|
ui_tooltip = "Depth high-pass mask amount";
|
||||||
|
ui_category = "Depth mask";
|
||||||
|
ui_min = 0; ui_max = 2000; ui_step = 1;
|
||||||
|
> = 128;
|
||||||
|
|
||||||
|
uniform bool Preview
|
||||||
|
< __UNIFORM_INPUT_BOOL1
|
||||||
|
ui_label = "Preview sharpen layer";
|
||||||
|
ui_tooltip = "Preview sharpen layer and mask for adjustment.\n"
|
||||||
|
"If you don't see red strokes,\n"
|
||||||
|
"try changing Preprocessor Definitions in the Settings tab.";
|
||||||
|
ui_category = "Debug View";
|
||||||
|
ui_category_closed = true;
|
||||||
|
> = false;
|
||||||
|
|
||||||
|
/*---------------.
|
||||||
|
| :: Textures :: |
|
||||||
|
'---------------*/
|
||||||
|
|
||||||
|
// Define screen texture with mirror tiles
|
||||||
|
sampler BackBuffer
|
||||||
|
{
|
||||||
|
Texture = ReShade::BackBufferTex;
|
||||||
|
AddressU = MIRROR;
|
||||||
|
AddressV = MIRROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------.
|
||||||
|
| :: Functions :: |
|
||||||
|
'----------------*/
|
||||||
|
|
||||||
|
// Overlay blending mode
|
||||||
|
float Overlay(float LayerA, float LayerB)
|
||||||
|
{
|
||||||
|
float MinA = min(LayerA, 0.5);
|
||||||
|
float MinB = min(LayerB, 0.5);
|
||||||
|
float MaxA = max(LayerA, 0.5);
|
||||||
|
float MaxB = max(LayerB, 0.5);
|
||||||
|
return 2f*(MinA*MinB+MaxA+MaxB-MaxA*MaxB)-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overlay blending mode for one input
|
||||||
|
float Overlay(float LayerAB)
|
||||||
|
{
|
||||||
|
float MinAB = min(LayerAB, 0.5);
|
||||||
|
float MaxAB = max(LayerAB, 0.5);
|
||||||
|
return 2f*(MinAB*MinAB+MaxAB+MaxAB-MaxAB*MaxAB)-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------.
|
||||||
|
| :: Shaders :: |
|
||||||
|
'--------------*/
|
||||||
|
|
||||||
|
// Sharpen pass
|
||||||
|
float3 FilmicAnamorphSharpenPS(
|
||||||
|
float4 pos : SV_Position,
|
||||||
|
float2 UvCoord : TEXCOORD
|
||||||
|
) : SV_Target
|
||||||
|
{
|
||||||
|
// Sample display image
|
||||||
|
float3 Source = GammaConvert::to_linear(tex2D(BackBuffer, UvCoord).rgb);
|
||||||
|
|
||||||
|
// Generate radial mask
|
||||||
|
float Mask;
|
||||||
|
if (UseMask)
|
||||||
|
{
|
||||||
|
// Generate radial mask
|
||||||
|
Mask = 1f-length(UvCoord*2f-1f);
|
||||||
|
Mask = Overlay(Mask) * Strength;
|
||||||
|
// Bypass
|
||||||
|
if (Mask<=0) return GammaConvert::to_display(Source);
|
||||||
|
}
|
||||||
|
else Mask = Strength;
|
||||||
|
|
||||||
|
// Get pixel size
|
||||||
|
float2 Pixel = BUFFER_PIXEL_SIZE;
|
||||||
|
|
||||||
|
if (DepthMask)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// original
|
||||||
|
float2 DepthPixel = Pixel*Offset+Pixel;
|
||||||
|
Pixel *= Offset;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// !!! calc pixel*offset once, use twice
|
||||||
|
float2 PixelOffset = Pixel * Offset;
|
||||||
|
float2 DepthPixel = PixelOffset + Pixel;
|
||||||
|
Pixel = PixelOffset;
|
||||||
|
|
||||||
|
// Sample display depth image
|
||||||
|
float SourceDepth = ReShade::GetLinearizedDepth(UvCoord);
|
||||||
|
|
||||||
|
float2 NorSouWesEst[4] = {
|
||||||
|
float2(UvCoord.x, UvCoord.y + Pixel.y),
|
||||||
|
float2(UvCoord.x, UvCoord.y - Pixel.y),
|
||||||
|
float2(UvCoord.x + Pixel.x, UvCoord.y),
|
||||||
|
float2(UvCoord.x - Pixel.x, UvCoord.y)
|
||||||
|
};
|
||||||
|
|
||||||
|
float2 DepthNorSouWesEst[4] = {
|
||||||
|
float2(UvCoord.x, UvCoord.y + DepthPixel.y),
|
||||||
|
float2(UvCoord.x, UvCoord.y - DepthPixel.y),
|
||||||
|
float2(UvCoord.x + DepthPixel.x, UvCoord.y),
|
||||||
|
float2(UvCoord.x - DepthPixel.x, UvCoord.y)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Luma high-pass color
|
||||||
|
// Luma high-pass depth
|
||||||
|
float HighPassColor = 0f, DepthMask = 0f;
|
||||||
|
|
||||||
|
[unroll]for(int s=0; s<4; s++)
|
||||||
|
{
|
||||||
|
HighPassColor +=
|
||||||
|
ColorConvert::RGB_to_Luma(
|
||||||
|
GammaConvert::to_linear(
|
||||||
|
tex2D(BackBuffer, NorSouWesEst[s]).rgb
|
||||||
|
));
|
||||||
|
DepthMask +=
|
||||||
|
ReShade::GetLinearizedDepth(NorSouWesEst[s])
|
||||||
|
+ReShade::GetLinearizedDepth(DepthNorSouWesEst[s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
HighPassColor = 0.5-0.5*(HighPassColor*0.25-ColorConvert::RGB_to_Luma(Source));
|
||||||
|
|
||||||
|
DepthMask = 1f-DepthMask*0.125+SourceDepth;
|
||||||
|
DepthMask = min(1f, DepthMask)+1f-max(1f, DepthMask);
|
||||||
|
DepthMask = saturate(DepthMaskContrast*DepthMask+1f-DepthMaskContrast);
|
||||||
|
|
||||||
|
// Sharpen strength
|
||||||
|
HighPassColor = lerp(0.5, HighPassColor, Mask*DepthMask);
|
||||||
|
|
||||||
|
// Clamping sharpen
|
||||||
|
/*
|
||||||
|
// original
|
||||||
|
HighPassColor = Clamp!=1f ? max(min(HighPassColor, Clamp), 1f-Clamp) : HighPassColor;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// !!! Clamp in settings above is restricted to 0.5 to 1.0
|
||||||
|
// !!! 1.0 - Clamp is the low value, while Clamp is the high value
|
||||||
|
// !!! so we can literally just use the clamp() func instead of min/max.
|
||||||
|
// !!! not sure if author was trying to take advantage of some kind of
|
||||||
|
// !!! compiler "cheat" using min/max instead of clamp to improve
|
||||||
|
// !!! performance. doesn't make sense to min/max otherwise.
|
||||||
|
HighPassColor = Clamp!=1f ? clamp(HighPassColor, 1f-Clamp, Clamp ) : HighPassColor;
|
||||||
|
|
||||||
|
float3 Sharpen = float3(
|
||||||
|
Overlay(Source.r, HighPassColor),
|
||||||
|
Overlay(Source.g, HighPassColor),
|
||||||
|
Overlay(Source.b, HighPassColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(Preview) // Preview mode ON
|
||||||
|
{
|
||||||
|
float PreviewChannel = lerp(HighPassColor, HighPassColor*DepthMask, 0.5);
|
||||||
|
return
|
||||||
|
GammaConvert::to_display(float3(
|
||||||
|
1f-DepthMask * (1f-HighPassColor),
|
||||||
|
PreviewChannel,
|
||||||
|
PreviewChannel
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GammaConvert::to_display(Sharpen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Pixel *= Offset;
|
||||||
|
|
||||||
|
float2 NorSouWesEst[4] = {
|
||||||
|
float2(UvCoord.x, UvCoord.y + Pixel.y),
|
||||||
|
float2(UvCoord.x, UvCoord.y - Pixel.y),
|
||||||
|
float2(UvCoord.x + Pixel.x, UvCoord.y),
|
||||||
|
float2(UvCoord.x - Pixel.x, UvCoord.y)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Luma high-pass color
|
||||||
|
float HighPassColor = 0f;
|
||||||
|
[unroll] for(uint s=0u; s<4u; s++)
|
||||||
|
HighPassColor +=
|
||||||
|
ColorConvert::RGB_to_Luma(
|
||||||
|
GammaConvert::to_linear(
|
||||||
|
tex2D(BackBuffer, NorSouWesEst[s]).rgb
|
||||||
|
));
|
||||||
|
|
||||||
|
// !!! added space above to make it more obvious
|
||||||
|
// !!! that loop is now a one-liner in this else branch
|
||||||
|
// !!! where-as loop in branch above was multi-part
|
||||||
|
HighPassColor = 0.5-0.5*(HighPassColor*0.25-ColorConvert::RGB_to_Luma(Source));
|
||||||
|
|
||||||
|
// Sharpen strength
|
||||||
|
HighPassColor = lerp(0.5, HighPassColor, Mask);
|
||||||
|
|
||||||
|
// Clamping sharpen
|
||||||
|
/*
|
||||||
|
// original
|
||||||
|
HighPassColor = Clamp!=1f ? max(min(HighPassColor, Clamp), 1f-Clamp) : HighPassColor;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// !!! Clamp in settings above is restricted to 0.5 to 1.0
|
||||||
|
// !!! 1.0 - Clamp is the low value, while Clamp is the high value
|
||||||
|
// !!! so we can literally just use the clamp() func instead of min/max.
|
||||||
|
// !!! not sure if author was trying to take advantage of some kind of
|
||||||
|
// !!! compiler "cheat" using min/max instead of clamp to improve
|
||||||
|
// !!! performance. doesn't make sense to min/max otherwise.
|
||||||
|
HighPassColor = Clamp!=1f ? clamp(HighPassColor, 1f-Clamp, Clamp) : HighPassColor;
|
||||||
|
|
||||||
|
float3 Sharpen = float3(
|
||||||
|
Overlay(Source.r, HighPassColor),
|
||||||
|
Overlay(Source.g, HighPassColor),
|
||||||
|
Overlay(Source.b, HighPassColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
return GammaConvert::to_display(
|
||||||
|
Preview // preview mode ON
|
||||||
|
? HighPassColor
|
||||||
|
: Sharpen
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------.
|
||||||
|
| :: Output :: |
|
||||||
|
'-------------*/
|
||||||
|
|
||||||
|
technique FilmicAnamorphSharpen
|
||||||
|
<
|
||||||
|
ui_label = "Filmic Anamorphic Sharpen";
|
||||||
|
ui_tooltip =
|
||||||
|
"This effect © 2018-2023 Jakub Maksymilian Fober\n"
|
||||||
|
"Licensed under CC BY-SA 4.0";
|
||||||
|
>
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
VertexShader = PostProcessVS;
|
||||||
|
PixelShader = FilmicAnamorphSharpenPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
-57
@@ -1,4 +1,7 @@
|
|||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
@@ -11,23 +14,52 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
|
using namespace tinygltf;
|
||||||
|
bool load_gltf() {
|
||||||
|
Model model;
|
||||||
|
TinyGLTF loader;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, "models/Models/BrainStem/glTF/BrainStem.gltf"); // YOUR GLTF HERE
|
||||||
|
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||||
|
|
||||||
|
if (!warn.empty()) {
|
||||||
|
printf("Warn: %s\n", warn.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
printf("Err: %s\n", err.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
printf("Failed to parse glTF\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
}
|
||||||
const VkAllocationCallbacks *pAllocator,
|
|
||||||
VkDebugUtilsMessengerEXT *pDebugMessenger) {
|
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pDebugMessenger) {
|
||||||
|
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger,
|
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger,
|
||||||
const VkAllocationCallbacks *pAllocator) {
|
const VkAllocationCallbacks* pAllocator) {
|
||||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
|
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance,
|
||||||
"vkDestroyDebugUtilsMessengerEXT");
|
"vkDestroyDebugUtilsMessengerEXT");
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
func(instance, debugMessenger, pAllocator);
|
func(instance, debugMessenger, pAllocator);
|
||||||
}
|
}
|
||||||
@@ -54,13 +86,13 @@ struct SwapChainSupportDetails {
|
|||||||
VkSurfaceFormatKHR chooseSwapSurfaceFormat() {
|
VkSurfaceFormatKHR chooseSwapSurfaceFormat() {
|
||||||
for (const auto& format : formats) {
|
for (const auto& format : formats) {
|
||||||
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
||||||
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!formats.empty())
|
if (!formats.empty())
|
||||||
return formats[0];
|
return formats[0];
|
||||||
return {VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_MAX_ENUM_KHR};
|
return { VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_MAX_ENUM_KHR };
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPresentModeKHR chooseSwapPresentMode() {
|
VkPresentModeKHR chooseSwapPresentMode() {
|
||||||
@@ -73,23 +105,23 @@ struct SwapChainSupportDetails {
|
|||||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkExtent2D chooseSwapExtent(GLFWwindow *window) {
|
VkExtent2D chooseSwapExtent(GLFWwindow* window) {
|
||||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
||||||
return capabilities.currentExtent;
|
return capabilities.currentExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
VkExtent2D actualExtent {
|
VkExtent2D actualExtent{
|
||||||
static_cast<uint32_t>(width),
|
static_cast<uint32_t>(width),
|
||||||
static_cast<uint32_t>(height)
|
static_cast<uint32_t>(height)
|
||||||
};
|
};
|
||||||
actualExtent.width = std::clamp(actualExtent.width,
|
actualExtent.width = std::clamp(actualExtent.width,
|
||||||
capabilities.minImageExtent.width,
|
capabilities.minImageExtent.width,
|
||||||
capabilities.maxImageExtent.width);
|
capabilities.maxImageExtent.width);
|
||||||
actualExtent.height = std::clamp(actualExtent.height,
|
actualExtent.height = std::clamp(actualExtent.height,
|
||||||
capabilities.minImageExtent.height,
|
capabilities.minImageExtent.height,
|
||||||
capabilities.maxImageExtent.height);
|
capabilities.maxImageExtent.height);
|
||||||
return actualExtent;
|
return actualExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +135,7 @@ struct SwapChainSupportDetails {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<char> readFile(const std::filesystem::path & filepath) {
|
static std::vector<char> readFile(const std::filesystem::path& filepath) {
|
||||||
std::ifstream file(filepath, std::ios::ate | std::ios::binary);
|
std::ifstream file(filepath, std::ios::ate | std::ios::binary);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
throw std::runtime_error(std::string("failed to open a file: ") + filepath.string());
|
throw std::runtime_error(std::string("failed to open a file: ") + filepath.string());
|
||||||
@@ -124,11 +156,11 @@ private:
|
|||||||
const int HEIGHT = 600;
|
const int HEIGHT = 600;
|
||||||
const std::string appName = "Vulkan on MacOS";
|
const std::string appName = "Vulkan on MacOS";
|
||||||
const std::string engineName = "The Best Engine";
|
const std::string engineName = "The Best Engine";
|
||||||
const std::vector<const char *> deviceExtensions = {
|
const std::vector<const char*> deviceExtensions = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
"VK_KHR_portability_subset",
|
"VK_KHR_portability_subset",
|
||||||
};
|
};
|
||||||
const std::vector<const char *> validationLayers = {
|
const std::vector<const char*> validationLayers = {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,7 +170,7 @@ private:
|
|||||||
const bool enableValidationLayers = true;
|
const bool enableValidationLayers = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLFWwindow *window = nullptr;
|
GLFWwindow* window = nullptr;
|
||||||
|
|
||||||
VkInstance instance = VK_NULL_HANDLE;
|
VkInstance instance = VK_NULL_HANDLE;
|
||||||
VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE;
|
VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE;
|
||||||
@@ -166,6 +198,7 @@ public:
|
|||||||
void run() {
|
void run() {
|
||||||
initWindow();
|
initWindow();
|
||||||
initVulkan();
|
initVulkan();
|
||||||
|
|
||||||
mainLoop();
|
mainLoop();
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
@@ -178,9 +211,9 @@ private:
|
|||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
|
|
||||||
window = glfwCreateWindow(
|
window = glfwCreateWindow(
|
||||||
WIDTH, HEIGHT,
|
WIDTH, HEIGHT,
|
||||||
appName.c_str(),
|
appName.c_str(),
|
||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initVulkan() {
|
void initVulkan() {
|
||||||
@@ -205,9 +238,9 @@ private:
|
|||||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||||
|
|
||||||
for (const auto &layerName: validationLayers) {
|
for (const auto& layerName : validationLayers) {
|
||||||
bool layerFound = false;
|
bool layerFound = false;
|
||||||
for (const auto &layerProperties: availableLayers) {
|
for (const auto& layerProperties : availableLayers) {
|
||||||
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
||||||
layerFound = true;
|
layerFound = true;
|
||||||
break;
|
break;
|
||||||
@@ -220,12 +253,12 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char *> getRequiredExtensions() const {
|
std::vector<const char*> getRequiredExtensions() const {
|
||||||
uint32_t glfwExtensionCount = 0;
|
uint32_t glfwExtensionCount = 0;
|
||||||
const char **glfwExtensions;
|
const char** glfwExtensions;
|
||||||
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||||
|
|
||||||
std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
|
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
|
||||||
|
|
||||||
if (enableValidationLayers) {
|
if (enableValidationLayers) {
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
@@ -237,15 +270,15 @@ private:
|
|||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo) {
|
static void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
|
||||||
createInfo = {};
|
createInfo = {};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
createInfo.messageSeverity =
|
createInfo.messageSeverity =
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||||
createInfo.messageType =
|
createInfo.messageType =
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
createInfo.pfnUserCallback = debugCallback;
|
createInfo.pfnUserCallback = debugCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,17 +324,17 @@ private:
|
|||||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||||
std::cout << "available extensions:\n";
|
std::cout << "available extensions:\n";
|
||||||
|
|
||||||
for (const auto &extension: extensions) {
|
for (const auto& extension : extensions) {
|
||||||
std::cout << '\t' << extension.extensionName << '\n';
|
std::cout << '\t' << extension.extensionName << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void *pUserData) {
|
void* pUserData) {
|
||||||
|
|
||||||
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
|
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
|
||||||
|
|
||||||
@@ -377,10 +410,10 @@ private:
|
|||||||
bool checkDeviceExtensionSupport(VkPhysicalDevice dev) {
|
bool checkDeviceExtensionSupport(VkPhysicalDevice dev) {
|
||||||
uint32_t extensionCount;
|
uint32_t extensionCount;
|
||||||
vkEnumerateDeviceExtensionProperties(dev, nullptr,
|
vkEnumerateDeviceExtensionProperties(dev, nullptr,
|
||||||
&extensionCount, nullptr);
|
&extensionCount, nullptr);
|
||||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||||
vkEnumerateDeviceExtensionProperties(dev, nullptr,
|
vkEnumerateDeviceExtensionProperties(dev, nullptr,
|
||||||
&extensionCount, availableExtensions.data());
|
&extensionCount, availableExtensions.data());
|
||||||
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
||||||
|
|
||||||
for (const auto& extension : availableExtensions) {
|
for (const auto& extension : availableExtensions) {
|
||||||
@@ -414,9 +447,9 @@ private:
|
|||||||
}
|
}
|
||||||
std::cout << ", swapchain is not empty: " << swapChainAdequate << "\n";
|
std::cout << ", swapchain is not empty: " << swapChainAdequate << "\n";
|
||||||
return hasQueues && isSupportExtensions && swapChainAdequate;
|
return hasQueues && isSupportExtensions && swapChainAdequate;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &dev: devices) {
|
for (const auto& dev : devices) {
|
||||||
if (isDeviceSuitable(dev)) {
|
if (isDeviceSuitable(dev)) {
|
||||||
physicalDevice = dev;
|
physicalDevice = dev;
|
||||||
break;
|
break;
|
||||||
@@ -438,7 +471,7 @@ private:
|
|||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||||
float queuePriority = 1.0f;
|
float queuePriority = 1.0f;
|
||||||
|
|
||||||
for (uint32_t queueFamily : uniqueQueueFamilies){
|
for (uint32_t queueFamily : uniqueQueueFamilies) {
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||||
@@ -493,7 +526,7 @@ private:
|
|||||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
|
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
|
||||||
uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
|
uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
|
||||||
if (indices.graphicsFamily != indices.presentFamily) {
|
if (indices.graphicsFamily != indices.presentFamily) {
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
createInfo.queueFamilyIndexCount = 2;
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
@@ -585,7 +618,7 @@ private:
|
|||||||
renderPassInfo.dependencyCount = 1;
|
renderPassInfo.dependencyCount = 1;
|
||||||
renderPassInfo.pDependencies = &dependency;
|
renderPassInfo.pDependencies = &dependency;
|
||||||
|
|
||||||
if(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
|
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
|
||||||
throw std::runtime_error("failed to create a render pass");
|
throw std::runtime_error("failed to create a render pass");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +626,7 @@ private:
|
|||||||
void createGraphicsPipeline() {
|
void createGraphicsPipeline() {
|
||||||
auto vertShaderCode = readFile("shaders/vert.spv");
|
auto vertShaderCode = readFile("shaders/vert.spv");
|
||||||
auto fragShaderCode = readFile("shaders/frag.spv");
|
auto fragShaderCode = readFile("shaders/frag.spv");
|
||||||
|
|
||||||
VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
|
VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
|
||||||
VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
|
VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
|
||||||
|
|
||||||
@@ -610,8 +643,8 @@ private:
|
|||||||
fragShaderStageInfo.pName = "main";
|
fragShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
std::vector<VkPipelineShaderStageCreateInfo> shaderStages = {
|
std::vector<VkPipelineShaderStageCreateInfo> shaderStages = {
|
||||||
vertShaderStageInfo,
|
vertShaderStageInfo,
|
||||||
fragShaderStageInfo
|
fragShaderStageInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkPipelineVertexInputStateCreateInfo vertexInputState{};
|
VkPipelineVertexInputStateCreateInfo vertexInputState{};
|
||||||
@@ -777,9 +810,9 @@ private:
|
|||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
renderPassInfo.renderPass = renderPass;
|
renderPassInfo.renderPass = renderPass;
|
||||||
renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
|
renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
|
||||||
renderPassInfo.renderArea.offset = {0, 0};
|
renderPassInfo.renderArea.offset = { 0, 0 };
|
||||||
renderPassInfo.renderArea.extent = swapChainExtent;
|
renderPassInfo.renderArea.extent = swapChainExtent;
|
||||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.4f, 1.0f}}};
|
VkClearValue clearColor = { {{0.0f, 0.0f, 0.4f, 1.0f}} };
|
||||||
renderPassInfo.clearValueCount = 1;
|
renderPassInfo.clearValueCount = 1;
|
||||||
renderPassInfo.pClearValues = &clearColor;
|
renderPassInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
@@ -796,7 +829,7 @@ private:
|
|||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
VkRect2D scissor{};
|
||||||
scissor.offset = {0, 0};
|
scissor.offset = { 0, 0 };
|
||||||
scissor.extent = swapChainExtent;
|
scissor.extent = swapChainExtent;
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
@@ -822,10 +855,10 @@ private:
|
|||||||
VkSubmitInfo submitInfo{};
|
VkSubmitInfo submitInfo{};
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
std::vector<VkSemaphore> waitSemaphores = {imageAvailableSemaphore};
|
std::vector<VkSemaphore> waitSemaphores = { imageAvailableSemaphore };
|
||||||
std::vector<VkPipelineStageFlags> waitStages = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
std::vector<VkPipelineStageFlags> waitStages = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||||
std::vector<VkCommandBuffer> commandBuffers = {commandBuffer};
|
std::vector<VkCommandBuffer> commandBuffers = { commandBuffer };
|
||||||
std::vector<VkSemaphore> signalSemaphores = {renderFinishedSemaphore};
|
std::vector<VkSemaphore> signalSemaphores = { renderFinishedSemaphore };
|
||||||
submitInfo.waitSemaphoreCount = waitSemaphores.size();
|
submitInfo.waitSemaphoreCount = waitSemaphores.size();
|
||||||
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
||||||
submitInfo.pWaitDstStageMask = waitStages.data();
|
submitInfo.pWaitDstStageMask = waitStages.data();
|
||||||
@@ -844,7 +877,7 @@ private:
|
|||||||
presentInfo.waitSemaphoreCount = signalSemaphores.size();
|
presentInfo.waitSemaphoreCount = signalSemaphores.size();
|
||||||
presentInfo.pWaitSemaphores = signalSemaphores.data();
|
presentInfo.pWaitSemaphores = signalSemaphores.data();
|
||||||
|
|
||||||
std::vector<VkSwapchainKHR> swapChains = {swapChain};
|
std::vector<VkSwapchainKHR> swapChains = { swapChain };
|
||||||
presentInfo.swapchainCount = swapChains.size();
|
presentInfo.swapchainCount = swapChains.size();
|
||||||
presentInfo.pSwapchains = swapChains.data();
|
presentInfo.pSwapchains = swapChains.data();
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
@@ -895,7 +928,8 @@ int main() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
app.run();
|
app.run();
|
||||||
} catch (const std::exception &e) {
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user