diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-01-23 21:57:31 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-01-23 21:57:31 -0500 |
| commit | e93eb289ca44e98967482ab80fd5329f85ccd03e (patch) | |
| tree | 4164b6d5b9ac2e40d18ec3eea52730c9f9606ccb | |
| parent | 846a6e1185417ee3e187edc06ef327d180bf0d9b (diff) | |
pke: first-pass 2d overlay render pass scaffolding
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | assets/shaders/glyph.frag | 24 | ||||
| -rw-r--r-- | assets/shaders/glyph.vert | 32 | ||||
| -rw-r--r-- | assets/shaders/present.vert | 8 | ||||
| -rw-r--r-- | assets/shaders/vertex.vert | 22 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | editor/editor.cpp | 156 | ||||
| -rw-r--r-- | src/asset-manager.cpp | 4 | ||||
| -rw-r--r-- | src/asset-manager.hpp | 2 | ||||
| -rw-r--r-- | src/components.hpp | 5 | ||||
| -rw-r--r-- | src/ecs.cpp | 2 | ||||
| -rw-r--r-- | src/entities.cpp | 72 | ||||
| -rw-r--r-- | src/font.cpp | 638 | ||||
| -rw-r--r-- | src/font.hpp | 74 | ||||
| -rw-r--r-- | src/static-plane.cpp | 21 | ||||
| -rw-r--r-- | src/static-plane.hpp | 15 | ||||
| -rw-r--r-- | src/window.cpp | 97 | ||||
| -rw-r--r-- | src/window.hpp | 24 |
18 files changed, 1098 insertions, 110 deletions
@@ -19,7 +19,7 @@ define cxx-dbg-command endef FLG_PKE = -Isub/imgui -Isub/stb -Isub/cgltf -Isub/bullet3/src -FLG_EDT = $(FLG_PKE) -Isrc +FLG_EDT = $(FLG_PKE) -Isrc -I/home/pikum/build/msdfgen -I/home/pikum/build/msdf-atlas-gen FLG_MPL = $(FLG_PKE) -Isrc FLG_RUN = $(FLG_PKE) -Isrc @@ -34,6 +34,7 @@ SRC = \ src/ecs.cpp \ src/entities.cpp \ src/event.cpp \ + src/font.cpp \ src/game.cpp \ src/game-settings.cpp \ src/helpers.cpp \ @@ -48,6 +49,7 @@ SRC = \ src/project.cpp \ src/project-settings.cpp \ src/static-cube.cpp \ + src/static-plane.cpp \ src/thread-pool.cpp \ src/vendor-cgltf-include.cpp \ src/vendor-stb-image-include.c \ @@ -59,6 +61,8 @@ DST_SHADERS = \ $(DIR_OBJ)/shaders/present.vert.spv \ $(DIR_OBJ)/shaders/texture.frag.spv \ $(DIR_OBJ)/shaders/present.frag.spv \ + $(DIR_OBJ)/shaders/glyph.vert.spv \ + $(DIR_OBJ)/shaders/glyph.frag.spv \ SRC_C = $(filter %.c,$(SRC)) SRC_CXX = $(filter %.cpp,$(SRC)) @@ -208,12 +212,12 @@ $(DIR_DBG)/libpke-example.a: $(DIR_OBJ)/example.so $(DIR_BIN)/pke-editor: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a $(DIR_BIN)/pke-editor: $(DIR_OBJ)/editor-main.o $(DIR_OBJ)/editor.o - $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ + $(CXX) -v -std=c++23 $(INCS) /home/pikum/build/msdfgen/dbg/msdfgen.a /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ $(DIR_DBG)/pke-editor: $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a $(DIR_DBG)/pke-editor: $(DIR_OBJ)/editor-main.so $(DIR_OBJ)/editor.so @echo $^ - $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ + $(CXX) -v -std=c++23 $(INCS) $^ /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a /home/pikum/build/msdfgen/dbg/msdfgen.a $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ $(DIR_BIN)/pke-runtime: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a $(DIR_BIN)/pke-runtime: $(DIR_OBJ)/runtime.o diff --git a/assets/shaders/glyph.frag b/assets/shaders/glyph.frag new file mode 100644 index 0000000..90186a3 --- /dev/null +++ b/assets/shaders/glyph.frag @@ -0,0 +1,24 @@ +# version 450 + +layout(location = 0) in vec4 in_fg_color; +layout(location = 1) in vec4 in_bg_color; +layout(location = 2) in vec4 in_sprite_region; +layout(location = 3) in vec2 in_uv; +layout(location = 4) in float in_width; + +layout(location = 0) out vec4 out_color; + +layout(binding = 1) uniform sampler2D mtsdfSampler; + +float median(float r, float g, float b) { + return max(min(r, g), min(max(r, g), b)); +} + +void main() { + vec2 atlas_coord = (in_uv - in_sprite_region.xy) / in_sprite_region.zw; + vec4 msd = texture(mtsdfSampler, atlas_coord); + float sd = median(msd.r, msd.g, msd.b); + float screenPxDistance = in_width * (sd - 0.5); + float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); + out_color = mix(in_bg_color, in_fg_color, opacity); +} diff --git a/assets/shaders/glyph.vert b/assets/shaders/glyph.vert new file mode 100644 index 0000000..52981c2 --- /dev/null +++ b/assets/shaders/glyph.vert @@ -0,0 +1,32 @@ +#version 450 + +// vertex +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_uv; + +// instance +layout(location = 2) in vec4 in_fg_color; +layout(location = 3) in vec4 in_bg_color; +layout(location = 4) in vec4 in_sprite_region; +layout(location = 5) in float in_width; + +layout(location = 0) out vec4 out_fg_color; +layout(location = 1) out vec4 out_bg_color; +layout(location = 2) out vec4 out_sprite_region; +layout(location = 3) out vec2 out_uv; +layout(location = 4) out float out_width; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + gl_Position = vec4(in_position, 0.0, 1.0); + out_fg_color = in_fg_color; + out_bg_color = in_bg_color; + out_sprite_region = in_sprite_region; + out_uv = in_uv; + out_width = in_width; +} diff --git a/assets/shaders/present.vert b/assets/shaders/present.vert index 5423fcf..a5d60d0 100644 --- a/assets/shaders/present.vert +++ b/assets/shaders/present.vert @@ -4,11 +4,11 @@ layout (location = 0) out vec2 outUV; out gl_PerVertex { - vec4 gl_Position; + vec4 gl_Position; }; void main() { - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); -}
\ No newline at end of file + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); +} diff --git a/assets/shaders/vertex.vert b/assets/shaders/vertex.vert index 57fa219..8b2c133 100644 --- a/assets/shaders/vertex.vert +++ b/assets/shaders/vertex.vert @@ -1,9 +1,9 @@ #version 450 layout(binding = 0) uniform UniformBufferObject { - mat4 model; - mat4 view; - mat4 proj; + mat4 model; + mat4 view; + mat4 proj; } ubo; // vertex @@ -20,12 +20,12 @@ layout(location = 0) out vec4 fragColor; layout(location = 1) out vec3 fragTexCoord; void main() { - gl_Position = - ubo.proj * - ubo.view * - ubo.model * - instPosRotScale * - vec4(inPosition, 1.0); - fragColor = vec4(0.0, 0.0, 0.0, 0.0); - fragTexCoord = vec3(inUV, 0); + gl_Position = + ubo.proj * + ubo.view * + ubo.model * + instPosRotScale * + vec4(inPosition, 1.0); + fragColor = vec4(0.0, 0.0, 0.0, 0.0); + fragTexCoord = vec3(inUV, 0); } @@ -15,6 +15,8 @@ USED_LIBS = \ vulkan \ glfw3 \ glm \ + freetype2 \ + libpng \ INCS = `$(PKG_CONFIG) --cflags $(USED_LIBS)` diff --git a/editor/editor.cpp b/editor/editor.cpp index a15c838..9f6b492 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -3,14 +3,20 @@ #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "array.hpp" +#include "asset-manager.hpp" #include "camera.hpp" #include "ecs.hpp" #include "entities.hpp" +#include "font.hpp" #include "game-settings.hpp" #include "game.hpp" #include "imgui.h" #include "level.hpp" #include "math-helpers.hpp" +#include "msdf-atlas-gen/GlyphGeometry.h" +#include "msdf-atlas-gen/glyph-generators.h" +#include "msdf-atlas-gen/image-save.h" +#include "msdf-atlas-gen/types.h" #include "player-input.hpp" #include "plugins.hpp" #include "project.hpp" @@ -19,11 +25,14 @@ #include "vendor-tinyfiledialogs.h" #include "window.hpp" #include "pk.h" +#include "msdf-atlas-gen/msdf-atlas-gen.h" #include <GLFW/glfw3.h> #include <compare> +#include <cstdio> #include <filesystem> #include <future> +#include <glm/fwd.hpp> #include <regex> #ifdef WIN32 @@ -230,7 +239,7 @@ void PkeEditor_Tick(double delta) { if (focusedInst != nullptr) { const auto *grBinds = ECS_GetGrBinds(focusedInst->grBindsHandle); if (grBinds != nullptr) { - pkeDebugHitbox.instanceBuffer = grBinds->instanceBuffer; + pkeDebugHitbox.instanceBuffer = grBinds->instanceBD.buffer; pkeDebugHitbox.instanceStartingIndex = focusedInst->index; found = true; } @@ -706,6 +715,140 @@ void RecordImGuiEntityTypes() { ImGui::End(); } +void GenerateMTSDF(const Asset *a) { + std::error_code e; + std::filesystem::create_directory("./cache", e); + if (msdfgen::FreetypeHandle *ft = msdfgen::initializeFreetype()) { + // Load font file + if (msdfgen::FontHandle *font = msdfgen::loadFont(ft, a->basePath)) { + // Storage for glyph geometry and their coordinates in the atlas + std::vector<msdf_atlas::GlyphGeometry> glyphs; + // FontGeometry is a helper class that loads a set of glyphs from a single font. + // It can also be used to get additional font metrics, kerning information, etc. + msdf_atlas::FontGeometry fontGeometry(&glyphs); + // Load a set of character glyphs: + // The second argument can be ignored unless you mix different font sizes in one atlas. + // In the last argument, you can specify a charset other than ASCII. + // To load specific glyph indices, use loadGlyphs instead. + fontGeometry.loadCharset(font, 1.0, msdf_atlas::Charset::ASCII); + // Apply MSDF edge coloring. See edge-coloring.h for other coloring strategies. + const double maxCornerAngle = 3.0; + for (msdf_atlas::GlyphGeometry &glyph : glyphs) + glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, maxCornerAngle, 0); + // TightAtlasPacker class computes the layout of the atlas. + msdf_atlas::TightAtlasPacker packer; + // Set atlas parameters: + // setDimensions or setDimensionsConstraint to find the best value + packer.setDimensionsConstraint(msdf_atlas::DimensionsConstraint::SQUARE); + // setScale for a fixed size or setMinimumScale to use the largest that fits + packer.setMinimumScale(24.0); + // setPixelRange or setUnitRange + packer.setPixelRange(2.0); + packer.setMiterLimit(1.0); + // Compute atlas layout - pack glyphs + packer.pack(glyphs.data(), glyphs.size()); + // Get final atlas dimensions + int width = 0, height = 0; + packer.getDimensions(width, height); + // The ImmediateAtlasGenerator class facilitates the generation of the atlas bitmap. + msdf_atlas::ImmediateAtlasGenerator< + float, // pixel type of buffer for individual glyphs depends on generator function + 4, // number of atlas color channels + &msdf_atlas::mtsdfGenerator, // function to generate bitmaps for individual glyphs + msdf_atlas::BitmapAtlasStorage<float, 4> // class that stores the atlas bitmap + // For example, a custom atlas storage class that stores it in VRAM can be used. + > generator(width, height); + // GeneratorAttributes can be modified to change the generator's default settings. + msdf_atlas::GeneratorAttributes attributes; + generator.setAttributes(attributes); + // generator.setThreadCount(4); + // Generate atlas bitmap + generator.generate(glyphs.data(), glyphs.size()); + // The atlas bitmap can now be retrieved via atlasStorage as a BitmapConstRef. + // The glyphs array (or fontGeometry) contains positioning data for typesetting text. + msdf_atlas::BitmapAtlasStorage<float, 4> storage = generator.atlasStorage(); + msdf_atlas::saveImage<4>(storage, msdf_atlas::ImageFormat::PNG, "cache/test-font.png", msdf_atlas::YDirection::TOP_DOWN); + + auto f = fopen("cache/test-font.glyphs", "w"); + pk_arr arr_glyphs = {}; + arr_glyphs.alignment = 8; + arr_glyphs.stride = sizeof(FontGlyphChar); + pk_arr_resize(&arr_glyphs, glyphs.size()); + FontGlyphChar *arr = reinterpret_cast<FontGlyphChar *>(arr_glyphs.data); + for (uint64_t i = 0; i < glyphs.size(); ++i) { + arr[i].unicode = glyphs[i].getCodepoint(); + glyphs[i].getBoxRect(arr[i].bounds.x, arr[i].bounds.y, arr[i].bounds.z, arr[i].bounds.a); + } + + fwrite(glyphs.data(), sizeof(msdf_atlas::GlyphGeometry) * glyphs.size(), 1, f); + fclose(f); + // _ = myProject::submitAtlasBitmapAndLayout(generator.atlasStorage(), glyphs); + // Cleanup + msdfgen::destroyFont(font); + } + msdfgen::deinitializeFreetype(ft); + } +} + +void RecordImGuiAssets() { + if (!ImGui::Begin("AssetList")) { + ImGui::End(); + return; + } + + static ImGuiTableFlags tableFlags{ + ImGuiTableFlags_Borders | + ImGuiTableFlags_RowBg + }; + if (ImGui::BeginTable("Assets", 7, tableFlags)) { + ImGui::TableSetupColumn("Controls"); + ImGui::TableSetupColumn("Type"); + ImGui::TableSetupColumn("Handle"); + ImGui::TableSetupColumn("Key"); + ImGui::TableSetupColumn("Data"); + ImGui::TableSetupColumn("Size"); + ImGui::TableSetupColumn("Ref Count"); + ImGui::TableHeadersRow(); + + pk_handle_bucket_index_T asset_bucket_count = AM_GetBucketCount(); + for (pk_handle_bucket_index_T b = 0; b < asset_bucket_count; ++b) { + pk_handle_item_index_T count; + auto *assets = AM_GetAssets(b, count); + ImGui::PushID(b); + for (pk_handle_item_index_T i = 0; i < count; ++i) { + const auto &asset = assets[i]; + if (asset.handle == EntityHandle_MAX) + continue; + ImGui::PushID(i); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + if ((asset.type & PKE_ASSET_TYPE_FONT) != PKE_ASSET_TYPE_UNSET) { + if (ImGui::Button("Create MTSDF")) { + GenerateMTSDF(&asset); + } + } + ImGui::TableSetColumnIndex(1); + ImGui::Text("%i", (uint8_t)asset.type); + ImGui::TableSetColumnIndex(2); + ImGui::Text("0x%08X 0x%08X", asset.handle.bucketIndex, asset.handle.itemIndex); + ImGui::TableSetColumnIndex(3); + ImGui::Text("%.16s", asset.key); + ImGui::TableSetColumnIndex(4); + ImGui::Text("%p", asset.ptr); + ImGui::TableSetColumnIndex(5); + ImGui::Text("%li", asset.size); + ImGui::TableSetColumnIndex(6); + ImGui::Text("%hhi", asset.referenceCount); + ImGui::PopID(); + } + ImGui::PopID(); + } + ImGui::EndTable(); + + } + ImGui::End(); +} + void RecordImGuiCameras() { CompInstance *activeInst = nullptr; // CompInstance *activeTargetInst = nullptr; @@ -1044,11 +1187,11 @@ void RecordImGui_CompGrBinds(bool readonly, CompGrBinds *component) { ImGui::InputScalar("IndexOffsets", ImGuiDataType_U64, &component->indexBD.offsets[0], nullptr, nullptr, nullptr, inputTextFlags); ImGui::InputScalar("IndexCount", ImGuiDataType_U32, &component->indexCount, nullptr, nullptr, nullptr, inputTextFlags); - if (component->instanceBuffer) - ImGui::InputScalar("VkInstanceBuffer", ImGuiDataType_U64, &component->instanceBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); - ImGui::InputScalar("InstanceFirstBinding", ImGuiDataType_U32, &component->instanceFirstBinding, nullptr, nullptr, nullptr, inputTextFlags); - ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBindingCount, nullptr, nullptr, nullptr, inputTextFlags); - ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceOffsets, nullptr, nullptr, nullptr, inputTextFlags); + if (component->instanceBD.buffer) + ImGui::InputScalar("VkInstanceBuffer", ImGuiDataType_U64, &component->instanceBD.buffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("InstanceFirstBinding", ImGuiDataType_U32, &component->instanceBD.firstBinding, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBD.bindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceBD.offsets[0], nullptr, nullptr, nullptr, inputTextFlags); ImGui::InputScalar("InstanceBufferMaxCount", ImGuiDataType_U32, &component->instanceBufferMaxCount, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); ImGui::InputScalar("Instance Count", ImGuiDataType_U32, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); @@ -1366,6 +1509,7 @@ void PkeEditor_RecordImGui() { RecordImGuiCameras(); RecordImGuiLevels(); RecordImGuiEntityTypes(); + RecordImGuiAssets(); Game_RecordImGui(); } } diff --git a/src/asset-manager.cpp b/src/asset-manager.cpp index b280361..d12d860 100644 --- a/src/asset-manager.cpp +++ b/src/asset-manager.cpp @@ -20,6 +20,8 @@ AssetKey EngineDefinedAssets[EngineDefinedAssetCount] = { "pke_prsnt_frg\0\0", "pke_txtr_vrt\0\0\0", "pke_txtr_frg\0\0\0", + "pke_glyph_vrt\0\0", + "pke_glyph_frg\0\0", }; void AM_Init() { @@ -29,6 +31,8 @@ void AM_Init() { AM_Register(EngineDefinedAssets[1], PKE_ASSET_TYPE_SHADER, "assets/shaders/present.frag.spv"); AM_Register(EngineDefinedAssets[2], PKE_ASSET_TYPE_SHADER, "assets/shaders/vertex.vert.spv"); AM_Register(EngineDefinedAssets[3], PKE_ASSET_TYPE_SHADER, "assets/shaders/texture.frag.spv"); + AM_Register(EngineDefinedAssets[4], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.vert.spv"); + AM_Register(EngineDefinedAssets[5], PKE_ASSET_TYPE_SHADER, "assets/shaders/glyph.frag.spv"); } void AM_Load_Task(Asset &asset) { diff --git a/src/asset-manager.hpp b/src/asset-manager.hpp index 0a7cd5c..fb922e9 100644 --- a/src/asset-manager.hpp +++ b/src/asset-manager.hpp @@ -29,7 +29,7 @@ const AssetType PKE_ASSET_TYPE_AUDIO = AssetType {0x08}; const AssetType PKE_ASSET_TYPE_FONT = AssetType {0x10}; const AssetType PKE_ASSET_TYPE_ALL = AssetType {0xFF}; -constexpr int64_t EngineDefinedAssetCount = 4; +constexpr int64_t EngineDefinedAssetCount = 6; extern AssetKey EngineDefinedAssets[EngineDefinedAssetCount]; struct Asset { diff --git a/src/components.hpp b/src/components.hpp index eb891a4..cf86099 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -42,17 +42,14 @@ struct CompGrBinds { BufferBindingDetails normalsBD; BufferBindingDetails uvBD; BufferBindingDetails indexBD; + BufferBindingDetails instanceBD; BufferBindingDetails physVertBD; BufferBindingDetails physNormBD; BufferBindingDetails physUvBD; BufferBindingDetails physIndxBD; - VkBuffer instanceBuffer = VK_NULL_HANDLE; uint32_t indexCount; - uint32_t instanceFirstBinding = 0; - uint32_t instanceBindingCount = 0; uint32_t instanceCounter = 0; uint32_t instanceBufferMaxCount = 0; - VkDeviceSize instanceOffsets = 0; PkeCallback collisionCallback{}; }; diff --git a/src/ecs.cpp b/src/ecs.cpp index 09eb725..c5f221a 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -336,7 +336,7 @@ void ECS_Tick_Late(double delta) { vkBeginCommandBuffer(transferCommandBuffer, &cbbi); for (long i = 0; i < ibc.chunks->Count(); ++i) { - vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBuffer, 1, &(*ibc.chunks)[i].dstBufferCopy); + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ibc.grBinds->instanceBD.buffer, 1, &(*ibc.chunks)[i].dstBufferCopy); } vkEndCommandBuffer(transferCommandBuffer); diff --git a/src/entities.cpp b/src/entities.cpp index 179ce4b..123c095 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -133,40 +133,6 @@ EntityType *EntityType_FindByEntityHandle(EntityHandle handle) { return nullptr; } -void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) { - combinedMemReqs.size = 0; - combinedMemReqs.alignment = memReqs[0].alignment; - combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits; - for (uint64_t i = 1; i < memReqsCount; ++i) { - combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits; - if (combinedMemReqs.alignment == memReqs[i].alignment) { - continue; - } - VkDeviceSize larger, smaller; - if (combinedMemReqs.alignment > memReqs[i].alignment) { - larger = combinedMemReqs.alignment; - smaller = memReqs[i].alignment; - } else { - larger = memReqs[i].alignment; - smaller = combinedMemReqs.alignment; - } - if (larger % smaller == 0) { - combinedMemReqs.alignment = larger; - continue; - } - int combined = larger * smaller; - while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) { - combined /= 2; - } - combinedMemReqs.alignment = combined; - } - for (uint64_t i = 0; i < memReqsCount; ++i) { - uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment; - memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); - combinedMemReqs.size += memReqs[i].size; - } -} - struct EntityTypeDetails_LoadHelperStruct { EntityTypeDetails *etd = nullptr; AssetHandle textureAssetHandle = AssetHandle_MAX; @@ -644,7 +610,7 @@ void EntityType_LoadTexture(EntityType_LoadHelperStruct &helper, const int64_t i VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { - descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture; + descriptorSets[i] = pkePipelines.descr_layouts.named.texture; } VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -773,8 +739,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh // 2023-09-27 - JCB // I don't know where else to put this - etdHelper.etd->grBinds->instanceFirstBinding = index; - etdHelper.etd->grBinds->instanceBindingCount = 1; + etdHelper.etd->grBinds->instanceBD.firstBinding = index; + etdHelper.etd->grBinds->instanceBD.bindingCount = 1; // no index += 1 because index just happens to be the right value here for // the binding index, whereas binding the IndexBuffer doesn't need a binding index. @@ -878,8 +844,8 @@ void EntityType_LoadMesh(EntityType_LoadHelperStruct &helper, const int64_t mesh etdHelper.etd->grBinds->instanceBufferMaxCount = etdHelper.etd->grBinds->instanceBufferMaxCount < 1 ? 1 : etdHelper.etd->grBinds->instanceBufferMaxCount; bufferCI.size = sizeof(glm::mat4) * etdHelper.etd->grBinds->instanceBufferMaxCount; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBuffer); - vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBuffer, helper.et.deviceMemoryInst, 0); + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &etdHelper.etd->grBinds->instanceBD.buffer); + vkBindBufferMemory(vkDevice, etdHelper.etd->grBinds->instanceBD.buffer, helper.et.deviceMemoryInst, 0); // bullet @@ -1094,8 +1060,8 @@ void EntityType_Load(EntityType &et) { * I don't like that we're just copying this. * This should be moved to window.cpp. */ - etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.vkPipelineLayout_Texture; - etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.Texture; + etdHelper.etd->grBinds->vkPipelineLayout = pkePipelines.pipe_layouts.named.texture; + etdHelper.etd->grBinds->graphicsPipeline = pkePipelines.pipelines.named.texture; // handle texture EntityType_LoadTexture(helper, i); @@ -1185,14 +1151,14 @@ void EntityType_Unload(EntityType &et, CompGrBinds *grBindsArr[1]) { grBinds->physIndxBD.bindingCount = 0; grBinds->physIndxBD.offsets[0] = 0; - if (grBinds->instanceBuffer != VK_NULL_HANDLE) - vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator); - grBinds->instanceBuffer = VK_NULL_HANDLE; - grBinds->instanceFirstBinding = 0; - grBinds->instanceBindingCount = 0; + if (grBinds->instanceBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, grBinds->instanceBD.buffer, vkAllocator); + grBinds->instanceBD.buffer = VK_NULL_HANDLE; + grBinds->instanceBD.firstBinding = 0; + grBinds->instanceBD.bindingCount = 0; grBinds->instanceCounter = 0; grBinds->instanceBufferMaxCount = 0; - grBinds->instanceOffsets = 0; + grBinds->instanceBD.offsets[0] = 0; } if (etd.textureImageView != VK_NULL_HANDLE) @@ -1277,7 +1243,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { uint32_t oldSize = sizeof(glm::mat4) * oldCount; VkDeviceMemory oldMemory(et.deviceMemoryInst); - VkBuffer oldBuffer(grBinds.instanceBuffer); + VkBuffer oldBuffer(grBinds.instanceBD.buffer); VkBufferCreateInfo vkBufferCreateInfo{}; vkBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -1288,10 +1254,10 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkBufferCreateInfo.queueFamilyIndexCount = 1; vkBufferCreateInfo.pQueueFamilyIndices = &graphicsFamilyIndex; - vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBuffer); + vkCreateBuffer(vkDevice, &vkBufferCreateInfo, vkAllocator, &grBinds.instanceBD.buffer); VkMemoryRequirements vkMemoryRequirementsInst; - vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); + vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBD.buffer, &vkMemoryRequirementsInst); VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; @@ -1300,7 +1266,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst); - vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0); + vkBindBufferMemory(vkDevice, grBinds.instanceBD.buffer, et.deviceMemoryInst, 0); // copy data { @@ -1323,7 +1289,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { memBarriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; memBarriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; memBarriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memBarriers[1].buffer = grBinds.instanceBuffer; + memBarriers[1].buffer = grBinds.instanceBD.buffer; memBarriers[1].offset = 0; memBarriers[1].size = vkMemoryRequirementsInst.size; @@ -1341,7 +1307,7 @@ void EntityType_RolloverInstances(EntityType &et, CompGrBinds &grBinds) { vkBufferCopy.srcOffset = 0; vkBufferCopy.dstOffset = 0; vkBufferCopy.size = oldSize; - vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBuffer, 1, &vkBufferCopy); + vkCmdCopyBuffer(graphicsCommandBuffer, oldBuffer, grBinds.instanceBD.buffer, 1, &vkBufferCopy); vkEndCommandBuffer(graphicsCommandBuffer); diff --git a/src/font.cpp b/src/font.cpp new file mode 100644 index 0000000..d218430 --- /dev/null +++ b/src/font.cpp @@ -0,0 +1,638 @@ + +#include "font.hpp" +#include "asset-manager.hpp" +#include "pk.h" +#include "window.hpp" +#include "static-plane.hpp" +#include "vendor-stb-image-include.h" +// #include "bucketed-array.hpp" + +// TODO threading + +TypeSafeInt_B(FontTypeIndex); +TypeSafeInt_B(FontRenderIndex); + +struct FontTypeData { + FontType *arr_ft; + FontTypeIndex n_ft{0}; + FontTypeIndex h_ft{0}; +} ftd; + +// BucketContainer<FontType, TextRenderHandle, 2> bktFont; + +void FontType_Init() { + ftd.h_ft = FontTypeIndex{5}; + ftd.arr_ft = pk_new<FontType>(5); +} + +void FontType_Teardown() { + FontTypeIndex i; + FontType *ft; + for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) { + FontType_Unload(i); + ft = &ftd.arr_ft[(FontTypeIndex_T)i]; + pk_delete<FontRender>(ft->renders, (FontTypeIndex_T)ft->n_render); + } + pk_delete(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft); +} + +FontType* FontType_GetFonts(FontTypeIndex &count) +{ + count = ftd.h_ft; + return ftd.arr_ft; +} + +FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle) { + VkResult vkResult; + pk_arr arr_vert_mem_reqs; + memset(&arr_vert_mem_reqs, 0, sizeof(pk_arr)); + arr_vert_mem_reqs.alignment = alignof(VkMemoryRequirements); + arr_vert_mem_reqs.stride = sizeof(VkMemoryRequirements); + pk_arr arr_inst_mem_reqs(arr_vert_mem_reqs); + pk_arr arr_texture_mem_reqs(arr_vert_mem_reqs); + VkDeviceSize index; + constexpr VkDeviceSize expectedBufferCount = 3; + constexpr VkDeviceSize startingGlyphCount = 4; + + VkMemoryRequirements combined_vert_mem_reqs; + VkMemoryRequirements combined_inst_mem_reqs; + VkMemoryRequirements combined_texture_mem_reqs; + + const Asset *fontTexture = AM_Get(fontTextureHandle); + const Asset *glyphs = AM_Get(glyphsHandle); + if (ftd.h_ft > ftd.n_ft) { + index = (VkDeviceSize)ftd.n_ft; + ftd.n_ft += FontTypeIndex{5}; + FontType *arr = pk_new<FontType>((FontTypeIndex_T)ftd.n_ft); + memcpy(arr, ftd.arr_ft, sizeof(FontType) * index); + pk_delete<FontType>(ftd.arr_ft, index); + ftd.arr_ft = arr; + } + + FontTypeIndex idx = ftd.h_ft++; + FontTypeIndex_T idx_t = (FontTypeIndex_T)idx; + FontType *ft = &ftd.arr_ft[idx_t]; + ft->title = title; + ft->fontTextureAssetKey = fontTextureHandle; + ft->glyphDetailsAssetKey = glyphsHandle; + ft->renders = pk_new<FontRender>(startingGlyphCount); + ft->n_render = FontRenderIndex{startingGlyphCount}; + + int txtr_x, txtr_y, txtr_chan; + stbi_uc *txtr_bytes = stbi_load_from_memory((unsigned char*)fontTexture->ptr, fontTexture->size, &txtr_x, &txtr_y, &txtr_chan, 4); + assert(txtr_chan == 4); + + /* + * vulkan setup + */ + VkBuffer buffer; + VkBufferCreateInfo bufferCI; + bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCI.pNext = nullptr; + bufferCI.flags = {}; + bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferCI.queueFamilyIndexCount = 1; + bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex; + + /* + * Vulkan resource setup + */ + // vertex + { + for (uint64_t index = 0; index < expectedBufferCount; ++index) { + if (index == 0) { + bufferCI.size = sizeof(glm::vec2) * 4; + } else if (index == 1) { + bufferCI.size = sizeof(glm::vec2) * 4; + } else if (index == 2) { + bufferCI.size = sizeof(uint16_t) * 6; + } + if (index == 2) { + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + } else { + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); + VkMemoryRequirements tmp; + vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp); + pk_arr_append(&arr_vert_mem_reqs, &tmp); + vkDestroyBuffer(vkDevice, buffer, vkAllocator); + } + } + // instance + { + bufferCI.size = 0; + bufferCI.size += sizeof(glm::vec4); // fgColor + bufferCI.size += sizeof(glm::vec4); // bgColor + bufferCI.size += sizeof(glm::vec4); // sprite_region + bufferCI.size += sizeof(float); // width + bufferCI.size *= startingGlyphCount; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &buffer); + VkMemoryRequirements tmp; + vkGetBufferMemoryRequirements(vkDevice, buffer, &tmp); + pk_arr_append(&arr_inst_mem_reqs, &tmp); + vkDestroyBuffer(vkDevice, buffer, vkAllocator); + } + // texture + VkImageCreateInfo imageCreateInfo{}; + VkImageSubresourceRange vkImageSubresourceRange; + { + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.pNext = nullptr; + imageCreateInfo.flags = 0; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R8G8B8A8_SRGB; + imageCreateInfo.extent.width = txtr_x; + imageCreateInfo.extent.height = txtr_y; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = renderSampleCount; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.queueFamilyIndexCount = 0; + imageCreateInfo.pQueueFamilyIndices = nullptr; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + vkImageSubresourceRange.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT; + vkImageSubresourceRange.baseMipLevel = 0u; + vkImageSubresourceRange.levelCount = 1u; + vkImageSubresourceRange.baseArrayLayer = 0u; + vkImageSubresourceRange.layerCount = 1u; + + VkImageViewCreateInfo vkImageViewCreateInfo; + vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vkImageViewCreateInfo.pNext = nullptr; + vkImageViewCreateInfo.flags = 0; + vkImageViewCreateInfo.image = ft->textureImage; + vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + vkImageViewCreateInfo.format = imageCreateInfo.format; + vkImageViewCreateInfo.components = VkComponentMapping { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }; + vkImageViewCreateInfo.subresourceRange = vkImageSubresourceRange; + + VkImage tmpImage; + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &tmpImage); + assert(vkResult == VK_SUCCESS); + + VkMemoryRequirements imageMemoryRequirements; + vkGetImageMemoryRequirements(vkDevice, tmpImage, &imageMemoryRequirements); + + VkDeviceSize paddedImageSize = imageMemoryRequirements.size + (imageMemoryRequirements.alignment - (imageMemoryRequirements.size % imageMemoryRequirements.alignment)); + assert(paddedImageSize % imageMemoryRequirements.alignment == 0); + + vkDestroyImage(vkDevice, tmpImage, vkAllocator); + + VkMemoryAllocateInfo vkMemoryAllocateInfo{}; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + vkMemoryAllocateInfo.allocationSize = paddedImageSize * MAX_FRAMES_IN_FLIGHT; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemoryRequirements.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkResult = vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture); + assert(vkResult == VK_SUCCESS); + + vkResult = vkCreateImage(vkDevice, &imageCreateInfo, vkAllocator, &ft->textureImage); + assert(vkResult == VK_SUCCESS); + vkResult = vkBindImageMemory(vkDevice, ft->textureImage, ft->deviceMemoryTexture, 0); + assert(vkResult == VK_SUCCESS); + + vkImageViewCreateInfo.image = ft->textureImage; + vkResult = vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &ft->textureImageView); + assert(vkResult == VK_SUCCESS); + } + + /* + * Vulkan memory allocation + */ + + VkMemoryAllocateInfo vkMemoryAllocateInfo; + vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vkMemoryAllocateInfo.pNext = nullptr; + + // verts + CalculateCombinedMemReqs(arr_vert_mem_reqs.next, (VkMemoryRequirements*)arr_vert_mem_reqs.data, combined_vert_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_vert_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_vert_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryVert); + + // inst + CalculateCombinedMemReqs(arr_inst_mem_reqs.next, (VkMemoryRequirements*)arr_inst_mem_reqs.data, combined_inst_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_inst_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_inst_mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryInst); + + // texture + CalculateCombinedMemReqs(arr_texture_mem_reqs.next, (VkMemoryRequirements*)arr_texture_mem_reqs.data, combined_texture_mem_reqs); + vkMemoryAllocateInfo.allocationSize = combined_texture_mem_reqs.size; + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + if (vkMemoryAllocateInfo.memoryTypeIndex == 0) { + vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combined_texture_mem_reqs.memoryTypeBits, 0); + } + vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &ft->deviceMemoryTexture); + + /* + * Vulkan data transfer + */ + VkBuffer transferBuffer; + VkDeviceMemory transferMemory; + void *deviceData; + VkDeviceSize runningOffset, alignmentPadding; + // vert + BeginTransferBuffer(combined_vert_mem_reqs.size, transferBuffer, transferMemory, deviceData); + { + index = 0; + runningOffset = 0; + + uint32_t offsetVert = runningOffset; + uint32_t sizeVert = sizeof(pkeIntrinsicsPlane.vert[0]) * 4; + ft->bindings.vertexBD.firstBinding = index; + ft->bindings.vertexBD.bindingCount = 1; + alignmentPadding = sizeVert % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeVert += alignmentPadding; + bufferCI.size = sizeVert; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.vertexBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.vertexBD.buffer, ft->deviceMemoryVert, offsetVert); + runningOffset += sizeVert; + index += 1; + + // uv + uint32_t offsetUV = runningOffset; + uint32_t sizeUV = sizeof(pkeIntrinsicsPlane.uv[0]) * 4; + ft->bindings.uvBD.firstBinding = index; + ft->bindings.uvBD.bindingCount = 1; + alignmentPadding = sizeUV % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeUV += alignmentPadding; + bufferCI.size = sizeUV; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.uvBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.uvBD.buffer, ft->deviceMemoryVert, offsetUV); + runningOffset += sizeUV; + index += 1; + + // 2023-09-27 - JCB + // I don't know where else to put this + ft->bindings.instanceBD.firstBinding = index; + ft->bindings.instanceBD.bindingCount = 1; + // no index += 1 because index just happens to be the right value here for + // the binding index, whereas binding the IndexBuffer doesn't need a binding index. + + // index + uint32_t offsetIndex = runningOffset; + uint32_t sizeIndex = sizeof(pkeIntrinsicsPlane.index[0]) * 6; + ft->bindings.indexBD.bindingCount = 1; + ft->bindings.indexCount = 6; + alignmentPadding = sizeIndex % combined_vert_mem_reqs.alignment; + alignmentPadding = alignmentPadding == 0 ? 0 : combined_vert_mem_reqs.alignment - alignmentPadding; + sizeIndex += alignmentPadding; + bufferCI.size = sizeIndex; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.indexBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.indexBD.buffer, ft->deviceMemoryVert, offsetIndex); + runningOffset += sizeIndex; + // index += 1; + + assert(runningOffset == combined_vert_mem_reqs.size); + + + runningOffset = 0; + + char *dstPtr = nullptr; + char *srcPtr = nullptr; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.vert); + memcpy(dstPtr, srcPtr, sizeVert); + runningOffset += sizeVert; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.uv); + memcpy(dstPtr, srcPtr, sizeUV); + runningOffset += sizeUV; + + dstPtr = static_cast<char *>(deviceData) + runningOffset; + srcPtr = reinterpret_cast<char *>(pkeIntrinsicsPlane.index); + memcpy(dstPtr, srcPtr, sizeIndex); + // runningOffset += sizeIndex; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + // TODO consider single-use? + vkCommandBufferBeginInfo.flags = 0; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); + VkBufferCopy bufferCopys[expectedBufferCount]; + for (VkDeviceSize i = 0; i < expectedBufferCount; ++i) { + bufferCopys[i].dstOffset = 0; + } + index = 0; + bufferCopys[index].srcOffset = offsetVert; + bufferCopys[index].size = sizeVert; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.vertexBD.buffer, 1, &bufferCopys[index]); + index+=1; + + bufferCopys[index].srcOffset = offsetUV; + bufferCopys[index].size = sizeUV; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.uvBD.buffer, 1, &bufferCopys[index]); + index+=1; + + bufferCopys[index].srcOffset = offsetIndex; + bufferCopys[index].size = sizeIndex; + vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, ft->bindings.indexBD.buffer, 1, &bufferCopys[index]); + // index+=1; + + vkEndCommandBuffer(transferCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transferCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(transferQueue); + } + EndTransferBuffer(transferBuffer, transferMemory); + // set up instance buffer + { + ft->bindings.instanceBufferMaxCount = startingGlyphCount; + bufferCI.size = combined_inst_mem_reqs.size; + bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &ft->bindings.instanceBD.buffer); + vkBindBufferMemory(vkDevice, ft->bindings.instanceBD.buffer, ft->deviceMemoryInst, 0); + } + // texture // transition image layout and copy to buffer + BeginTransferBuffer(combined_texture_mem_reqs.size, transferBuffer, transferMemory, deviceData); + memcpy(deviceData, txtr_bytes, combined_texture_mem_reqs.size); + { + VkImageMemoryBarrier vkImageMemoryBarrier; + vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + vkImageMemoryBarrier.pNext = nullptr; + vkImageMemoryBarrier.srcAccessMask = {}; + vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.image = ft->textureImage; + vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + // TODO MipMap + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(transferCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + VkBufferImageCopy vkBufferImageCopy; + vkBufferImageCopy.bufferOffset = 0; + vkBufferImageCopy.bufferRowLength = txtr_x; + vkBufferImageCopy.bufferImageHeight = txtr_y; + vkBufferImageCopy.imageSubresource = VkImageSubresourceLayers { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }; + vkBufferImageCopy.imageOffset = VkOffset3D { + .x = 0, + .y = 0, + .z = 0, + }; + vkBufferImageCopy.imageExtent = VkExtent3D { + .width = static_cast<uint32_t>(txtr_x), + .height = static_cast<uint32_t>(txtr_y), + .depth = 1, + }; + vkCmdCopyBufferToImage(transferCommandBuffer, transferBuffer, ft->textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkBufferImageCopy); + + vkEndCommandBuffer(transferCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &transferCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(transferQueue); + vkResetCommandBuffer(transferCommandBuffer, 0); + } + EndTransferBuffer(transferBuffer, transferMemory); + { + VkImageMemoryBarrier vkImageMemoryBarrier; + vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + vkImageMemoryBarrier.pNext = nullptr; + vkImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkImageMemoryBarrier.image = ft->textureImage; + vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + // TODO MipMap + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkCommandBufferBeginInfo vkCommandBufferBeginInfo; + vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkCommandBufferBeginInfo.pNext = nullptr; + vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo); + + vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); + + vkEndCommandBuffer(graphicsCommandBuffer); + + VkSubmitInfo submitInfo; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = nullptr; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &graphicsCommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr); + vkQueueWaitIdle(graphicsQueue); + } + + /* + * Vulkan descriptor sets + */ + VkDescriptorPoolSize descriptorPoolSizes[1]; + descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorPoolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; + + VkDescriptorPoolCreateInfo vkDescriptorPoolCreateInfo; + vkDescriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + vkDescriptorPoolCreateInfo.pNext = nullptr; + vkDescriptorPoolCreateInfo.flags = 0; + vkDescriptorPoolCreateInfo.maxSets = MAX_FRAMES_IN_FLIGHT; + vkDescriptorPoolCreateInfo.poolSizeCount = (uint32_t)1; + vkDescriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes; + + // consider making me a global pool + vkResult = vkCreateDescriptorPool(vkDevice, &vkDescriptorPoolCreateInfo, vkAllocator, &ft->vkDescriptorPool); + assert(vkResult == VK_SUCCESS); + + VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + descriptorSets[i] = pkePipelines.descr_layouts.named.glyph; + } + VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; + vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + vkDescriptorSetAllocateInfo.pNext = nullptr; + vkDescriptorSetAllocateInfo.descriptorPool = ft->vkDescriptorPool; + vkDescriptorSetAllocateInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; + vkDescriptorSetAllocateInfo.pSetLayouts = descriptorSets; + + ft->vkDescriptorSets = pk_new<VkDescriptorSet>(MAX_FRAMES_IN_FLIGHT); + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + ft->vkDescriptorSets[i] = VkDescriptorSet{}; + } + vkResult = vkAllocateDescriptorSets(vkDevice, &vkDescriptorSetAllocateInfo, ft->vkDescriptorSets); + assert(vkResult == VK_SUCCESS); + + VkWriteDescriptorSet writeDescriptorSets[1 * MAX_FRAMES_IN_FLIGHT]; + for (long i = 0; i < 1 * MAX_FRAMES_IN_FLIGHT; ++i) { + writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[i].pNext = nullptr; + writeDescriptorSets[i].dstSet = nullptr; + writeDescriptorSets[i].dstBinding = i; + writeDescriptorSets[i].dstArrayElement = 0; + writeDescriptorSets[i].descriptorCount = 1; + writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSets[i].pImageInfo = nullptr; + writeDescriptorSets[i].pBufferInfo = nullptr; + writeDescriptorSets[i].pTexelBufferView = nullptr; + } + + VkDescriptorImageInfo textureDescriptorInfo; + textureDescriptorInfo.sampler = pkePipelines.vkSampler_Texture; + textureDescriptorInfo.imageView = ft->textureImageView; + textureDescriptorInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + VkDescriptorBufferInfo vkDescriptorBufferInfo[MAX_FRAMES_IN_FLIGHT]; + + for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + vkDescriptorBufferInfo[i].buffer = UniformBuffers[i]; + vkDescriptorBufferInfo[i].offset = 0; + vkDescriptorBufferInfo[i].range = sizeof(UniformBufferObject); + + long uboIndex = i * 2; + long samplerIndex = uboIndex + 1; + + writeDescriptorSets[uboIndex].pBufferInfo = &vkDescriptorBufferInfo[i]; + writeDescriptorSets[uboIndex].dstSet = ft->vkDescriptorSets[i]; + + writeDescriptorSets[samplerIndex].pImageInfo = &textureDescriptorInfo; + writeDescriptorSets[samplerIndex].dstSet = ft->vkDescriptorSets[i]; + } + + vkUpdateDescriptorSets(vkDevice, 2 * MAX_FRAMES_IN_FLIGHT, writeDescriptorSets, 0, nullptr); + + return idx; +} + +void FontType_Unload(FontTypeIndex idx) +{ + FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx]; + + if (ft->vkDescriptorSets != VK_NULL_HANDLE && ft->vkDescriptorPool != VK_NULL_HANDLE) { + // 2023-09-27 - JCB (copied from entities.cpp) + // We are not setting the pool flag for allowing freeing descriptor sets + // so all we need to do is destroy the pool + // If we switch to a global pool, we will need to free here, and + // destroy the pool outside of this loop + vkDestroyDescriptorPool(vkDevice, ft->vkDescriptorPool, vkAllocator); + ft->vkDescriptorSets = CAFE_BABE(VkDescriptorSet); + ft->vkDescriptorPool = VK_NULL_HANDLE; + } + + if (ft->bindings.vertexBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.vertexBD.buffer, vkAllocator); + ft->bindings.vertexBD.buffer = VK_NULL_HANDLE; + ft->bindings.vertexBD.firstBinding = 0; + ft->bindings.vertexBD.bindingCount = 0; + ft->bindings.vertexBD.offsets[0] = 0; + + if (ft->bindings.uvBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.uvBD.buffer, vkAllocator); + ft->bindings.uvBD.buffer = VK_NULL_HANDLE; + ft->bindings.uvBD.firstBinding = 0; + ft->bindings.uvBD.bindingCount = 0; + ft->bindings.uvBD.offsets[0] = 0; + + if (ft->bindings.indexBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.indexBD.buffer, vkAllocator); + ft->bindings.indexBD.buffer = VK_NULL_HANDLE; + ft->bindings.indexBD.bindingCount = 0; + ft->bindings.indexBD.offsets[0] = 0; + ft->bindings.indexCount = 0; + + if (ft->bindings.instanceBD.buffer != VK_NULL_HANDLE) + vkDestroyBuffer(vkDevice, ft->bindings.instanceBD.buffer, vkAllocator); + ft->bindings.instanceBD.buffer = VK_NULL_HANDLE; + ft->bindings.instanceBD.firstBinding = 0; + ft->bindings.instanceBD.bindingCount = 0; + ft->bindings.instanceCounter = 0; + ft->bindings.instanceBufferMaxCount = 0; + ft->bindings.instanceBD.offsets[0] = 0; + + if (ft->textureImageView != VK_NULL_HANDLE) + vkDestroyImageView(vkDevice, ft->textureImageView, vkAllocator); + ft->textureImageView = VK_NULL_HANDLE; + + if (ft->textureImage != VK_NULL_HANDLE) + vkDestroyImage(vkDevice, ft->textureImage, vkAllocator); + ft->textureImage = VK_NULL_HANDLE; + + if (ft->deviceMemoryInst != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryInst, vkAllocator); + ft->deviceMemoryInst = VK_NULL_HANDLE; + + if (ft->deviceMemoryVert != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryVert, vkAllocator); + ft->deviceMemoryVert = VK_NULL_HANDLE; + + if (ft->deviceMemoryTexture != VK_NULL_HANDLE) + vkFreeMemory(vkDevice, ft->deviceMemoryTexture, vkAllocator); + ft->deviceMemoryTexture = VK_NULL_HANDLE; +} diff --git a/src/font.hpp b/src/font.hpp new file mode 100644 index 0000000..48a7b40 --- /dev/null +++ b/src/font.hpp @@ -0,0 +1,74 @@ +#ifndef PKE_FONT_TYPE_HPP +#define PKE_FONT_TYPE_HPP + +#include "asset-manager.hpp" +#include "components.hpp" +#include "pk.h" + +#include <glm/vec4.hpp> + +/* +Vert: (two triangles) +vec2 vertex +vec2 uv + +Inst: +vec4 fg_color +vec4 bg_color +vec4 sprite_region +float width + +Texture: +the MTSDF +*/ + +TypeSafeInt_H(FontTypeIndex, uint16_t, 0xFFFF); +TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF); + +struct FontGlyphChar { + uint32_t unicode; + glm::ivec4 bounds; +}; +struct FontRender { + uint32_t len; + FontTypeIndex index_ft; + FontRenderIndex index_fr; +}; +struct FontType : public Entity_Base { + pk_cstr title; + AssetHandle fontTextureAssetKey; + AssetHandle glyphDetailsAssetKey; + VkDeviceMemory deviceMemoryVert = VK_NULL_HANDLE; + VkDeviceMemory deviceMemoryTexture = VK_NULL_HANDLE; + VkDeviceMemory deviceMemoryInst = VK_NULL_HANDLE; + VkImage textureImage = VK_NULL_HANDLE; + VkImageView textureImageView = VK_NULL_HANDLE; + VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE; + VkDescriptorSet *vkDescriptorSets = nullptr; + FontRender *renders = nullptr; + FontRenderIndex n_render = FontRenderIndex{0}; + FontRenderIndex h_render = FontRenderIndex{0}; + FontTypeIndex index_ft = FontTypeIndex{0}; + struct FontTypeBindings { + BufferBindingDetails vertexBD; + BufferBindingDetails uvBD; + BufferBindingDetails indexBD; + BufferBindingDetails instanceBD; + uint32_t indexCount; + uint32_t instanceCounter = 0; + uint32_t instanceBufferMaxCount = 0; + } bindings; +}; + + +void FontType_Init(); +void FontType_Teardown(); +// void FontType_Serialize(FontType *ft); // TODO +// void FontType_Deserialize(FontType **ft); // TODO +FontType* FontType_GetFonts(FontTypeIndex &count); +FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetKey fontTexture, AssetKey glyphs); +void FontType_Unload(FontTypeIndex idx); +FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr); +void FontType_RemoveStringRender(FontRender fr); + +#endif /* PKE_FONT_TYPE_HPP */ diff --git a/src/static-plane.cpp b/src/static-plane.cpp new file mode 100644 index 0000000..d504b24 --- /dev/null +++ b/src/static-plane.cpp @@ -0,0 +1,21 @@ + +#include "static-plane.hpp" + +IntrinsicShapePlane pkeIntrinsicsPlane { + .vert = { + {-1, -1}, + { 1, -1}, + { 1, 1}, + {-1, 1}, + }, + .uv = { + {0,0}, + {1,0}, + {1,1}, + {0,1}, + }, + .index = { + 2, 1, 0, + 0, 3, 2, + }, +}; diff --git a/src/static-plane.hpp b/src/static-plane.hpp new file mode 100644 index 0000000..097a779 --- /dev/null +++ b/src/static-plane.hpp @@ -0,0 +1,15 @@ +#ifndef PKE_STATIC_PLANE_HPP +#define PKE_STATIC_PLANE_HPP + +#include <glm/ext/vector_float3.hpp> +#include <glm/ext/vector_float2.hpp> + +struct IntrinsicShapePlane { + glm::vec2 vert[4]; + glm::vec2 uv[4]; + uint16_t index[6]; +}; + +extern IntrinsicShapePlane pkeIntrinsicsPlane; + +#endif /* PKE_STATIC_PLANE_HPP */ diff --git a/src/window.cpp b/src/window.cpp index b83ef9a..a06895c 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,3 +1,4 @@ +#include "font.hpp" #define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN @@ -1562,18 +1563,23 @@ void CreateGraphicsPipelines() { .bindingCount = 2, .pBindings = vkDescriptorSetLayoutBindings, }; - vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.vkDescriptorSetLayout_Texture); + vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.texture); + + // no UBO on glyph + vkDescriptorSetLayoutBindings[0] = vkDescriptorSetLayoutBindings[1]; + vkDescriptorSetLayoutCreateInfo.bindingCount = 1; + vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &pkePipelines.descr_layouts.named.glyph); VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, - .setLayoutCount = 1, - .pSetLayouts = &pkePipelines.vkDescriptorSetLayout_Texture, + .setLayoutCount = 2, + .pSetLayouts = pkePipelines.descr_layouts.arr, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; - vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, &pkePipelines.vkPipelineLayout_Texture); + vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, pkePipelines.pipe_layouts.arr); VkSamplerCreateInfo vkSamplerCreateInfo; vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -1814,7 +1820,7 @@ void CreateGraphicsPipelines() { vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDynamicState = &vkPipelineDynamicStateCreateInfo; - vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.vkPipelineLayout_Texture; + vkGraphicsPipelineCreateInfo[i].layout = pkePipelines.pipe_layouts.named.texture; vkGraphicsPipelineCreateInfo[i].renderPass = renderRenderPass; vkGraphicsPipelineCreateInfo[i].subpass = 0; vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE; @@ -2259,7 +2265,7 @@ void UpdateDebugGraphicsPipeline() { VkDescriptorSetLayout descriptorSets[MAX_FRAMES_IN_FLIGHT]; for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { - descriptorSets[i] = pkePipelines.vkDescriptorSetLayout_Texture; + descriptorSets[i] = pkePipelines.descr_layouts.named.texture; } VkDescriptorSetAllocateInfo vkDescriptorSetAllocateInfo; vkDescriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -2414,7 +2420,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { throw "failed to begin recording command buffer"; } - // VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}}; + VkClearColorValue clearColorTransparent = {{0.0f, 0.0f, 0.0f, 0.0f}}; VkClearColorValue clearColorBlack = {{0.0f, 0.0f, 0.0f, 1.0f}}; VkClearDepthStencilValue clearDepth; clearDepth.depth = 1.0; @@ -2463,7 +2469,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { continue; if (!binder->vkPipelineLayout) continue; - if (binder->instanceBindingCount < 1) { + if (binder->instanceBD.bindingCount < 1) { continue; } vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, binder->graphicsPipeline); @@ -2474,13 +2480,13 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdBindVertexBuffers(commandBuffer, binder->vertexBD.firstBinding, binder->vertexBD.bindingCount, &binder->vertexBD.buffer, binder->vertexBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->normalsBD.firstBinding, binder->normalsBD.bindingCount, &binder->normalsBD.buffer, binder->normalsBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->uvBD.firstBinding, binder->uvBD.bindingCount, &binder->uvBD.buffer, binder->uvBD.offsets); - vkCmdBindVertexBuffers(commandBuffer, binder->instanceFirstBinding, binder->instanceBindingCount, &binder->instanceBuffer, &binder->instanceOffsets); + vkCmdBindVertexBuffers(commandBuffer, binder->instanceBD.firstBinding, binder->instanceBD.bindingCount, &binder->instanceBD.buffer, binder->instanceBD.offsets); vkCmdDrawIndexed(commandBuffer, binder->indexCount, binder->instanceCounter, 0, 0, 0); if (pkeSettings.isRenderingDebug) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); vkCmdBindVertexBuffers(commandBuffer, binder->physVertBD.firstBinding, 1, &binder->physVertBD.buffer, binder->physVertBD.offsets); vkCmdBindVertexBuffers(commandBuffer, binder->physNormBD.firstBinding, 1, &binder->physNormBD.buffer, binder->physVertBD.offsets); @@ -2493,8 +2499,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { } if (pkeDebugHitbox.instanceBuffer != VK_NULL_HANDLE) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.TextureWireframe); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.vkPipelineLayout_Texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.texture_wireframe); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.texture, 0, 1, &pkeDebugHitbox.vkDescriptorSets[imageIndex], 0, {}); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets); // TODO don't hardcode firstBinding @@ -2509,8 +2515,8 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdEndRenderPass(commandBuffer); - /* // 2d overlay pass + /* renderPassInfo.renderPass = d2OverlayRenderPass; renderPassInfo.framebuffer = d2OverlayImageFramebuffers[imageIndex]; renderPassInfo.clearValueCount = 1; @@ -2521,10 +2527,23 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); // TODO 2d overlay grbinds + FontTypeIndex count; + FontType *fts = FontType_GetFonts(count); + for (FontTypeIndex i = FontTypeIndex{0}; i < count; ++i) { + FontType *ft = &fts[(FontTypeIndex_T)i]; + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.glyph); - } + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipe_layouts.named.glyph, 0, 1, &ft->vkDescriptorSets[imageIndex], 0, {}); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &UniformBuffers[imageIndex], offsets); + vkCmdBindIndexBuffer(commandBuffer, ft->bindings.indexBD.buffer, ft->bindings.indexBD.offsets[0], VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.vertexBD.firstBinding, ft->bindings.vertexBD.bindingCount, &ft->bindings.vertexBD.buffer, ft->bindings.vertexBD.offsets); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.uvBD.firstBinding, ft->bindings.uvBD.bindingCount, &ft->bindings.uvBD.buffer, ft->bindings.uvBD.offsets); + vkCmdBindVertexBuffers(commandBuffer, ft->bindings.instanceBD.firstBinding, ft->bindings.instanceBD.bindingCount, &ft->bindings.instanceBD.buffer, ft->bindings.instanceBD.offsets); + + vkCmdDrawIndexed(commandBuffer, ft->bindings.indexCount, ft->bindings.instanceCounter, 0, 0, 0); + } vkCmdEndRenderPass(commandBuffer); */ @@ -2544,9 +2563,9 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { vkCmdDraw(commandBuffer, 3, 1, 0, 0); // ImGui - const auto count = LoadedPkePlugins.Count(); + const auto plugin_count = LoadedPkePlugins.Count(); bool any = false; - for (long i = 0; i < count; ++i) { + for (long i = 0; i < plugin_count; ++i) { if (LoadedPkePlugins[i].OnImGuiRender != nullptr) { any = true; break; @@ -2556,7 +2575,7 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) { ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - for (long i = 0; i < count; ++i) { + for (long i = 0; i < plugin_count; ++i) { if (LoadedPkePlugins[i].OnImGuiRender != nullptr) { LoadedPkePlugins[i].OnImGuiRender(); } @@ -2746,10 +2765,10 @@ void DestroyWindow() { if (pkePipelines.pipelines.arr[i] != VK_NULL_HANDLE) vkDestroyPipeline(vkDevice, pkePipelines.pipelines.arr[i], vkAllocator); } - if (pkePipelines.vkPipelineLayout_Texture != VK_NULL_HANDLE) - vkDestroyPipelineLayout(vkDevice, pkePipelines.vkPipelineLayout_Texture, vkAllocator); - if (pkePipelines.vkDescriptorSetLayout_Texture != VK_NULL_HANDLE) - vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.vkDescriptorSetLayout_Texture, vkAllocator); + if (pkePipelines.pipe_layouts.named.texture != VK_NULL_HANDLE) + vkDestroyPipelineLayout(vkDevice, pkePipelines.pipe_layouts.named.texture, vkAllocator); + if (pkePipelines.descr_layouts.named.texture != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vkDevice, pkePipelines.descr_layouts.named.texture, vkAllocator); for (long i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { vkDestroyBuffer(vkDevice, UniformBuffers[i], vkAllocator); @@ -2805,6 +2824,40 @@ VkShaderModule UploadShader(AssetHandle handle) { return vkShaderModule; } +void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs) { + combinedMemReqs.size = 0; + combinedMemReqs.alignment = memReqs[0].alignment; + combinedMemReqs.memoryTypeBits = memReqs[0].memoryTypeBits; + for (uint64_t i = 1; i < memReqsCount; ++i) { + combinedMemReqs.memoryTypeBits |= memReqs[i].memoryTypeBits; + if (combinedMemReqs.alignment == memReqs[i].alignment) { + continue; + } + VkDeviceSize larger, smaller; + if (combinedMemReqs.alignment > memReqs[i].alignment) { + larger = combinedMemReqs.alignment; + smaller = memReqs[i].alignment; + } else { + larger = memReqs[i].alignment; + smaller = combinedMemReqs.alignment; + } + if (larger % smaller == 0) { + combinedMemReqs.alignment = larger; + continue; + } + int combined = larger * smaller; + while ((combined / 2) % 2 == 0 && (combined / 2) % larger == 0) { + combined /= 2; + } + combinedMemReqs.alignment = combined; + } + for (uint64_t i = 0; i < memReqsCount; ++i) { + uint32_t alignmentPadding = memReqs[i].size % combinedMemReqs.alignment; + memReqs[i].size += (alignmentPadding == 0 ? 0 : combinedMemReqs.alignment - alignmentPadding); + combinedMemReqs.size += memReqs[i].size; + } +} + void Render() { vkWaitForFences(vkDevice, 1, &presentInFlightFences[CURRENT_FRAME], VK_TRUE, UINT64_MAX); diff --git a/src/window.hpp b/src/window.hpp index 35891c0..e6f422a 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -66,14 +66,27 @@ struct DebugHitbox { }; extern DebugHitbox pkeDebugHitbox; struct ImplementedPipelines { - VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE; - VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE; VkSampler vkSampler_Texture = VK_NULL_HANDLE; union { - VkPipeline arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + VkDescriptorSetLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + struct ImplementedPipelineLayoutsByName { + VkDescriptorSetLayout texture; + VkDescriptorSetLayout glyph; + } named; + } descr_layouts; + union { + VkPipelineLayout arr[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + struct ImplementedPipelineLayoutsByName { + VkPipelineLayout texture; + VkPipelineLayout glyph; + } named; + } pipe_layouts; + union { + VkPipeline arr[3] = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE }; struct ImplementedPipelinesByName { - VkPipeline Texture; - VkPipeline TextureWireframe; + VkPipeline texture; + VkPipeline texture_wireframe; + VkPipeline glyph; } named; } pipelines; }; @@ -85,6 +98,7 @@ VkShaderModule UploadShader(AssetHandle handle); void Render(); unsigned int FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags memPropertyFlags); +void CalculateCombinedMemReqs(uint64_t memReqsCount, VkMemoryRequirements *memReqs, VkMemoryRequirements &combinedMemReqs); void BeginTransferBuffer(VkDeviceSize requestedMemorySize, VkBuffer &buffer, VkDeviceMemory &deviceMemory, void *&deviceData); void EndTransferBuffer(VkBuffer &buffer, VkDeviceMemory &deviceMemory); |
