diff --git a/.gitmodules b/.gitmodules index 2f603ba..7a36cd7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "external/ttf-parser"] path = external/ttf-parser url = git@github.com:kv01/ttf-parser.git +[submodule "external/freetype"] + path = external/freetype + url = https://gitlab.freedesktop.org/freetype/freetype.git diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 5de037a..f136689 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,7 +4,7 @@ "name": "Win32", "includePath": [ "${workspaceFolder}/src/**", - "${workspaceFolder}/external/**" + "${workspaceFolder}/src/Engine" ], "defines": [ "_DEBUG", diff --git a/CMakeLists.txt b/CMakeLists.txt index 4970c11..adce967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ set(JSON_ROOT ${EXTERNAL_ROOT}/json) set(KTX_ROOT ${EXTERNAL_ROOT}/ktx) set(STB_ROOT ${EXTERNAL_ROOT}/stb) set(TTFPARSER_ROOT ${EXTERNAL_ROOT}/ttf-parser) +set(FREETYPE_ROOT ${EXTERNAL_ROOT}/freetype) set(SPIRV_ROOT ${EXTERNAL_ROOT}/SPIRV-Cross) set(NSAM_ROOT ${EXTERNAL_ROOT}/aftermath) @@ -50,6 +51,7 @@ find_package(Threads REQUIRED) find_package(Assimp REQUIRED) find_package(JSON REQUIRED) find_package(GLFW REQUIRED) +find_package(FreeType REQUIRED) find_package(TTFParser REQUIRED) find_package(GLM REQUIRED) find_package(KTX REQUIRED) @@ -130,6 +132,7 @@ if(WIN32) COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_BINARIES} $ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_GLSLANG} $ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLFW_BINARY} $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FREETYPE_BINARY} $ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ASSIMP_BINARY} $ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${NSAM_BINARIES} $ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${NSAM_LLVM} $ diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index d7d98e4..b8ee817 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -62,9 +62,9 @@ set(GLFW_VULKAN_STATIC OFF CACHE BOOL "GLFW vulkan static") add_subdirectory(${GLFW_ROOT} ${GLFW_ROOT}) #--------------FreeType------------------------------ -#list(APPEND DEPENDENCIES freetype) +list(APPEND DEPENDENCIES freetype) -#add_subdirectory(${FREETYPE_ROOT} ${FREETYPE_ROOT}) +add_subdirectory(${FREETYPE_ROOT} ${FREETYPE_ROOT}) #--------------SLang------------------------------ list(APPEND DEPENDENCIES slang) @@ -73,7 +73,7 @@ if(WIN32) ExternalProject_Add(slang SOURCE_DIR ${SLANG_ROOT} BINARY_DIR ${SLANG_ROOT} - CONFIGURE_COMMAND "" + CONFIGURE_COMMAND premake.bat vs2019 --file=${CMAKE_SOURCE_DIR}/external/slang/premake5.lua gmake --arch=${CMAKE_PLATFORM} --deps=true BUILD_COMMAND msbuild slang.sln -p:Configuration=Release -p:Platform=${CMAKE_PLATFORM} INSTALL_COMMAND "") elseif(UNIX) diff --git a/external/freetype b/external/freetype new file mode 160000 index 0000000..e50798b --- /dev/null +++ b/external/freetype @@ -0,0 +1 @@ +Subproject commit e50798b72043c8b378caa46e0a854519f9028ae4 diff --git a/external/slang b/external/slang index 858c7c5..2e1a84a 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit 858c7c57b125afed9b5b2329d6b02477284e4803 +Subproject commit 2e1a84add57efd9f8a50a88d0569a48ae4b6d834 diff --git a/res/fonts/Calibri.ttf b/res/fonts/Calibri.ttf new file mode 100644 index 0000000..98e329a Binary files /dev/null and b/res/fonts/Calibri.ttf differ diff --git a/res/shaders/TextPass.slang b/res/shaders/TextPass.slang new file mode 100644 index 0000000..6c67faf --- /dev/null +++ b/res/shaders/TextPass.slang @@ -0,0 +1,69 @@ + +struct GlyphData +{ + float2 bearing; + float2 size; +}; +struct ViewData +{ + float4x4 projectionMatrix; +} +layout(set = 0, binding = 0) +ConstantBuffer viewData; +layout(set = 0, binding = 1) +SamplerState glyphSampler; +layout(set = 0, binding = 2) +StructuredBuffer glyphData; +layout(set = 1) +Texture2D glyphTextures[]; +layout(push_constant) +float scale; + +struct VertexStageInput +{ + uint glyphIndex; + float2 position; + uint vertexId : SV_VertexID; +}; + +struct VertexStageOutput +{ + float4 position : SV_Position; + float2 uvCoords : TEXCOORD; + uint glyphIndex : GLYPHINDEX; +}; + +[shader("vertex")] +VertexStageOutput vertexMain(VertexStageInput input) +{ + GlyphData glyph = glyphData[input.glyphIndex]; + + float xpos = input.position.x + glyph.bearing.x * scale; + float ypos = input.position.y - (glyph.size.y - glyph.bearing.y) * scale; + + float w = glyph.size.x * scale; + float h = glyph.size.y * scale; + + float4 coordinates[4] = { + float4(xpos, ypos + h, 0, 0), + float4(xpos, ypos, 0, 1), + float4(xpos + w, ypos, 1, 0), + float4(xpos + w, ypos + h, 1, 1) + }; + float4 vertex = coordinates[input.vertexId]; + VertexStageOutput output; + output.uvCoords = vertex.zw; + output.position = mul(viewData.projectionMatrix, float4(vertex.xy, 0, 1)); + output.glyphIndex = input.glyphIndex; + return output; +} + +[shader("fragment")] +float4 fragmentMain( + float4 position : SV_Position, + float2 uvCoords : TEXCOORD, + uint glyphIndex : GLYPHINDEX +) : SV_Target +{ + return glyphTextures[glyphIndex].Sample(glyphSampler, uvCoords); +} \ No newline at end of file diff --git a/res/shaders/UIPass.slang b/res/shaders/UIPass.slang index 30d28b9..4dbfea0 100644 --- a/res/shaders/UIPass.slang +++ b/res/shaders/UIPass.slang @@ -17,7 +17,6 @@ VertexStageOutput vertexMain(uint vertexId : SV_VertexID) VertexStageOutput output; output.uvCoords = coordinates[vertexId]; output.position = float4(output.uvCoords * 2 - 1, 1, 1); - output.position.y = -output.position.y; return output; } diff --git a/res/shaders/compile.bat b/res/shaders/compile.bat index 831787a..fc2d8cb 100755 --- a/res/shaders/compile.bat +++ b/res/shaders/compile.bat @@ -1,2 +1,2 @@ -slangc ForwardPlus.slang -target spirv -entry vertexMain -profile vs_6_0 -o vertex.spv -I lib/ -D USE_INSTANCING=0 -D NUM_MATERIAL_TEXCOORDS=1 -slangc ForwardPlus.slang -target spirv -entry fragmentMain -profile ps_6_0 -o fragment.spv -I lib/ -D USE_INSTANCING=0 -D NUM_MATERIAL_TEXCOORDS=1 \ No newline at end of file +slangc TextPass.slang -target glsl -entry vertexMain -profile vs_6_0 -o vertex.glsl -I lib/ -D INDEX_VIEW_PARAMS=0 +slangc TextPass.slang -target glsl -entry fragmentMain -profile ps_6_0 -o fragment.glsl -I lib/ -D INDEX_VIEW_PARAMS=0 \ No newline at end of file diff --git a/res/shaders/fragment.glsl b/res/shaders/fragment.glsl new file mode 100644 index 0000000..d710148 --- /dev/null +++ b/res/shaders/fragment.glsl @@ -0,0 +1,20 @@ +#version 450 +layout(row_major) uniform; +layout(row_major) buffer; + +#line 61 0 +layout(location = 0) +out vec4 _S1; + + +#line 61 +void main() +{ + +#line 61 + _S1 = vec4(float(0), float(1), float(0), float(1)); + +#line 61 + return; +} + diff --git a/res/shaders/slang-glslang.dll b/res/shaders/slang-glslang.dll new file mode 100644 index 0000000..cf9cfe1 Binary files /dev/null and b/res/shaders/slang-glslang.dll differ diff --git a/res/shaders/slang-stdlib.bin b/res/shaders/slang-stdlib.bin new file mode 100644 index 0000000..b0cf381 Binary files /dev/null and b/res/shaders/slang-stdlib.bin differ diff --git a/res/shaders/slang.dll b/res/shaders/slang.dll index 8fba5f4..cf8c59e 100644 Binary files a/res/shaders/slang.dll and b/res/shaders/slang.dll differ diff --git a/res/shaders/slangc.exe b/res/shaders/slangc.exe index b63d45d..0fc6bd6 100755 Binary files a/res/shaders/slangc.exe and b/res/shaders/slangc.exe differ diff --git a/res/shaders/vertex.glsl b/res/shaders/vertex.glsl new file mode 100644 index 0000000..6fbe6ae --- /dev/null +++ b/res/shaders/vertex.glsl @@ -0,0 +1,114 @@ +#version 450 +layout(row_major) uniform; +layout(row_major) buffer; + +#line 7 0 +struct GlyphData_0 +{ + vec2 bearing_0; + vec2 size_0; +}; + + +layout(std430, binding = 1) readonly buffer _S1 { + GlyphData_0 _data[]; +} glyphData_0; + +#line 1 +struct ViewParameter_0 +{ + mat4x4 projectionMatrix_0; +}; + + +#line 5 +layout(binding = 0) +layout(std140) uniform _S2 +{ + ViewParameter_0 _data; +} gViewParams_0; + +#line 5 +layout(location = 0) +out vec2 _S3; + + +#line 5 +layout(location = 1) +out uint _S4; + + +#line 5 +layout(location = 0) +in uint _S5; + + +#line 5 +layout(location = 1) +in vec2 _S6; + + +#line 5 +layout(location = 2) +in float _S7; + + +#line 20 +struct VertexStageInput_0 +{ + uint glyphIndex_0; + vec2 position_0; + float scale_0; + uint vertexId_0; +}; + +struct VertexStageOutput_0 +{ + vec4 position_1; + vec2 uvCoords_0; + uint glyphIndex_1; +}; + + +void main() +{ + +#line 36 + VertexStageInput_0 _S8 = VertexStageInput_0(_S5, _S6, _S7, uint(gl_VertexIndex)); + + GlyphData_0 glyph_0 = ((glyphData_0)._data[(_S8.glyphIndex_0)]); + + float xpos_0 = _S8.position_0.x + glyph_0.bearing_0.x * _S8.scale_0; + float ypos_0 = _S8.position_0.y - (glyph_0.size_0.y - glyph_0.bearing_0.y) * _S8.scale_0; + + float w_0 = glyph_0.size_0.x * _S8.scale_0; + + + vec4 coordinates_0[4] = { vec4(xpos_0, ypos_0 + glyph_0.size_0.y * _S8.scale_0, float(0), float(0)), vec4(xpos_0, ypos_0, float(0), float(1)), vec4(xpos_0 + w_0, ypos_0, float(1), float(0)), vec4(xpos_0 + w_0, ypos_0 + w_0, float(1), float(1)) }; + +#line 46 + vec4 vertex_0 = coordinates_0[_S8.vertexId_0]; + +#line 53 + VertexStageOutput_0 output_0; + output_0.uvCoords_0 = vertex_0.zw; + vec4 _S9 = (((vec4(vertex_0.xy, float(0), float(1))) * (gViewParams_0._data.projectionMatrix_0))); + +#line 55 + output_0.position_1 = _S9; + output_0.glyphIndex_1 = _S8.glyphIndex_0; + VertexStageOutput_0 _S10 = output_0; + +#line 57 + gl_Position = _S10.position_1; + +#line 57 + _S3 = _S10.uvCoords_0; + +#line 57 + _S4 = _S10.glyphIndex_1; + +#line 57 + return; +} + diff --git a/src/Engine/Asset/FontAsset.cpp b/src/Engine/Asset/FontAsset.cpp index fc4ef72..4ccb9b1 100644 --- a/src/Engine/Asset/FontAsset.cpp +++ b/src/Engine/Asset/FontAsset.cpp @@ -1,7 +1,8 @@ #include "FontAsset.h" #include "Graphics/GraphicsResources.h" -#define TTF_FONT_PARSER_IMPLEMENTATION -#include "ttfParser.h" +#include +#include FT_FREETYPE_H +#include "Window/WindowManager.h" using namespace Seele; @@ -31,20 +32,30 @@ void FontAsset::save() void FontAsset::load() { - TTFFontParser::FontData font_data; - int8_t error = TTFFontParser::parse_file(getFullPath().c_str(), &font_data, [](void*, void*, int){}, nullptr); - assert(!error); - for(auto pair : font_data.glyphs) + FT_Library ft; + assert(!FT_Init_FreeType(&ft)); + FT_Face face; + assert(!FT_New_Face(ft, getFullPath().c_str(), 0, &face)); + FT_Set_Pixel_Sizes(face, 0, 48); + for(uint8 c = 0; c < 128; ++c) { - const TTFFontParser::Glyph& glyphData = pair.second; - Glyph& glyph = glyphs[pair.first]; - glyph.advance = glyphData.advance_width; - std::memcpy(glyph.boundingBox, glyphData.bounding_box, sizeof(glyphData.bounding_box)); - glyph.center = Vector2(glyphData.glyph_center.x, glyphData.glyph_center.y); - glyph.index = glyphData.glyph_index; - glyph.leftSideBearing = glyphData.left_side_bearing; - glyph.numContours = glyphData.num_contours; - Array curveTextureData; - + Gfx::PGraphics graphics = WindowManager::getGraphics(); + if(FT_Load_Char(face, c, FT_LOAD_RENDER)) + { + std::cout << "error loading " << (char)c << std::endl; + } + TextureCreateInfo imageData; + imageData.format = Gfx::SE_FORMAT_R8_UINT; + imageData.width = face->glyph->bitmap.width; + imageData.height = face->glyph->bitmap.rows; + imageData.resourceData.data = face->glyph->bitmap.buffer; + imageData.resourceData.size = imageData.width * imageData.height; + Glyph& glyph = glyphs[c]; + glyph.texture = graphics->createTexture2D(imageData); + glyph.size = IVector2(face->glyph->bitmap.width, face->glyph->bitmap.rows); + glyph.bearing = IVector2(face->glyph->bitmap_left, face->glyph->bitmap_top); + glyph.advance = face->glyph->advance.x; } + FT_Done_Face(face); + FT_Done_FreeType(ft); } \ No newline at end of file diff --git a/src/Engine/Asset/FontAsset.h b/src/Engine/Asset/FontAsset.h index 4a2ac73..27bf95b 100644 --- a/src/Engine/Asset/FontAsset.h +++ b/src/Engine/Asset/FontAsset.h @@ -13,18 +13,16 @@ public: virtual ~FontAsset(); virtual void save() override; virtual void load() override; -private: + struct Glyph { - int16 index; - int16 numContours; - uint16 advance; - int16 leftSideBearing; - int16 boundingBox[4]; - Vector2 center; - Gfx::PTexture2D curveTexture; - Gfx::PTexture2D bandTexture; + Gfx::PTexture2D texture; + IVector2 size; + IVector2 bearing; + uint32 advance; }; + const Map getGlyphData() const { return glyphs; } +private: Map glyphs; }; DECLARE_REF(FontAsset) diff --git a/src/Engine/Asset/TextureAsset.cpp b/src/Engine/Asset/TextureAsset.cpp index 590722c..afb2fd5 100644 --- a/src/Engine/Asset/TextureAsset.cpp +++ b/src/Engine/Asset/TextureAsset.cpp @@ -3,6 +3,8 @@ #include "Graphics/Graphics.h" #include "Window/WindowManager.h" #include "Graphics/Vulkan/VulkanGraphicsEnums.h" +#include "ktx.h" + using namespace Seele; diff --git a/src/Engine/Asset/TextureLoader.cpp b/src/Engine/Asset/TextureLoader.cpp index df4911c..06e53fb 100644 --- a/src/Engine/Asset/TextureLoader.cpp +++ b/src/Engine/Asset/TextureLoader.cpp @@ -7,6 +7,7 @@ #include #define STB_IMAGE_WRITE_IMPLEMENTATION #include +#include "ktx.h" using namespace Seele; diff --git a/src/Engine/Containers/Map.h b/src/Engine/Containers/Map.h index 51872dd..86cfdef 100644 --- a/src/Engine/Containers/Map.h +++ b/src/Engine/Containers/Map.h @@ -198,7 +198,7 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - Map() + constexpr Map() noexcept : root(-1) , beginIt(-1) , endIt(-1) @@ -207,8 +207,7 @@ public: , comp(Compare()) { } - explicit Map(const Compare& comp, - const Allocator& alloc = Allocator()) + constexpr explicit Map(const Compare& comp, const Allocator& alloc = Allocator()) noexcept(noexcept(Allocator())) : nodeContainer(alloc) , root(-1) , beginIt(-1) @@ -218,7 +217,7 @@ public: , comp(comp) { } - explicit Map(const Allocator& alloc) + constexpr explicit Map(const Allocator& alloc) noexcept(noexcept(Compare)) : nodeContainer(alloc) , root(-1) , beginIt(-1) @@ -228,7 +227,7 @@ public: , comp(Compare()) { } - Map(const Map& other) + constexpr Map(const Map& other) : nodeContainer(other.nodeContainer) , root(other.root) , _size(other._size) @@ -236,18 +235,18 @@ public: { markIteratorsDirty(); } - Map(Map&& other) - : nodeContainer(other.nodeContainer) + constexpr Map(Map&& other) noexcept + : nodeContainer(std::move(other.nodeContainer)) , root(std::move(other.root)) , _size(std::move(other._size)) , comp(std::move(other.comp)) { markIteratorsDirty(); } - ~Map() + constexpr ~Map() noexcept { } - Map& operator=(const Map& other) + constexpr Map& operator=(const Map& other) { if(this != &other) { @@ -259,7 +258,7 @@ public: } return *this; } - Map& operator=(Map&& other) + constexpr Map& operator=(Map&& other) { if(this != &other) { @@ -271,7 +270,7 @@ public: } return *this; } - inline mapped_type& operator[](const key_type& key) + constexpr mapped_type& operator[](const key_type& key) { root = splay(root, key); if (!isValid(root) @@ -284,7 +283,7 @@ public: markIteratorsDirty(); return getNode(root)->pair.value; } - inline mapped_type& operator[](key_type&& key) + constexpr mapped_type& operator[](key_type&& key) { root = splay(root, std::move(key)); if (!isValid(root) @@ -297,7 +296,7 @@ public: markIteratorsDirty(); return getNode(root)->pair.value; } - iterator find(const key_type& key) + constexpr iterator find(const key_type& key) { root = splay(root, key); refreshIterators(); @@ -309,7 +308,7 @@ public: } return iterator(root, &nodeContainer); } - iterator find(key_type&& key) + constexpr iterator find(key_type&& key) { root = splay(root, std::move(key)); refreshIterators(); @@ -321,30 +320,34 @@ public: } return iterator(root, &nodeContainer); } - iterator erase(const key_type& key) + constexpr iterator erase(const key_type& key) { root = remove(root, key); refreshIterators(); return iterator(root, &nodeContainer); } - iterator erase(K&& key) + constexpr iterator erase(key_type&& key) { root = remove(root, std::move(key)); refreshIterators(); return iterator(root, &nodeContainer); } - void clear() + constexpr void clear() { nodeContainer.clear(); root = -1; _size = 0; markIteratorsDirty(); } - bool exists(key_type&& key) + constexpr bool exists(const key_type& key) { - return find(std::forward(key)) != endIt; + return find(key) != endIt; } - iterator begin() + constexpr bool exists(key_type&& key) + { + return find(std::move(key)) != endIt; + } + constexpr iterator begin() { if(iteratorsDirty) { @@ -352,7 +355,7 @@ public: } return beginIt; } - iterator end() + constexpr iterator end() { if(iteratorsDirty) { @@ -360,7 +363,7 @@ public: } return endIt; } - iterator begin() const + constexpr iterator begin() const { if(iteratorsDirty) { @@ -368,7 +371,7 @@ public: } return beginIt; } - iterator end() const + constexpr iterator end() const { if(iteratorsDirty) { @@ -376,11 +379,11 @@ public: } return endIt; } - bool empty() const + constexpr bool empty() const { return nodeContainer.empty(); } - size_type size() const + constexpr size_type size() const { return _size; } diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index af73c17..fd022c3 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -4,7 +4,6 @@ #include "Containers/Array.h" #include "VertexShaderInput.h" #include "ShaderCompiler.h" -#include "ktx.h" namespace Seele { diff --git a/src/Engine/Graphics/GraphicsEnums.h b/src/Engine/Graphics/GraphicsEnums.h index 299717e..ea63ee9 100644 --- a/src/Engine/Graphics/GraphicsEnums.h +++ b/src/Engine/Graphics/GraphicsEnums.h @@ -1404,6 +1404,19 @@ typedef enum SeDescriptorType SE_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } SeDescriptorType; +typedef enum SeDescriptorBindingFlagBits { + SE_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, + SE_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, + SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, + SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, + SE_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = SE_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, + SE_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = SE_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, + SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + SE_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} SeDescriptorBindingFlagBits; +typedef SeFlags SeDescriptorBindingFlags; + typedef enum SeAttachmentLoadOp { SE_ATTACHMENT_LOAD_OP_LOAD = 0, diff --git a/src/Engine/Graphics/GraphicsInitializer.h b/src/Engine/Graphics/GraphicsInitializer.h index ba0cab6..81c91f2 100644 --- a/src/Engine/Graphics/GraphicsInitializer.h +++ b/src/Engine/Graphics/GraphicsInitializer.h @@ -50,73 +50,63 @@ struct ViewportCreateInfo // doesnt own the data, only proxy it struct BulkResourceData { - uint32 size; - uint8 *data; + uint32 size = 0; + uint8 *data = nullptr; Gfx::QueueType owner = Gfx::QueueType::GRAPHICS; - BulkResourceData() - : size(0), data(nullptr), owner(Gfx::QueueType::GRAPHICS) - { - } }; struct TextureCreateInfo { - BulkResourceData resourceData; - uint32 width; - uint32 height; - uint32 depth; - bool bArray; - uint32 arrayLayers; - uint32 mipLevels; - uint32 samples; - Gfx::SeFormat format; - Gfx::SeImageUsageFlagBits usage; - TextureCreateInfo() - : resourceData(), width(1), height(1), depth(1), bArray(false), arrayLayers(1) - , mipLevels(1), samples(1), format(Gfx::SE_FORMAT_R32G32B32A32_SFLOAT) - , usage(Gfx::SE_IMAGE_USAGE_SAMPLED_BIT) - { - } + BulkResourceData resourceData = BulkResourceData(); + uint32 width = 1; + uint32 height = 1; + uint32 depth = 1; + bool bArray = false; + uint32 arrayLayers = 1; + uint32 mipLevels = 1; + uint32 samples = 1; + Gfx::SeFormat format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT; + Gfx::SeImageUsageFlagBits usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT; }; struct SamplerCreateInfo { + Gfx::SeSamplerCreateFlags flags; + Gfx::SeFilter magFilter; + Gfx::SeFilter minFilter; + Gfx::SeSamplerMipmapMode mipmapMode; + Gfx::SeSamplerAddressMode addressModeU; + Gfx::SeSamplerAddressMode addressModeV; + Gfx::SeSamplerAddressMode addressModeW; + float mipLodBias; + uint32 anisotropyEnable; + float maxAnisotropy; + uint32 compareEnable; + Gfx::SeCompareOp compareOp; + float minLod; + float maxLod; + Gfx::SeBorderColor borderColor; + uint32 unnormalizedCoordinates; }; struct VertexBufferCreateInfo { - BulkResourceData resourceData; + BulkResourceData resourceData = BulkResourceData(); // bytes per vertex - uint32 vertexSize; - uint32 numVertices; - VertexBufferCreateInfo() - : resourceData(), vertexSize(0), numVertices(0) - { - } + uint32 vertexSize = 0; + uint32 numVertices = 0; }; struct IndexBufferCreateInfo { - BulkResourceData resourceData; - Gfx::SeIndexType indexType; - IndexBufferCreateInfo() - : resourceData(), indexType(Gfx::SeIndexType::SE_INDEX_TYPE_UINT16) - { - } + BulkResourceData resourceData = BulkResourceData(); + Gfx::SeIndexType indexType = Gfx::SeIndexType::SE_INDEX_TYPE_UINT16; }; struct UniformBufferCreateInfo { - BulkResourceData resourceData; - uint8 bDynamic : 1; - UniformBufferCreateInfo() - : resourceData(), bDynamic(0) - { - } + BulkResourceData resourceData = BulkResourceData(); + uint8 bDynamic : 1 = 0; }; struct StructuredBufferCreateInfo { BulkResourceData resourceData; uint8 bDynamic: 1; - StructuredBufferCreateInfo() - : resourceData(), bDynamic(0) - { - } }; struct ShaderCreateInfo { @@ -138,13 +128,6 @@ struct SePushConstantRange }; struct VertexElement { - VertexElement(){} - //VertexElement(uint8 attributeIndex, SeFormat vertexFormat, uint8 offset) - // : attributeIndex(attributeIndex), vertexFormat(vertexFormat), offset(offset) - //{} - VertexElement(uint8 streamIndex, uint8 offset, SeFormat vertexFormat, uint8 attributeIndex, uint8 stride) - : streamIndex(streamIndex), offset(offset), vertexFormat(vertexFormat), attributeIndex(attributeIndex), stride(stride) - {} uint8 streamIndex; uint8 offset; SeFormat vertexFormat; @@ -152,6 +135,7 @@ struct VertexElement uint8 stride; uint8 bInstanced = 0; }; +static_assert(std::is_aggregate_v); struct RasterizationState { uint8 depthClampEnable : 1; diff --git a/src/Engine/Graphics/GraphicsResources.cpp b/src/Engine/Graphics/GraphicsResources.cpp index 8fa32c3..06de0c2 100644 --- a/src/Engine/Graphics/GraphicsResources.cpp +++ b/src/Engine/Graphics/GraphicsResources.cpp @@ -93,17 +93,17 @@ ShaderCollection& ShaderMap::createShaders( return collection; } -void DescriptorLayout::addDescriptorBinding(uint32 bindingIndex, SeDescriptorType type, uint32 arrayCount) +void DescriptorLayout::addDescriptorBinding(uint32 bindingIndex, SeDescriptorType type, uint32 arrayCount, SeDescriptorBindingFlags bindingFlags) { if (descriptorBindings.size() <= bindingIndex) { descriptorBindings.resize(bindingIndex + 1); } - DescriptorBinding binding; + DescriptorBinding& binding = descriptorBindings[bindingIndex]; binding.binding = bindingIndex; binding.descriptorType = type; binding.descriptorCount = arrayCount; - descriptorBindings[bindingIndex] = binding; + binding.bindingFlags = bindingFlags; } PDescriptorSet DescriptorLayout::allocateDescriptorSet() diff --git a/src/Engine/Graphics/GraphicsResources.h b/src/Engine/Graphics/GraphicsResources.h index ba5c4a9..e674cba 100644 --- a/src/Engine/Graphics/GraphicsResources.h +++ b/src/Engine/Graphics/GraphicsResources.h @@ -160,16 +160,10 @@ public: : binding(other.binding), descriptorType(other.descriptorType), descriptorCount(other.descriptorCount), shaderStages(other.shaderStages) { } - void operator=(const DescriptorBinding &other) - { - binding = other.binding; - descriptorType = other.descriptorType; - descriptorCount = other.descriptorCount; - shaderStages = other.shaderStages; - } uint32_t binding; SeDescriptorType descriptorType; uint32_t descriptorCount; + SeDescriptorBindingFlags bindingFlags = 0; SeShaderStageFlags shaderStages; }; DEFINE_REF(DescriptorBinding) @@ -196,6 +190,7 @@ public: virtual void updateBuffer(uint32 binding, PStructuredBuffer structuredBuffer) = 0; virtual void updateSampler(uint32 binding, PSamplerState samplerState) = 0; virtual void updateTexture(uint32 binding, PTexture texture, PSamplerState samplerState = nullptr) = 0; + virtual void updateTextureArray(uint32_t binding, Array texture) = 0; virtual bool operator<(PDescriptorSet other) = 0; virtual uint32 getSetIndex() const = 0; @@ -224,7 +219,7 @@ public: return *this; } virtual void create() = 0; - virtual void addDescriptorBinding(uint32 binding, SeDescriptorType type, uint32 arrayCount = 1); + virtual void addDescriptorBinding(uint32 binding, SeDescriptorType type, uint32 arrayCount = 1, SeDescriptorBindingFlags bindingFlags = 0); virtual void reset(); virtual PDescriptorSet allocateDescriptorSet(); const Array &getBindings() const { return descriptorBindings; } @@ -557,6 +552,7 @@ public: virtual void bindDescriptor(const Array& sets) = 0; virtual void bindVertexBuffer(const Array& streams) = 0; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; virtual void draw(const MeshBatchElement& data) = 0; virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) = 0; std::string name; @@ -571,6 +567,7 @@ public: virtual void bindPipeline(Gfx::PComputePipeline pipeline) = 0; virtual void bindDescriptor(Gfx::PDescriptorSet set) = 0; virtual void bindDescriptor(const Array& sets) = 0; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) = 0; std::string name; }; diff --git a/src/Engine/Graphics/RenderPass/CMakeLists.txt b/src/Engine/Graphics/RenderPass/CMakeLists.txt index 944ec7d..83f63cc 100644 --- a/src/Engine/Graphics/RenderPass/CMakeLists.txt +++ b/src/Engine/Graphics/RenderPass/CMakeLists.txt @@ -11,5 +11,7 @@ target_sources(Engine RenderGraph.h RenderGraph.cpp RenderPass.h + TextPass.h + TextPass.cpp UIPass.h UIPass.cpp) \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/TextPass.cpp b/src/Engine/Graphics/RenderPass/TextPass.cpp new file mode 100644 index 0000000..0f391a8 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/TextPass.cpp @@ -0,0 +1,200 @@ +#include "TextPass.h" +#include "RenderGraph.h" +#include "Graphics/Graphics.h" +#include "Graphics/VertexShaderInput.h" + +using namespace Seele; + +TextPass::TextPass(Gfx::PGraphics graphics, Gfx::PViewport viewport, Gfx::PRenderTargetAttachment attachment) + : RenderPass(graphics, viewport) + , renderTarget(attachment) +{ +} + +TextPass::~TextPass() +{ + +} + +MainJob TextPass::beginFrame() +{ + for(TextRender& render : passData.texts) + { + FontData& fontData = getFontData(render.font); + TextResources& resources = textResources.add(); + Array instanceData; + float x = render.position.x; + float y = render.position.y; + for(uint32 c : render.text) + { + instanceData.add(GlyphInstanceData{ + .glyphIndex = fontData.characterToGlyphIndex[c], + .position = Vector2(x, y) + }); + x += (fontData.characterAdvance[c] >> 6) * render.scale; + } + VertexBufferCreateInfo vbInfo; + vbInfo.numVertices = static_cast(instanceData.size()); + vbInfo.vertexSize = sizeof(GlyphInstanceData); + vbInfo.resourceData.data = reinterpret_cast(instanceData.data()); + vbInfo.resourceData.size = static_cast(instanceData.size()); + resources.vertexBuffer = graphics->createVertexBuffer(vbInfo); + + resources.descriptorSet = descriptorLayout->allocateDescriptorSet(); + resources.descriptorSet->updateBuffer(0, projectionBuffer); + resources.descriptorSet->updateSampler(1, glyphSampler); + resources.descriptorSet->updateBuffer(2, fontData.structuredBuffer); + resources.descriptorSet->writeChanges(); + + resources.textureArraySet = descriptorLayout->allocateDescriptorSet(); + resources.textureArraySet->updateTextureArray(0, fontData.textures); + + resources.textureArraySet->writeChanges(); + resources.scale = render.scale; + } + co_return; +} + +MainJob TextPass::render() +{ + graphics->beginRenderPass(renderPass); + Array commands; + for(TextResources& resources : textResources) + { + Gfx::PRenderCommand command = graphics->createRenderCommand("TextPassCommand"); + command->setViewport(viewport); + command->bindPipeline(pipeline); + + command->bindVertexBuffer({VertexInputStream(0, 0, resources.vertexBuffer)}); + + command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float), &resources.scale); + command->draw(4, static_cast(resources.vertexBuffer->getNumVertices()), 0, 0); + commands.add(command); + } + graphics->executeCommands(commands); + graphics->endRenderPass(); + co_return; +} + +MainJob TextPass::endFrame() +{ + co_return; +} + +void TextPass::publishOutputs() +{ +} + +void TextPass::createRenderPass() +{ + depthAttachment = resources->requestRenderTarget("UIPASS_DEPTH"); + std::ifstream codeStream("./shaders/TextPass.slang", std::ios::ate); + auto fileSize = codeStream.tellg(); + codeStream.seekg(0); + Array buffer(static_cast(fileSize)); + codeStream.read(buffer.data(), fileSize); + + ShaderCreateInfo createInfo; + createInfo.shaderCode.add(std::string(buffer.data())); + createInfo.defines["INDEX_VIEW_PARAMS"] = "0"; + createInfo.name = "TextVertex"; + createInfo.entryPoint = "vertexMain"; + vertexShader = graphics->createVertexShader(createInfo); + + createInfo.name = "TextFragment"; + createInfo.entryPoint = "fragmentMain"; + fragmentShader = graphics->createFragmentShader(createInfo); + Array elements; + elements.add({ + .streamIndex = 0, + .offset = offsetof(GlyphInstanceData, glyphIndex), + .vertexFormat = Gfx::SE_FORMAT_R32_UINT, + .attributeIndex = 0, + .stride = sizeof(GlyphInstanceData), + .bInstanced = 1 + }); + elements.add({ + .streamIndex = 0, + .offset = offsetof(GlyphInstanceData, position), + .vertexFormat = Gfx::SE_FORMAT_R32G32_SFLOAT, + .attributeIndex = 1, + .stride = sizeof(GlyphInstanceData), + .bInstanced = 1 + }); + declaration = graphics->createVertexDeclaration(elements); + + descriptorLayout = graphics->createDescriptorLayout("TextDescriptor"); + descriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + descriptorLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER); + descriptorLayout->addDescriptorBinding(2, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT); + descriptorLayout->create(); + + textureArrayLayout = graphics->createDescriptorLayout("TextureArray"); + textureArrayLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT); + textureArrayLayout->create(); + + Matrix4 projectionMatrix = glm::ortho(0.f, (float)viewport->getSizeX(), 0.f, (float)viewport->getSizeY()); + projectionBuffer = graphics->createUniformBuffer({ + .resourceData = { + .size = sizeof(Matrix4), + .data = (uint8*)&projectionMatrix, + }, + .bDynamic = false, + }); + + glyphSampler = graphics->createSamplerState({ + .magFilter = Gfx::SE_FILTER_LINEAR, + .minFilter = Gfx::SE_FILTER_LINEAR, + .addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE + }); + + pipelineLayout = graphics->createPipelineLayout(); + pipelineLayout->addDescriptorLayout(0, descriptorLayout); + pipelineLayout->addDescriptorLayout(1, textureArrayLayout); + pipelineLayout->addPushConstants({ + .stageFlags = Gfx::SE_SHADER_STAGE_VERTEX_BIT, + .offset = 0, + .size = sizeof(float)}); + pipelineLayout->create(); + + Gfx::PRenderTargetLayout layout = new Gfx::RenderTargetLayout(renderTarget, depthAttachment); + renderPass = graphics->createRenderPass(layout, viewport); + + GraphicsPipelineCreateInfo pipelineInfo; + pipelineInfo.vertexDeclaration = declaration; + pipelineInfo.vertexShader = vertexShader; + pipelineInfo.fragmentShader = fragmentShader; + pipelineInfo.renderPass = renderPass; + pipelineInfo.pipelineLayout = pipelineLayout; + pipelineInfo.rasterizationState.cullMode = Gfx::SE_CULL_MODE_NONE; + pipelineInfo.topology = Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + + pipeline = graphics->createGraphicsPipeline(pipelineInfo); +} +TextPass::FontData& TextPass::getFontData(PFontAsset font) +{ + if(fontData.exists(font)) + { + return fontData[font]; + } + const Map& fontGlyphs = font->getGlyphData(); + FontData& fd = fontData[font]; + Array buffer; + buffer.reserve(fontGlyphs.size()); + for(const auto& [key, value] : fontGlyphs) + { + fd.characterToGlyphIndex[key] = static_cast(buffer.size()); + fd.characterAdvance[key] = value.advance; + fd.textures.add(value.texture); + GlyphData& gd = buffer.add(); + gd.bearing = value.bearing; + gd.size = value.size; + } + StructuredBufferCreateInfo bufferInfo; + bufferInfo.bDynamic = false; + bufferInfo.resourceData.data = reinterpret_cast(buffer.data()); + bufferInfo.resourceData.size = static_cast(buffer.size()); + fd.structuredBuffer = graphics->createStructuredBuffer(bufferInfo); + return fontData[font]; +} diff --git a/src/Engine/Graphics/RenderPass/TextPass.h b/src/Engine/Graphics/RenderPass/TextPass.h new file mode 100644 index 0000000..aeb1d06 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/TextPass.h @@ -0,0 +1,85 @@ +#pragma once +#include "RenderPass.h" +#include "UI/RenderHierarchy.h" +#include "Graphics/GraphicsResources.h" +#include "Asset/FontAsset.h" + +namespace Seele +{ +DECLARE_NAME_REF(Gfx, Texture2D) +DECLARE_NAME_REF(Gfx, RenderTargetAttachment) +DECLARE_NAME_REF(Gfx, StructuredBuffer) +struct TextRender +{ + std::string text; + PFontAsset font; + Vector4 textColor; + Vector2 position; + float scale; +}; +struct TextPassData +{ + Array texts; +}; + +class TextPass : public RenderPass +{ +public: + TextPass(Gfx::PGraphics graphics, Gfx::PViewport viewport, Gfx::PRenderTargetAttachment renderTarget); + virtual ~TextPass(); + virtual MainJob beginFrame() override; + virtual MainJob render() override; + virtual MainJob endFrame() override; + virtual void publishOutputs() override; + virtual void createRenderPass() override; +private: + struct GlyphData + { + Vector2 bearing; + Vector2 size; + }; + struct GlyphInstanceData + { + uint32 glyphIndex; + Vector2 position; + }; + struct FontData + { + Gfx::PStructuredBuffer structuredBuffer; + Array textures; + Map characterToGlyphIndex; + // Logically this should be part of GlyphData, + // but because GlyphData mirrors shader data and we need + // the advance on the CPU, we need this in a separate structure + Map characterAdvance; + }; + FontData& getFontData(PFontAsset font); + Map fontData; + + struct TextResources + { + Gfx::PDescriptorSet descriptorSet; + Gfx::PDescriptorSet textureArraySet; + Gfx::PVertexBuffer vertexBuffer; + float scale; + }; + Array textResources; + + Gfx::PRenderTargetAttachment renderTarget; + Gfx::PRenderTargetAttachment depthAttachment; + Gfx::PTexture2D depthBuffer; + + Gfx::PDescriptorLayout descriptorLayout; + Gfx::PDescriptorLayout textureArrayLayout; + + Gfx::PUniformBuffer projectionBuffer; + Gfx::PSamplerState glyphSampler; + + Gfx::PVertexDeclaration declaration; + Gfx::PVertexShader vertexShader; + Gfx::PFragmentShader fragmentShader; + Gfx::PPipelineLayout pipelineLayout; + Gfx::PGraphicsPipeline pipeline; +}; +DEFINE_REF(TextPass); +} // namespace Seele diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp index ac3a30e..019ed7c 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp @@ -290,6 +290,13 @@ void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) PIndexBuffer buf = indexBuffer.cast(); vkCmdBindIndexBuffer(handle, buf->getHandle(), 0, cast(buf->getIndexType())); } + +void RenderCommand::pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) +{ + assert(threadId == std::this_thread::get_id()); + vkCmdPushConstants(handle, layout.cast()->getHandle(), stage, offset, size, data); +} + void RenderCommand::draw(const MeshBatchElement& data) { assert(threadId == std::this_thread::get_id()); @@ -386,6 +393,12 @@ void ComputeCommand::bindDescriptor(const Array& descriptor delete[] sets; } +void ComputeCommand::pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) +{ + assert(threadId == std::this_thread::get_id()); + vkCmdPushConstants(handle, layout.cast()->getHandle(), stage, offset, size, data); +} + void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) { assert(threadId == std::this_thread::get_id()); diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h index c2e6c63..9515e12 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h @@ -89,6 +89,7 @@ public: virtual void bindDescriptor(const Array& descriptorSets) override; virtual void bindVertexBuffer(const Array& streams) override; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; virtual void draw(const MeshBatchElement& data) override; virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override; private: @@ -121,6 +122,7 @@ public: virtual void bindPipeline(Gfx::PComputePipeline pipeline) override; virtual void bindDescriptor(Gfx::PDescriptorSet set) override; virtual void bindDescriptor(const Array& sets) override; + virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) override; private: PComputePipeline pipeline; diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp index db06c23..c93fa39 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp @@ -29,6 +29,7 @@ void DescriptorLayout::create() return; } bindings.resize(descriptorBindings.size()); + Array bindingFlags(descriptorBindings.size()); for (size_t i = 0; i < descriptorBindings.size(); ++i) { VkDescriptorSetLayoutBinding &binding = bindings[i]; @@ -38,9 +39,16 @@ void DescriptorLayout::create() binding.descriptorType = cast(rhiBinding.descriptorType); binding.stageFlags = rhiBinding.shaderStages; binding.pImmutableSamplers = nullptr; + bindingFlags[i] = rhiBinding.bindingFlags; } VkDescriptorSetLayoutCreateInfo createInfo = init::DescriptorSetLayoutCreateInfo(bindings.data(), (uint32)bindings.size()); + VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo = {}; + bindingFlagsInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + bindingFlagsInfo.pNext = nullptr; + bindingFlagsInfo.bindingCount = static_cast(bindingFlags.size()); + bindingFlagsInfo.pBindingFlags = bindingFlags.data(); + createInfo.pNext = &bindingFlagsInfo; VK_CHECK(vkCreateDescriptorSetLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle)); allocator = new DescriptorAllocator(graphics, *this); @@ -188,20 +196,54 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx:: imageInfo.sampler = vulkanSampler->sampler; } imageInfos.add(imageInfo); + VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + if(samplerState != nullptr) + { + descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + } + else if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) + { + descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet( setHandle, - samplerState != nullptr ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + descriptorType, binding, &imageInfos.back()); - if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) - { - writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - } + writeDescriptors.add(writeDescriptor); cachedData[binding] = vulkanTexture; } +void DescriptorSet::updateTextureArray(uint32_t binding, Array textures) +{ + // maybe make this a parameter? + uint32 arrayElement = 0; + for(const auto& gfxTexture : textures) + { + TextureHandle* vulkanTexture = TextureBase::cast(gfxTexture); + imageInfos.add( + init::DescriptorImageInfo( + VK_NULL_HANDLE, + vulkanTexture->getView(), + cast(vulkanTexture->getLayout()))); + + VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) + { + descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } + VkWriteDescriptorSet& write = writeDescriptors.add( + init::WriteDescriptorSet( + setHandle, + descriptorType, + binding, + &imageInfos.back() + )); + write.dstArrayElement = arrayElement++; + } +} bool DescriptorSet::operator<(Gfx::PDescriptorSet other) { @@ -281,6 +323,20 @@ void DescriptorAllocator::allocateDescriptorSet(Gfx::PDescriptorSet &descriptorS VkDescriptorSetLayout layoutHandle = layout.getHandle(); VkDescriptorSetAllocateInfo allocInfo = init::DescriptorSetAllocateInfo(poolHandle, &layoutHandle, 1); + VkDescriptorSetVariableDescriptorCountAllocateInfo setCounts = {}; + setCounts.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO; + setCounts.pNext = nullptr; + setCounts.descriptorSetCount = 1; + uint32 counts = 0; + for(const auto& binding : layout.bindings) + { + if(binding.binding & Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) + { + counts = binding.descriptorCount; + } + } + setCounts.pDescriptorCounts = &counts; + allocInfo.pNext = &setCounts; for(uint32 setIndex = 0; setIndex < cachedHandles.size(); ++setIndex) { diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h index 3d997c8..4ec3cce 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h @@ -12,11 +12,10 @@ public: DescriptorLayout(PGraphics graphics, const std::string& name); virtual ~DescriptorLayout(); virtual void create(); - inline VkDescriptorSetLayout getHandle() const + constexpr VkDescriptorSetLayout getHandle() const { return layoutHandle; } - private: uint32 hash; PGraphics graphics; @@ -72,6 +71,7 @@ public: virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer); virtual void updateSampler(uint32_t binding, Gfx::PSamplerState samplerState); virtual void updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSamplerState sampler = nullptr); + virtual void updateTextureArray(uint32_t binding, Array texture); virtual bool operator<(Gfx::PDescriptorSet other); inline bool isCurrentlyBound() const diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp index 003eb7b..2578f81 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp @@ -204,11 +204,27 @@ Gfx::PComputePipeline Graphics::createComputePipeline(const ComputePipelineCreat return pipeline; } -Gfx::PSamplerState Graphics::createSamplerState(const SamplerCreateInfo&) +Gfx::PSamplerState Graphics::createSamplerState(const SamplerCreateInfo& createInfo) { - PSamplerState sampler = new SamplerState(); // TODO: proper sampler creation + PSamplerState sampler = new SamplerState(); VkSamplerCreateInfo vkInfo = init::SamplerCreateInfo(); + vkInfo.addressModeU = cast(createInfo.addressModeU); + vkInfo.addressModeV = cast(createInfo.addressModeV); + vkInfo.addressModeW = cast(createInfo.addressModeW); + vkInfo.anisotropyEnable = createInfo.anisotropyEnable; + vkInfo.borderColor = cast(createInfo.borderColor); + vkInfo.compareEnable = createInfo.compareEnable; + vkInfo.compareOp = cast(createInfo.compareOp); + vkInfo.flags = createInfo.flags; + vkInfo.magFilter = cast(createInfo.magFilter); + vkInfo.maxAnisotropy = createInfo.maxAnisotropy; + vkInfo.maxLod = createInfo.maxLod; + vkInfo.minFilter = cast(createInfo.minFilter); + vkInfo.minLod = createInfo.minLod; + vkInfo.mipLodBias = createInfo.mipLodBias; + vkInfo.mipmapMode = cast(createInfo.mipmapMode); + vkInfo.unnormalizedCoordinates = createInfo.unnormalizedCoordinates; VK_CHECK(vkCreateSampler(handle, &vkInfo, nullptr, &sampler->sampler)); return sampler; } @@ -537,6 +553,15 @@ void Graphics::createDevice(GraphicsInitializer initializer) queueInfos.data(), (uint32)queueInfos.size(), &features); + + VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexing = {}; + std::memset(&descriptorIndexing, 0, sizeof(descriptorIndexing)); + descriptorIndexing.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + descriptorIndexing.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + descriptorIndexing.runtimeDescriptorArray = VK_TRUE; + descriptorIndexing.descriptorBindingVariableDescriptorCount = VK_TRUE; + descriptorIndexing.descriptorBindingPartiallyBound = VK_TRUE; + deviceInfo.pNext = &descriptorIndexing; #if ENABLE_VALIDATION VkDeviceDiagnosticsConfigCreateInfoNV crashDiagInfo; crashDiagInfo.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.cpp index ddc6ecb..ba89021 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.cpp @@ -1421,3 +1421,134 @@ Gfx::SeClearValue Seele::Vulkan::cast(const VkClearValue& clear) } return result; } + +VkSamplerAddressMode Seele::Vulkan::cast(const Gfx::SeSamplerAddressMode &mode) +{ + switch(mode) + { + case SE_SAMPLER_ADDRESS_MODE_REPEAT: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case SE_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + case SE_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: + return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; + default: + return VK_SAMPLER_ADDRESS_MODE_MAX_ENUM; + } +} +Gfx::SeSamplerAddressMode Seele::Vulkan::cast(const VkSamplerAddressMode &mode) +{ + switch(mode) + { + case VK_SAMPLER_ADDRESS_MODE_REPEAT: + return SE_SAMPLER_ADDRESS_MODE_REPEAT; + case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + return SE_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + return SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + return SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: + return SE_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; + default: + return SE_SAMPLER_ADDRESS_MODE_MAX_ENUM; + } +} +VkBorderColor Seele::Vulkan::cast(const Gfx::SeBorderColor &color) +{ + switch(color) + { + case SE_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + case SE_BORDER_COLOR_INT_TRANSPARENT_BLACK: + return VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; + case SE_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + case SE_BORDER_COLOR_INT_OPAQUE_BLACK: + return VK_BORDER_COLOR_INT_OPAQUE_BLACK; + case SE_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + case SE_BORDER_COLOR_INT_OPAQUE_WHITE: + return VK_BORDER_COLOR_INT_OPAQUE_WHITE; + default: + return VK_BORDER_COLOR_MAX_ENUM; + } +} +Gfx::SeBorderColor Seele::Vulkan::cast(const VkBorderColor &color) +{ + switch(color) + { + case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + return SE_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: + return SE_BORDER_COLOR_INT_TRANSPARENT_BLACK; + case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + return SE_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + case VK_BORDER_COLOR_INT_OPAQUE_BLACK: + return SE_BORDER_COLOR_INT_OPAQUE_BLACK; + case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + return SE_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + case VK_BORDER_COLOR_INT_OPAQUE_WHITE: + return SE_BORDER_COLOR_INT_OPAQUE_WHITE; + default: + return SE_BORDER_COLOR_MAX_ENUM; + } +} + +VkFilter Seele::Vulkan::cast(const Gfx::SeFilter &filter) +{ + switch(filter) + { + case SE_FILTER_NEAREST: + return VK_FILTER_NEAREST; + case SE_FILTER_LINEAR: + return VK_FILTER_LINEAR; + case SE_FILTER_CUBIC_IMG: + return VK_FILTER_CUBIC_IMG; + default: + return VK_FILTER_MAX_ENUM; + } +} +Gfx::SeFilter Seele::Vulkan::cast(const VkFilter &filter) +{ + switch(filter) + { + case VK_FILTER_NEAREST: + return SE_FILTER_NEAREST; + case VK_FILTER_LINEAR: + return SE_FILTER_LINEAR; + case VK_FILTER_CUBIC_IMG: + return SE_FILTER_CUBIC_IMG; + default: + return SE_FILTER_MAX_ENUM; + } +} + +VkSamplerMipmapMode Seele::Vulkan::cast(const Gfx::SeSamplerMipmapMode &filter) +{ + switch(filter) + { + case SE_SAMPLER_MIPMAP_MODE_NEAREST: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SE_SAMPLER_MIPMAP_MODE_LINEAR: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + default: + return VK_SAMPLER_MIPMAP_MODE_MAX_ENUM; + } +} +Gfx::SeSamplerMipmapMode Seele::Vulkan::cast(const VkSamplerMipmapMode &filter) +{ + switch(filter) + { + case VK_SAMPLER_MIPMAP_MODE_NEAREST: + return SE_SAMPLER_MIPMAP_MODE_NEAREST; + case VK_SAMPLER_MIPMAP_MODE_LINEAR: + return SE_SAMPLER_MIPMAP_MODE_LINEAR; + default: + return SE_SAMPLER_MIPMAP_MODE_MAX_ENUM; + } +} \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.h b/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.h index 03aa288..060b077 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.h +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsEnums.h @@ -54,5 +54,13 @@ VkCompareOp cast(const Gfx::SeCompareOp &op); Gfx::SeCompareOp cast(const VkCompareOp &op); VkClearValue cast(const Gfx::SeClearValue &clear); Gfx::SeClearValue cast(const VkClearValue &clear); +VkSamplerAddressMode cast(const Gfx::SeSamplerAddressMode &mode); +Gfx::SeSamplerAddressMode cast(const VkSamplerAddressMode &mode); +VkBorderColor cast(const Gfx::SeBorderColor &color); +Gfx::SeBorderColor cast(const VkBorderColor &color); +VkFilter cast(const Gfx::SeFilter &filter); +Gfx::SeFilter cast(const VkFilter &filter); +VkSamplerMipmapMode cast(const Gfx::SeSamplerMipmapMode &filter); +Gfx::SeSamplerMipmapMode cast(const VkSamplerMipmapMode &filter); } // namespace Vulkan } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/MaterialAsset.cpp b/src/Engine/Material/MaterialAsset.cpp index ae22592..8cbee6d 100644 --- a/src/Engine/Material/MaterialAsset.cpp +++ b/src/Engine/Material/MaterialAsset.cpp @@ -116,8 +116,7 @@ void MaterialAsset::load() { PSamplerParameter p = new SamplerParameter(param.key(), 0, bindingCounter); layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER); - SamplerCreateInfo createInfo; - p->data = WindowManager::getGraphics()->createSamplerState(createInfo); + p->data = WindowManager::getGraphics()->createSamplerState({}); parameters.add(p); } else diff --git a/src/Engine/Window/InspectorView.cpp b/src/Engine/Window/InspectorView.cpp index aaa4df9..7f5bb3b 100644 --- a/src/Engine/Window/InspectorView.cpp +++ b/src/Engine/Window/InspectorView.cpp @@ -2,17 +2,29 @@ #include "Graphics/Graphics.h" #include "Scene/Actor/Actor.h" #include "Window.h" +#include "Asset/AssetRegistry.h" using namespace Seele; InspectorView::InspectorView(Gfx::PGraphics graphics, PWindow window, const ViewportCreateInfo &createInfo) : View(graphics, window, createInfo, "InspectorView") , uiPass(UIPass(graphics, viewport, new Gfx::SwapchainAttachment(window->getGfxHandle()))) + , textPass(TextPass(graphics, viewport, new Gfx::SwapchainAttachment(window->getGfxHandle()))) { + AssetRegistry::importFile("./fonts/Calibri.ttf"); PRenderGraphResources resources = new RenderGraphResources(); uiPass.setResources(resources); + textPass.setResources(resources); uiPass.publishOutputs(); + textPass.publishOutputs(); uiPass.createRenderPass(); + textPass.createRenderPass(); + TextRender& render = textPassData.texts.add(); + render.font = AssetRegistry::findFont("Calibri"); + render.text = "Seele Engine"; + render.position = Vector2(0.5f, 0.5f); + render.scale = 1.0f; + render.textColor = Vector4(1, 1, 1, 1); } InspectorView::~InspectorView() @@ -31,19 +43,21 @@ Job InspectorView::update() void InspectorView::commitUpdate() { - } void InspectorView::prepareRender() { - + textPass.updateViewFrame(textPassData); } MainJob InspectorView::render() { return uiPass.beginFrame() + .then(textPass.beginFrame()) .then(uiPass.render()) - .then(uiPass.endFrame()); + .then(textPass.render()) + .then(uiPass.endFrame()) + .then(textPass.endFrame()); } void InspectorView::keyCallback(KeyCode, InputAction, KeyModifier) diff --git a/src/Engine/Window/InspectorView.h b/src/Engine/Window/InspectorView.h index db62bf5..d5c2e9d 100644 --- a/src/Engine/Window/InspectorView.h +++ b/src/Engine/Window/InspectorView.h @@ -2,6 +2,7 @@ #include "View.h" #include "Graphics/RenderPass/RenderGraph.h" #include "Graphics/RenderPass/UIPass.h" +#include "Graphics/RenderPass/TextPass.h" #include "UI/Elements/Panel.h" namespace Seele @@ -22,8 +23,10 @@ public: void selectActor(); protected: UIPass uiPass; + TextPass textPass; UIPassData uiPassData; + TextPassData textPassData; UI::PPanel rootPanel; PActor selectedActor; diff --git a/src/Engine/Window/SceneView.cpp b/src/Engine/Window/SceneView.cpp index dd7bdfa..f57b0d4 100644 --- a/src/Engine/Window/SceneView.cpp +++ b/src/Engine/Window/SceneView.cpp @@ -20,7 +20,6 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo { scene = new Scene(graphics); scene->addActor(activeCamera); - AssetRegistry::importFile("./fonts/GLSNECB.ttf"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Diffuse.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Lightmap.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Face_Diffuse.png"); diff --git a/src/Engine/main.cpp b/src/Engine/main.cpp index 78d7f54..a2e713d 100644 --- a/src/Engine/main.cpp +++ b/src/Engine/main.cpp @@ -19,7 +19,7 @@ int main() mainWindowInfo.pixelFormat = Gfx::SE_FORMAT_B8G8R8A8_UNORM; auto window = windowManager->addWindow(mainWindowInfo); ViewportCreateInfo sceneViewInfo; - sceneViewInfo.sizeX = 1280; + sceneViewInfo.sizeX = 680; sceneViewInfo.sizeY = 720; sceneViewInfo.offsetX = 0; sceneViewInfo.offsetY = 0; @@ -31,144 +31,12 @@ int main() inspectorViewInfo.sizeY = 720; inspectorViewInfo.offsetX = 640; inspectorViewInfo.offsetY = 0; - //PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo); - //window->addView(inspectorView); + PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo); + window->addView(inspectorView); sceneView->setFocused(); window->render(); getGlobalThreadPool().mainLoop(); return 0; -} -/* -#include -#include -#include -#include - -struct Return; -struct Promise -{ - Promise() - { - handle = std::coroutine_handle::from_promise(*this); - numRefs = 0; - } - Return get_return_object(); - std::suspend_always initial_suspend() noexcept { return {}; } - std::suspend_always final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception() {} - void resume() { handle.resume(); } - void addRef() - { - numRefs++; - } - void removeRef() - { - numRefs--; - if(numRefs == 0) - { - if(handle.done()) - { - handle.destroy(); - } - else - { - resume(); - } - } - } - std::coroutine_handle handle; - uint64_t numRefs; -}; - -struct Return -{ - using promise_type = Promise; - Return(Promise* promise) - : promise(promise) - { - promise->addRef(); - } - Return(const Return& other) - { - promise = other.promise; - if(promise != nullptr) - { - promise->addRef(); - } - } - Return(Return&& other) - { - promise = other.promise; - other.promise = nullptr; - } - ~Return() - { - promise->removeRef(); - } - Return& operator=(const Return& other) - { - if(this != &other) - { - if(promise != nullptr) - { - promise->removeRef(); - } - promise = other.promise; - if(promise != nullptr) - { - promise->addRef(); - } - } - return *this; - } - Return& operator=(Return&& other) - { - if(this != &other) - { - if(promise != nullptr) - { - promise->removeRef(); - } - promise = other.promise; - } - } - Promise* promise; -}; - - -Return Promise::get_return_object(){ - return {this}; -} - -Return coro1() -{ - std::cout << "coro1" << std::endl; - co_return; -} - -Return coro2() -{ - std::cout << "coro2" << std::endl; - co_return; -} - -Return coroAll(std::vector coros) -{ - for(auto coro : coros) - { - coro.promise->resume(); - } - co_return; -} - -int main() -{ - std::vector returns{coro1(), coro2()}; - std::thread t = std::thread([returns](){ - coroAll(returns); - }); - t.join(); -}*/ \ No newline at end of file +} \ No newline at end of file