From 984277af90ed35dab441ee49b34a1b8d4b1d1838 Mon Sep 17 00:00:00 2001 From: Thomas Choquet Date: Fri, 27 Feb 2026 08:28:21 +0900 Subject: [PATCH] add getter for swapchain image descriptor improve drawable and image handling for metal swapchain --- include/Graphics/Swapchain.hpp | 6 ++--- src/Metal/MetalDrawable.hpp | 11 ++++++--- src/Metal/MetalDrawable.mm | 24 +++++++++---------- src/Metal/MetalSwapchain.hpp | 13 ++++++----- src/Metal/MetalSwapchain.mm | 42 +++++++++++++++++++++++----------- src/Metal/MetalTexture.hpp | 3 ++- src/Metal/MetalTexture.mm | 17 +++++++++----- src/Vulkan/VulkanSwapchain.cpp | 20 ++++++++-------- src/Vulkan/VulkanSwapchain.hpp | 7 ++---- 9 files changed, 84 insertions(+), 59 deletions(-) diff --git a/include/Graphics/Swapchain.hpp b/include/Graphics/Swapchain.hpp index 30be572..7edfb78 100644 --- a/include/Graphics/Swapchain.hpp +++ b/include/Graphics/Swapchain.hpp @@ -13,6 +13,7 @@ #include "Graphics/Surface.hpp" #include "Graphics/Enums.hpp" #include "Graphics/Drawable.hpp" +#include "Graphics/Texture.hpp" #include #include @@ -38,9 +39,8 @@ class Swapchain Swapchain(const Swapchain&) = delete; Swapchain(Swapchain&&) = delete; - virtual uint32_t width() const = 0; - virtual uint32_t height() const = 0; - virtual PixelFormat pixelFormat() const = 0; + // descriptor used to create textures for drawables + virtual const Texture::Descriptor& drawablesTextureDescriptor() const = 0; virtual std::shared_ptr nextDrawable() = 0; diff --git a/src/Metal/MetalDrawable.hpp b/src/Metal/MetalDrawable.hpp index 4ff2b77..a0ced31 100644 --- a/src/Metal/MetalDrawable.hpp +++ b/src/Metal/MetalDrawable.hpp @@ -11,6 +11,9 @@ #define METALDRAWABLE_HPP #include "Graphics/Drawable.hpp" +#include "Metal/MetalTexture.hpp" + +#include #if !defined(__OBJC__) #error this file can only by used in objective c @@ -28,16 +31,18 @@ class MetalDrawable : public Drawable MetalDrawable(const MetalDrawable&) = delete; MetalDrawable(MetalDrawable&&) = delete; - MetalDrawable(id); + MetalDrawable(const Texture::Descriptor&); std::shared_ptr texture() const override; - id mtlDrawable() const { return m_mtlDrawable; } + inline id mtlDrawable() const { return m_mtlDrawable; } + void setMtlDrawable(const id& d); ~MetalDrawable() override = default; private: - id m_mtlDrawable; + id m_mtlDrawable = nil; + std::shared_ptr m_texture = nullptr; public: MetalDrawable& operator=(const MetalDrawable&) = delete; diff --git a/src/Metal/MetalDrawable.mm b/src/Metal/MetalDrawable.mm index ef622e4..7054829 100644 --- a/src/Metal/MetalDrawable.mm +++ b/src/Metal/MetalDrawable.mm @@ -14,26 +14,26 @@ #include "Metal/MetalEnums.hpp" #include "Metal/MetalTexture.hpp" +#include + namespace gfx { -MetalDrawable::MetalDrawable(id mtlDrawable) - : m_mtlDrawable(mtlDrawable) +MetalDrawable::MetalDrawable(const Texture::Descriptor& textureDescriptor) + : m_texture(std::make_shared(textureDescriptor)) { } std::shared_ptr MetalDrawable::texture() const { @autoreleasepool { - id mtlTexture = m_mtlDrawable.texture; - Texture::Descriptor desc = { - .type = TextureType::texture2d, - .width = static_cast(mtlTexture.width), - .height = static_cast(mtlTexture.height), - .pixelFormat = toPixelFormat(mtlTexture.pixelFormat), - .usages = TextureUsage::colorAttachment, - .storageMode = ResourceStorageMode::deviceLocal - }; - return std::make_shared(m_mtlDrawable.texture, desc); + m_texture->setMtlTexture(m_mtlDrawable.texture); + return m_texture; }} +void MetalDrawable::setMtlDrawable(const id& drawable) +{ + m_mtlDrawable = drawable; + m_texture->setMtlTexture(nil); +} + } diff --git a/src/Metal/MetalSwapchain.hpp b/src/Metal/MetalSwapchain.hpp index 25e241d..e8d69f6 100644 --- a/src/Metal/MetalSwapchain.hpp +++ b/src/Metal/MetalSwapchain.hpp @@ -12,6 +12,8 @@ #include "Graphics/Swapchain.hpp" #include "Graphics/Drawable.hpp" +#include "Metal/MetalDrawable.hpp" +#include "Metal/MetalTexture.hpp" #if !defined(__OBJC__) #error this file can only by used in objective c @@ -30,19 +32,18 @@ class MetalSwapchain : public Swapchain MetalSwapchain(const MetalDevice&, const Swapchain::Descriptor&); - inline uint32_t width() const override { return m_width; } - inline uint32_t height() const override { return m_height; } - inline PixelFormat pixelFormat() const override { return m_pixelFormat; }; + inline const Texture::Descriptor& drawablesTextureDescriptor() const override { return m_swapchainImagesDescriptor; } std::shared_ptr nextDrawable() override; ~MetalSwapchain() override = default; private: - uint32_t m_width; - uint32_t m_height; + Texture::Descriptor m_swapchainImagesDescriptor; + CAMetalLayer* m_mtlLayer; - PixelFormat m_pixelFormat; + std::vector> m_drawables; + uint32_t m_nextDrawableIndex = 0; public: MetalSwapchain& operator=(const MetalSwapchain&) = delete; diff --git a/src/Metal/MetalSwapchain.mm b/src/Metal/MetalSwapchain.mm index b7dbcd0..c454a87 100644 --- a/src/Metal/MetalSwapchain.mm +++ b/src/Metal/MetalSwapchain.mm @@ -16,29 +16,45 @@ #include "Metal/MetalSurface.hpp" #import "Metal/MetalEnums.hpp" +#include namespace gfx { MetalSwapchain::MetalSwapchain(const MetalDevice& device, const Swapchain::Descriptor& desc) - : m_width(desc.width) - , m_height(desc.height) - , m_pixelFormat(desc.pixelFormat) { @autoreleasepool + : m_swapchainImagesDescriptor{ + .type = TextureType::texture2d, + .width = desc.width, + .height = desc.height, + .pixelFormat = desc.pixelFormat, + .usages = TextureUsage::colorAttachment, + .storageMode = ResourceStorageMode::deviceLocal + } { - assert(desc.surface); - auto* mtlSurface = dynamic_cast(desc.surface); - assert(mtlSurface); - - m_mtlLayer = mtlSurface->mtlLayer(); - m_mtlLayer.device = device.mtlDevice(); - m_mtlLayer.drawableSize = CGSize{CGFloat(desc.width), CGFloat(desc.height)}; - m_mtlLayer.pixelFormat = toMTLPixelFormat(desc.pixelFormat); -}} + @autoreleasepool { + assert(desc.surface); + auto* mtlSurface = dynamic_cast(desc.surface); + assert(mtlSurface); + + m_mtlLayer = mtlSurface->mtlLayer(); + m_mtlLayer.device = device.mtlDevice(); + m_mtlLayer.drawableSize = CGSize{CGFloat(desc.width), CGFloat(desc.height)}; + m_mtlLayer.pixelFormat = toMTLPixelFormat(desc.pixelFormat); + + m_drawables.resize(desc.drawableCount); + for (auto& drawable : m_drawables) + drawable = std::make_shared(m_swapchainImagesDescriptor); + + } +} std::shared_ptr MetalSwapchain::nextDrawable() { @autoreleasepool { ZoneScoped; - return std::make_shared([m_mtlLayer nextDrawable]); + std::shared_ptr nextDrawable = m_drawables.at(m_nextDrawableIndex); + m_nextDrawableIndex = (m_nextDrawableIndex + 1) % m_drawables.size(); + nextDrawable->setMtlDrawable([m_mtlLayer nextDrawable]); + return nextDrawable; }} } diff --git a/src/Metal/MetalTexture.hpp b/src/Metal/MetalTexture.hpp index 7e4b4a0..27c8522 100644 --- a/src/Metal/MetalTexture.hpp +++ b/src/Metal/MetalTexture.hpp @@ -31,7 +31,7 @@ class MetalTexture : public Texture MetalTexture(const MetalTexture&) = delete; MetalTexture(MetalTexture&&) = delete; - MetalTexture(const id&, const Texture::Descriptor&); + MetalTexture(const Texture::Descriptor&); MetalTexture(const MetalDevice&, const Texture::Descriptor&); TextureType type() const override; @@ -42,6 +42,7 @@ class MetalTexture : public Texture inline ResourceStorageMode storageMode() const override { return m_storageMode; }; inline id mtltexture() const { return m_mtlTexture; } + inline void setMtlTexture(const id& t) { m_mtlTexture = t; } ~MetalTexture() override = default; diff --git a/src/Metal/MetalTexture.mm b/src/Metal/MetalTexture.mm index e082005..346c3e2 100644 --- a/src/Metal/MetalTexture.mm +++ b/src/Metal/MetalTexture.mm @@ -15,13 +15,14 @@ #import "Metal/MetalEnums.hpp" +#include + namespace gfx { -MetalTexture::MetalTexture(const id& mtltexture, const Texture::Descriptor& desc) +MetalTexture::MetalTexture(const Texture::Descriptor& desc) : m_usages(desc.usages) , m_storageMode(desc.storageMode) - , m_mtlTexture(mtltexture) { } @@ -44,22 +45,26 @@ TextureType MetalTexture::type() const { @autoreleasepool { - return toTextureType([mtltexture() textureType]); + assert(m_mtlTexture); + return toTextureType([m_mtlTexture textureType]); }} uint32_t MetalTexture::width() const { @autoreleasepool { - return static_cast(mtltexture().width); + assert(m_mtlTexture); + return static_cast(m_mtlTexture.width); }} uint32_t MetalTexture::height() const { @autoreleasepool { - return static_cast(mtltexture().height); + assert(m_mtlTexture); + return static_cast(m_mtlTexture.height); }} PixelFormat MetalTexture::pixelFormat() const { @autoreleasepool { - return toPixelFormat([mtltexture() pixelFormat]); + assert(m_mtlTexture); + return toPixelFormat([m_mtlTexture pixelFormat]); }} } diff --git a/src/Vulkan/VulkanSwapchain.cpp b/src/Vulkan/VulkanSwapchain.cpp index 6ff8c94..120b6a2 100644 --- a/src/Vulkan/VulkanSwapchain.cpp +++ b/src/Vulkan/VulkanSwapchain.cpp @@ -17,13 +17,12 @@ #include "Vulkan/VulkanSurface.hpp" #include "Vulkan/VulkanEnums.hpp" #include "Vulkan/VulkanDrawable.hpp" +#include "vulkan/vulkan.hpp" namespace gfx { -VulkanSwapchain::VulkanSwapchain(const VulkanDevice* device, const Descriptor& desc) - : m_device(device) - , m_pixelFormat(desc.pixelFormat) +VulkanSwapchain::VulkanSwapchain(const VulkanDevice* device, const Descriptor& desc) : m_device(device) { assert(desc.surface); const vk::SurfaceKHR& vkSurface = dynamic_cast(*desc.surface).vkSurface(); @@ -40,12 +39,13 @@ VulkanSwapchain::VulkanSwapchain(const VulkanDevice* device, const Descriptor& d std::vector surfacePresentModes = vkPhysicalDevice.getSurfacePresentModesKHR(vkSurface); assert(std::ranges::any_of(surfacePresentModes, [&desc](auto& m){return m == toVkPresentModeKHR(desc.presentMode);})); + vk::Extent2D extent; if (surfaceCapabilities.currentExtent.width != std::numeric_limits::max()) - m_extent = surfaceCapabilities.currentExtent; + extent = surfaceCapabilities.currentExtent; else { - m_extent.width = std::clamp(desc.width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width); - m_extent.height = std::clamp(desc.height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height); + extent.width = std::clamp(desc.width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width); + extent.height = std::clamp(desc.height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height); } @@ -54,7 +54,7 @@ VulkanSwapchain::VulkanSwapchain(const VulkanDevice* device, const Descriptor& d .setMinImageCount(desc.imageCount) .setImageFormat(toVkFormat(desc.pixelFormat)) .setImageColorSpace(toVkColorSpaceKHR(desc.pixelFormat)) - .setImageExtent(m_extent) + .setImageExtent(extent) .setImageArrayLayers(1) .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment) .setPreTransform(surfaceCapabilities.currentTransform) @@ -76,15 +76,15 @@ VulkanSwapchain::VulkanSwapchain(const VulkanDevice* device, const Descriptor& d m_vkSwapchain = vkSwapchainPtr.get(); s_oldSwapchains[&vkSurface] = *m_vkSwapchain; - Texture::Descriptor swapchainImageTexDesc = { - .width = m_extent.width, .height = m_extent.height, + m_swapchainImagesDescriptor = { + .width = extent.width, .height = extent.height, .pixelFormat = desc.pixelFormat, .usages = TextureUsage::colorAttachment, .storageMode = ResourceStorageMode::deviceLocal }; m_swapchainImages = m_device->vkDevice().getSwapchainImagesKHR(*vkSwapchainPtr) - | std::views::transform([&](vk::Image& vkImage) { return std::make_shared(m_device, std::move(vkImage), vkSwapchainPtr, swapchainImageTexDesc); }) + | std::views::transform([&](vk::Image& vkImage) { return std::make_shared(m_device, std::move(vkImage), vkSwapchainPtr, m_swapchainImagesDescriptor); }) | std::ranges::to(); m_drawables.resize(desc.drawableCount); diff --git a/src/Vulkan/VulkanSwapchain.hpp b/src/Vulkan/VulkanSwapchain.hpp index 4ad6748..79e4881 100644 --- a/src/Vulkan/VulkanSwapchain.hpp +++ b/src/Vulkan/VulkanSwapchain.hpp @@ -31,9 +31,7 @@ class VulkanSwapchain : public Swapchain VulkanSwapchain(const VulkanDevice*, const Swapchain::Descriptor&); - inline uint32_t width() const override { return m_extent.width; } - inline uint32_t height() const override { return m_extent.height; } - inline PixelFormat pixelFormat() const override { return m_pixelFormat; }; + inline const Texture::Descriptor& drawablesTextureDescriptor() const override { return m_swapchainImagesDescriptor; } std::shared_ptr nextDrawable() override; @@ -41,8 +39,7 @@ class VulkanSwapchain : public Swapchain private: const VulkanDevice* m_device; - vk::Extent2D m_extent; - PixelFormat m_pixelFormat; + Texture::Descriptor m_swapchainImagesDescriptor; vk::SwapchainKHR* m_vkSwapchain; std::vector> m_swapchainImages;