/* 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; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN #include #endif module Crafter.Graphics:Rendertarget_impl; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN import :Rendertarget; import :Window; import :DescriptorHeapVulkan; import :RenderingElement2DVulkan; import std; using namespace Crafter; RendertargetVulkan::RendertargetVulkan(std::uint16_t sizeX, std::uint16_t sizeY, std::vector&& elementss) : RendertargetBase(sizeX, sizeY), elements(std::move(elementss)) { for(Transform2D* child : transform.children) { SetOrderResursive(child); } for(std::uint8_t frame = 0; frame < Window::numFrames; frame++) { transformBuffer[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, elements.size()+1); RenderingElement2DVulkanTransformInfo* val = reinterpret_cast(reinterpret_cast(transformBuffer[frame].value) + sizeof(RenderingElement2DVulkanTransformInfo)); std::uint16_t* sizePtr = reinterpret_cast(transformBuffer[frame].value); *sizePtr = static_cast(elements.size()); for(std::uint16_t i = 0; i < elements.size(); i++) { elements[i]->ScaleElement(transform); val[i].scaled = elements[i]->scaled; val[i].bufferX = elements[i]->bufferX; val[i].bufferY = elements[i]->bufferY; } transformBuffer[frame].FlushDevice(); } } RendertargetVulkan::RendertargetVulkan(std::uint16_t sizeX, std::uint16_t sizeY) : RendertargetBase(sizeX, sizeY) { } void RendertargetVulkan::UpdateBuffer(std::uint8_t frame) { elements.clear(); for(Transform2D* child : transform.children) { SetOrderResursive(child); } transformBuffer[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, elements.size()+1); RenderingElement2DVulkanTransformInfo* val = reinterpret_cast(reinterpret_cast(transformBuffer[frame].value) + sizeof(RenderingElement2DVulkanTransformInfo)); std::uint16_t* sizePtr = reinterpret_cast(transformBuffer[frame].value); *sizePtr = static_cast(elements.size()); for(std::uint16_t i = 0; i < elements.size(); i++) { elements[i]->ScaleElement(transform); val[i].scaled = elements[i]->scaled; val[i].bufferX = elements[i]->bufferX; val[i].bufferY = elements[i]->bufferY; } transformBuffer[frame].FlushDevice(); } void RendertargetVulkan::ReorderBuffer(std::uint8_t frame) { RenderingElement2DVulkanTransformInfo* val = reinterpret_cast(reinterpret_cast(transformBuffer[frame].value) + sizeof(RenderingElement2DVulkanTransformInfo)); elements.clear(); for(Transform2D* child : transform.children) { SetOrderResursive(child); } for(std::uint16_t i = 0; i < elements.size(); i++) { val[i].scaled = elements[i]->scaled; val[i].bufferX = elements[i]->bufferX; val[i].bufferY = elements[i]->bufferY; } } void RendertargetVulkan::WriteDescriptors(std::span infos, std::span ranges, std::uint16_t start, std::uint32_t bufferOffset, DescriptorHeapVulkan& descriptorHeap) { VkDeviceAddressRangeKHR transformRanges[Window::numFrames] = { { .address = transformBuffer[0].address, .size = transformBuffer[0].size }, { .address = transformBuffer[1].address, .size = transformBuffer[1].size }, { .address = transformBuffer[2].address, .size = transformBuffer[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 bufferRanges(elements.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 < elements.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 = elements[i]->buffers[i2]->address, .size = elements[i]->buffers[i2]->size }; } start += elements.size(); rangeOffset += elements.size(); } Device::vkWriteResourceDescriptorsEXT(Device::device, start, infos.data(), ranges.data()); for(std::uint8_t i = 0; i < Window::numFrames; i++) { descriptorHeap.resourceHeap[i].FlushDevice(); } } void RendertargetVulkan::SetOrderResursive(Transform2D* elementTransform) { std::sort(elementTransform->children.begin(), elementTransform->children.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; }); for(Transform2D* childTransform : elementTransform->children) { RenderingElement2DVulkanBase* renderer = dynamic_cast(childTransform); if(renderer) { renderer->index = elements.size(); elements.push_back(renderer); } SetOrderResursive(childTransform); } } #endif