2026-04-05 22:53:59 +02:00
|
|
|
/*
|
|
|
|
|
Crafter®.Graphics
|
|
|
|
|
Copyright (C) 2026 Catcrafts®
|
|
|
|
|
catcrafts.net
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
License version 3.0 as published by the Free Software Foundation;
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
module;
|
|
|
|
|
#include "../lib/stb_truetype.h"
|
2026-04-09 00:15:09 +02:00
|
|
|
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
|
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
|
#endif
|
2026-04-05 22:53:59 +02:00
|
|
|
export module Crafter.Graphics:RenderingElement2DVulkan;
|
2026-04-09 00:15:09 +02:00
|
|
|
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
|
2026-04-05 22:53:59 +02:00
|
|
|
import Crafter.Asset;
|
|
|
|
|
import std;
|
|
|
|
|
import :Transform2D;
|
2026-04-09 00:15:09 +02:00
|
|
|
import :VulkanBuffer;
|
2026-04-05 22:53:59 +02:00
|
|
|
import :Types;
|
|
|
|
|
import :Window;
|
2026-04-10 22:26:15 +02:00
|
|
|
import :DescriptorHeapVulkan;
|
2026-04-05 22:53:59 +02:00
|
|
|
|
|
|
|
|
export namespace Crafter {
|
|
|
|
|
struct __attribute__((packed)) RenderingElement2DVulkanTransformInfo {
|
|
|
|
|
ScaleData2D scaled; // 0 - 8 bytes
|
|
|
|
|
std::uint16_t bufferX; // 8 - 2 bytes
|
|
|
|
|
std::uint16_t bufferY; // 10 - 2 bytes
|
|
|
|
|
//12 bytes total;
|
2026-04-09 00:15:09 +02:00
|
|
|
};
|
2026-04-05 22:53:59 +02:00
|
|
|
|
2026-04-09 00:15:09 +02:00
|
|
|
struct RenderingElement2DVulkanBase : Transform2D {
|
|
|
|
|
std::uint16_t index;
|
|
|
|
|
std::uint16_t bufferX;
|
|
|
|
|
std::uint16_t bufferY;
|
2026-04-10 22:26:15 +02:00
|
|
|
std::array<VulkanBufferBase*, Window::numFrames> buffers;
|
2026-04-10 22:57:53 +02:00
|
|
|
RenderingElement2DVulkanBase(Anchor2D anchor) : Transform2D(anchor) {
|
|
|
|
|
|
|
|
|
|
}
|
2026-04-09 00:15:09 +02:00
|
|
|
RenderingElement2DVulkanBase(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) : bufferX(bufferX), bufferY(bufferY), Transform2D(anchor) {
|
|
|
|
|
|
2026-04-10 22:26:15 +02:00
|
|
|
}
|
|
|
|
|
RenderingElement2DVulkanBase(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY, std::array<VulkanBufferBase*, Window::numFrames>&& buffers) : bufferX(bufferX), bufferY(bufferY), buffers(std::move(buffers)), Transform2D(anchor) {
|
|
|
|
|
|
2026-04-09 00:15:09 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::vector<RenderingElement2DVulkanBase*> renderingElement2DVulkans;
|
2026-04-10 22:26:15 +02:00
|
|
|
VulkanBuffer<RenderingElement2DVulkanTransformInfo, true> renderingElement2DVulkanTransformBuffer[Window::numFrames];
|
2026-04-05 22:53:59 +02:00
|
|
|
|
|
|
|
|
template<bool Owning, bool Mapped>
|
2026-04-09 00:15:09 +02:00
|
|
|
struct RenderingElement2DVulkan : RenderingElement2DVulkanBase {
|
2026-04-10 22:57:53 +02:00
|
|
|
RenderingElement2DVulkan(Anchor2D anchor, RendertargetBase<Window::numFrames>& target, Transform2D& parent) requires(Owning) : RenderingElement2DVulkanBase(anchor) {
|
|
|
|
|
renderingElement2DVulkans.push_back(this);
|
|
|
|
|
UpdatePosition(target, parent);
|
|
|
|
|
this->bufferX = this->scaled.size.x;
|
|
|
|
|
this->bufferY = this->scaled.size.y;
|
|
|
|
|
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
|
|
|
|
|
buffers[i] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>();
|
2026-04-11 13:54:17 +02:00
|
|
|
static_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffers[i])->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY);
|
2026-04-10 22:57:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-11 13:54:17 +02:00
|
|
|
|
2026-04-09 00:15:09 +02:00
|
|
|
RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) requires(Owning) : RenderingElement2DVulkanBase(anchor, bufferX, bufferY) {
|
2026-04-05 22:53:59 +02:00
|
|
|
renderingElement2DVulkans.push_back(this);
|
2026-04-09 00:15:09 +02:00
|
|
|
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
|
2026-04-10 22:26:15 +02:00
|
|
|
buffers[i] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>();
|
2026-04-11 13:54:17 +02:00
|
|
|
static_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffers[i])->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY);
|
2026-04-09 00:15:09 +02:00
|
|
|
}
|
2026-04-05 22:53:59 +02:00
|
|
|
}
|
2026-04-11 13:54:17 +02:00
|
|
|
|
2026-04-10 22:26:15 +02:00
|
|
|
RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY, std::array<VulkanBufferBase*, Window::numFrames>&& buffers) requires(!Owning) : RenderingElement2DVulkanBase(anchor, bufferX, bufferY, std::move(buffers)) {
|
2026-04-05 22:53:59 +02:00
|
|
|
renderingElement2DVulkans.push_back(this);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 13:54:17 +02:00
|
|
|
RenderingElement2DVulkan(Anchor2D anchor, const std::filesystem::path& assetPath, bool single) requires(Owning && Mapped) : RenderingElement2DVulkanBase(anchor) {
|
|
|
|
|
TextureAssetInfo info = TextureAsset<_Float16>::LoadInfo(assetPath);
|
|
|
|
|
this->bufferX = info.sizeX;
|
|
|
|
|
this->bufferY = info.sizeY;
|
|
|
|
|
if(single) {
|
|
|
|
|
buffers[0] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>();
|
|
|
|
|
static_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffers[0])->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY);
|
|
|
|
|
for(std::uint8_t i = 1; i < Window::numFrames; i++) {
|
|
|
|
|
buffers[i] = buffers[0];
|
|
|
|
|
}
|
|
|
|
|
TextureAsset<_Float16>::LoadInfo(assetPath, buffers[0].value, this->bufferX, this->bufferY);
|
|
|
|
|
} else {
|
|
|
|
|
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
|
|
|
|
|
buffers[i] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>();
|
|
|
|
|
static_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffers[i])->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY);
|
|
|
|
|
}
|
|
|
|
|
TextureAsset<_Float16>::LoadInfo(assetPath, buffers[0].value, this->bufferX, this->bufferY);
|
|
|
|
|
for(std::uint8_t i = 1; i < Window::numFrames; i++) {
|
|
|
|
|
std::memcpy(buffers[i].value, buffers[0].value, this->bufferX * this->bufferY * sizeof(_Float16));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 22:53:59 +02:00
|
|
|
~RenderingElement2DVulkan() {
|
|
|
|
|
if constexpr(Owning) {
|
2026-04-10 22:26:15 +02:00
|
|
|
for(VulkanBufferBase* buffer : buffers) {
|
2026-04-11 13:54:17 +02:00
|
|
|
delete static_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffer);
|
2026-04-05 22:53:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-09 00:15:09 +02:00
|
|
|
auto it = std::find(renderingElement2DVulkans.begin(), renderingElement2DVulkans.end(), this);
|
|
|
|
|
if (it != renderingElement2DVulkans.end()) {
|
|
|
|
|
renderingElement2DVulkans.erase(it);
|
|
|
|
|
}
|
2026-04-05 22:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RenderingElement2DVulkan(RenderingElement2DVulkan&) = delete;
|
|
|
|
|
RenderingElement2DVulkan& operator=(RenderingElement2DVulkan&) = delete;
|
|
|
|
|
|
2026-04-09 00:15:09 +02:00
|
|
|
void UpdatePosition(RendertargetBase<Window::numFrames>& window, Transform2D& parent) override {
|
2026-04-05 22:53:59 +02:00
|
|
|
this->ScaleElement(parent);
|
2026-04-09 00:15:09 +02:00
|
|
|
RenderingElement2DVulkanTransformInfo* val = reinterpret_cast<RenderingElement2DVulkanTransformInfo*>(reinterpret_cast<char*>(renderingElement2DVulkanTransformBuffer[window.frame].value) + sizeof(RenderingElement2DVulkanTransformInfo));
|
|
|
|
|
val[index].scaled = this->scaled;
|
2026-04-05 22:53:59 +02:00
|
|
|
for(Transform2D* child : this->children) {
|
|
|
|
|
child->UpdatePosition(window, *this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-10 22:26:15 +02:00
|
|
|
void WriteRenderingElement2DVulkanDescriptors(std::span<VkResourceDescriptorInfoEXT> infos, std::span<VkHostAddressRangeEXT> ranges, std::uint16_t start, std::uint32_t bufferOffset, DescriptorHeapVulkan& descriptorHeap) {
|
|
|
|
|
VkDeviceAddressRangeKHR transformRanges[Window::numFrames] = {
|
|
|
|
|
{
|
|
|
|
|
.address = renderingElement2DVulkanTransformBuffer[0].address,
|
|
|
|
|
.size = renderingElement2DVulkanTransformBuffer[0].size
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.address = renderingElement2DVulkanTransformBuffer[1].address,
|
|
|
|
|
.size = renderingElement2DVulkanTransformBuffer[1].size
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.address = renderingElement2DVulkanTransformBuffer[2].address,
|
|
|
|
|
.size = renderingElement2DVulkanTransformBuffer[2].size
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
|
|
|
|
|
ranges[start + i] = {
|
|
|
|
|
.address = descriptorHeap.resourceHeap[i].value + bufferOffset,
|
|
|
|
|
.size = Device::descriptorHeapProperties.bufferDescriptorSize
|
|
|
|
|
};
|
|
|
|
|
infos[start + i] = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
|
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
|
.data = { .pAddressRange = &transformRanges[i]}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start += 3;
|
|
|
|
|
bufferOffset += Device::descriptorHeapProperties.bufferDescriptorSize;
|
|
|
|
|
|
|
|
|
|
std::vector<VkDeviceAddressRangeKHR> bufferRanges(renderingElement2DVulkans.size() * Window::numFrames);
|
|
|
|
|
|
|
|
|
|
std::uint16_t rangeOffset = 0;
|
|
|
|
|
|
|
|
|
|
for(std::uint8_t i2 = 0; i2 < Window::numFrames; i2++) {
|
|
|
|
|
for(std::uint16_t i = 0; i < renderingElement2DVulkans.size(); i++) {
|
|
|
|
|
ranges[start + i] = {
|
|
|
|
|
.address = descriptorHeap.resourceHeap[i2].value + bufferOffset + Device::descriptorHeapProperties.bufferDescriptorSize * i,
|
|
|
|
|
.size = Device::descriptorHeapProperties.bufferDescriptorSize
|
|
|
|
|
};
|
|
|
|
|
infos[start + i] = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
|
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
|
.data = { .pAddressRange = &bufferRanges[i]}
|
|
|
|
|
};
|
|
|
|
|
bufferRanges[rangeOffset + i] = {
|
|
|
|
|
.address = renderingElement2DVulkans[i]->buffers[i2]->address,
|
|
|
|
|
.size = renderingElement2DVulkans[i]->buffers[i2]->size
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
start += renderingElement2DVulkans.size();
|
|
|
|
|
rangeOffset += renderingElement2DVulkans.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Device::vkWriteResourceDescriptorsEXT(Device::device, start, infos.data(), ranges.data());
|
|
|
|
|
|
|
|
|
|
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
|
|
|
|
|
descriptorHeap.resourceHeap[i].FlushDevice();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 00:15:09 +02:00
|
|
|
void InitializeRenderingElement2DVulkanBuffer() {
|
|
|
|
|
for(std::uint8_t frame = 0; frame < Window::numFrames; frame++) {
|
|
|
|
|
renderingElement2DVulkanTransformBuffer[frame].Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, renderingElement2DVulkans.size()+1);
|
|
|
|
|
RenderingElement2DVulkanTransformInfo* val = reinterpret_cast<RenderingElement2DVulkanTransformInfo*>(reinterpret_cast<char*>(renderingElement2DVulkanTransformBuffer[frame].value) + sizeof(RenderingElement2DVulkanTransformInfo));
|
|
|
|
|
std::uint16_t* sizePtr = reinterpret_cast<std::uint16_t*>(renderingElement2DVulkanTransformBuffer[frame].value);
|
|
|
|
|
*sizePtr = renderingElement2DVulkans.size();
|
|
|
|
|
for(std::uint16_t i = 0; i < renderingElement2DVulkans.size(); i++) {
|
|
|
|
|
val[i].scaled = renderingElement2DVulkans[i]->scaled;
|
|
|
|
|
val[i].bufferX = renderingElement2DVulkans[i]->bufferX;
|
|
|
|
|
val[i].bufferY = renderingElement2DVulkans[i]->bufferY;
|
|
|
|
|
renderingElement2DVulkans[i]->index = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdateRenderingElement2DVulkanBuffer(std::uint8_t frame) {
|
|
|
|
|
renderingElement2DVulkanTransformBuffer[frame].Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, renderingElement2DVulkans.size()+1);
|
|
|
|
|
RenderingElement2DVulkanTransformInfo* val = reinterpret_cast<RenderingElement2DVulkanTransformInfo*>(reinterpret_cast<char*>(renderingElement2DVulkanTransformBuffer[frame].value) + sizeof(RenderingElement2DVulkanTransformInfo));
|
|
|
|
|
std::uint16_t* sizePtr = reinterpret_cast<std::uint16_t*>(renderingElement2DVulkanTransformBuffer[frame].value);
|
|
|
|
|
*sizePtr = renderingElement2DVulkans.size();
|
|
|
|
|
for(std::uint16_t i = 0; i < renderingElement2DVulkans.size(); i++) {
|
|
|
|
|
val[i].scaled = renderingElement2DVulkans[i]->scaled;
|
|
|
|
|
val[i].bufferX = renderingElement2DVulkans[i]->bufferX;
|
|
|
|
|
val[i].bufferY = renderingElement2DVulkans[i]->bufferY;
|
|
|
|
|
renderingElement2DVulkans[i]->index = i + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|