mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (MG_Backend/DirectVulkan): new VkRenderPassManager and a bunch of changes accordingly
This commit is contained in:
+2
-2
@@ -162,6 +162,7 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
|
||||
|
||||
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
|
||||
|
||||
@@ -225,11 +226,10 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderTargetManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||
|
||||
MobileGL/MG_State/GLState/Core.cpp
|
||||
MobileGL/MG_State/GLState/ErrorState/Error.cpp
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "UniformDescriptorBinder.h"
|
||||
|
||||
#include "VkRenderTargetManager.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_Util/ShaderTranspiler/Types.h"
|
||||
@@ -138,8 +137,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator,
|
||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||
Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes,
|
||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager,
|
||||
VkRenderTargetManager* framebufferManager) {
|
||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
||||
Shutdown();
|
||||
|
||||
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
||||
@@ -151,8 +149,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
"UniformDescriptorBinder::Initialize requires valid texture manager");
|
||||
MOBILEGL_ASSERT(samplerManager != nullptr,
|
||||
"UniformDescriptorBinder::Initialize requires valid sampler manager");
|
||||
MOBILEGL_ASSERT(framebufferManager != nullptr,
|
||||
"UniformDescriptorBinder::Initialize requires valid framebuffer manager");
|
||||
|
||||
m_device = device;
|
||||
m_allocator = allocator;
|
||||
@@ -164,7 +160,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_peakDescriptorSetsObserved = 0;
|
||||
m_textureManager = textureManager;
|
||||
m_samplerManager = samplerManager;
|
||||
m_framebufferManager = framebufferManager;
|
||||
|
||||
m_frames.resize(m_frameCount);
|
||||
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
|
||||
@@ -228,7 +223,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_peakDescriptorSetsObserved = 0;
|
||||
m_textureManager = nullptr;
|
||||
m_samplerManager = nullptr;
|
||||
m_framebufferManager = nullptr;
|
||||
}
|
||||
|
||||
void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) {
|
||||
@@ -451,6 +445,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const {
|
||||
(void)commandBuffer;
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
||||
@@ -481,36 +476,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageView offscreenView = VK_NULL_HANDLE;
|
||||
VkImage offscreenImage = VK_NULL_HANDLE;
|
||||
VkImageLayout* offscreenLayout = nullptr;
|
||||
if (m_framebufferManager->GetOffscreenColorTargetStateByTexture(texture->GetExternalIndex(), offscreenView,
|
||||
offscreenImage, offscreenLayout) &&
|
||||
offscreenView != VK_NULL_HANDLE && offscreenLayout != nullptr) {
|
||||
const Bool fromUndefined = (*offscreenLayout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
if (VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, offscreenImage, *offscreenLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
fromUndefined
|
||||
? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
|
||||
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
|
||||
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)) {
|
||||
VkDescriptorImageInfo sampledInfo{};
|
||||
if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, sampledInfo)) {
|
||||
return false;
|
||||
}
|
||||
sampledInfo.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse);
|
||||
if (sampledInfo.sampler == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
sampledInfo.imageView = offscreenView;
|
||||
sampledInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
outImageInfo = sampledInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, outImageInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkRenderTargetManager;
|
||||
|
||||
class UniformDescriptorBinder {
|
||||
public:
|
||||
enum class BindingKind : Uint8 {
|
||||
@@ -33,8 +31,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
|
||||
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
|
||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr,
|
||||
VkRenderTargetManager* framebufferManager = nullptr);
|
||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
||||
void Shutdown();
|
||||
|
||||
void BeginFrame(Uint32 frameIndex);
|
||||
@@ -100,7 +97,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 m_peakDescriptorSetsObserved = 0;
|
||||
VkTextureManager* m_textureManager = nullptr;
|
||||
VkSamplerManager* m_samplerManager = nullptr;
|
||||
VkRenderTargetManager* m_framebufferManager = nullptr;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
|
||||
@@ -61,14 +61,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_pendingClears[pTexture] = clearPayload;
|
||||
}
|
||||
|
||||
Bool VkClearManager::DequeueClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
|
||||
if (m_aliveObjects.find(texture) == m_aliveObjects.end())
|
||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
return m_pendingClears.find(texture) != m_pendingClears.end();
|
||||
}
|
||||
|
||||
Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
|
||||
if (m_aliveObjects.find(texture) == m_aliveObjects.end() ||
|
||||
m_pendingClears.find(texture) == m_pendingClears.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = m_pendingClears[texture];
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
m_aliveObjects.erase(texture);
|
||||
m_pendingClears.erase(texture);
|
||||
return true;
|
||||
}
|
||||
|
||||
SizeT VkClearManager::CollectGarbage() {
|
||||
|
||||
@@ -40,7 +40,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void QueueClear(
|
||||
const ClearAttachmentPayload& clearPayload,
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
|
||||
Bool DequeueClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
||||
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
||||
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
|
||||
|
||||
@@ -8,327 +8,234 @@
|
||||
|
||||
#include "VkRenderPassManager.h"
|
||||
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkRenderPassManager::Initialize(const InitInfo& initInfo) {
|
||||
Shutdown();
|
||||
VkRenderPassManager::VkRenderPassManager(VkDevice device,
|
||||
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager):
|
||||
m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager) {
|
||||
RenderPassEntry::s_device = m_device;
|
||||
}
|
||||
|
||||
if (initInfo.device == VK_NULL_HANDLE || initInfo.colorFormat == VK_FORMAT_UNDEFINED ||
|
||||
initInfo.depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||
return false;
|
||||
}
|
||||
VkRenderPassManager::~VkRenderPassManager() {}
|
||||
|
||||
m_device = initInfo.device;
|
||||
m_colorFormat = initInfo.colorFormat;
|
||||
m_depthStencilFormat = initInfo.depthStencilFormat;
|
||||
m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
MGLOG_D("VkRenderPassManager: RenderPasses created (LOAD/CLEAR).");
|
||||
return m_renderPassLoad != VK_NULL_HANDLE;
|
||||
Bool VkRenderPassManager::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::Shutdown() {
|
||||
DestroyDefaultFramebuffers();
|
||||
for (auto& [_, target] : m_offscreenRenderTargets) {
|
||||
DestroyOffscreenRenderTarget(target);
|
||||
}
|
||||
m_offscreenRenderTargets.clear();
|
||||
}
|
||||
|
||||
if (m_device != VK_NULL_HANDLE) {
|
||||
if (m_renderPassLoad != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr);
|
||||
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
||||
const MG_State::GLState::FramebufferObject& fbo) const {
|
||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||
auto& drawBuffers = fbo.GetDrawBuffers();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0])));
|
||||
auto readBuffer = fbo.GetReadBuffer();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &readBuffer, sizeof(FramebufferAttachmentType)));
|
||||
Int validDrawBufCount = 0;
|
||||
for (Int i = 0; i < drawBuffers.size(); ++i) {
|
||||
auto drawbuf = drawBuffers[i];
|
||||
if (drawbuf != FramebufferAttachmentType::None)
|
||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||
}
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &validDrawBufCount, sizeof(validDrawBufCount)));
|
||||
|
||||
auto combineFramebufferAttachmentObjHash = [&](FramebufferAttachmentType attachment) {
|
||||
auto& att = fbo.GetAttachment(attachment);
|
||||
|
||||
Int type = 0;
|
||||
if (att.IsEmpty()) type = 0;
|
||||
else if (att.IsTexture()) type = 1;
|
||||
else if (att.IsRenderbuffer()) type = 2;
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &type, sizeof(type)));
|
||||
void* contentPtr = nullptr;
|
||||
if (att.IsTexture())
|
||||
contentPtr = att.GetTexture().get();
|
||||
else if (att.IsRenderbuffer())
|
||||
contentPtr = att.GetRenderbuffer().get();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
|
||||
|
||||
if (att.IsTexture()) {
|
||||
auto hasClear = m_clearManager.HasPendingClear(att.GetTexture().get());
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
|
||||
}
|
||||
};
|
||||
|
||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
||||
auto drawbuf = drawBuffers[i];
|
||||
combineFramebufferAttachmentObjHash(drawbuf);
|
||||
}
|
||||
|
||||
m_renderPassLoad = VK_NULL_HANDLE;
|
||||
m_colorFormat = VK_FORMAT_UNDEFINED;
|
||||
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
m_defaultExtent = {0, 0};
|
||||
m_device = VK_NULL_HANDLE;
|
||||
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Depth);
|
||||
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Stencil);
|
||||
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
|
||||
const Vector<VkImageView>& depthStencilViews,
|
||||
VkExtent2D extent) {
|
||||
DestroyDefaultFramebuffers();
|
||||
RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo) {
|
||||
// retrieve from cache first
|
||||
auto hash = ComputeHash(fbo);
|
||||
auto it = m_renderPasses.find(hash);
|
||||
if (it != m_renderPasses.end())
|
||||
return it->second;
|
||||
|
||||
if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 ||
|
||||
extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) {
|
||||
return false;
|
||||
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||
// Color attachment
|
||||
auto& drawbufs = fbo.GetDrawBuffers();
|
||||
Int validDrawBufCount = 0;
|
||||
for (Int i = 0; i < drawbufs.size(); ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf != FramebufferAttachmentType::None)
|
||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||
}
|
||||
|
||||
m_defaultFramebuffers.reserve(colorViews.size());
|
||||
for (SizeT i = 0; i < colorViews.size(); ++i) {
|
||||
if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) {
|
||||
DestroyDefaultFramebuffers();
|
||||
return false;
|
||||
Int width = 0;
|
||||
Int height = 0;
|
||||
Vector<VkAttachmentDescription> colorAttachmentDescriptions(validDrawBufCount);
|
||||
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
||||
Vector<VkDescriptorImageInfo> descriptorImageInfo(validDrawBufCount);
|
||||
// This should automatically work on default & offscreen FBO
|
||||
// assuming default FBO has the right param
|
||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf == FramebufferAttachmentType::None ||
|
||||
fbo.GetAttachment(drawbuf).IsRenderbuffer())
|
||||
continue;
|
||||
|
||||
auto& att = fbo.GetAttachment(drawbuf);
|
||||
auto* texture = att.GetTexture().get();
|
||||
const auto textureTarget = texture->GetTarget();
|
||||
|
||||
// Color attachment description
|
||||
VkAttachmentDescription& desc = colorAttachmentDescriptions[i];
|
||||
switch (textureTarget) {
|
||||
case TextureTarget::Texture2D: {
|
||||
auto* texture2d =
|
||||
static_cast<MG_State::GLState::TextureObject2D*>(texture);
|
||||
desc.format =
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(
|
||||
texture2d->GetFormat());
|
||||
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
Bool hasClear = m_clearManager.HasPendingClear(texture);
|
||||
desc.loadOp = hasClear ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
desc.finalLayout = isDefaultFbo ?
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
if (width == 0)
|
||||
width = texture2d->GetBaseSize().x();
|
||||
if (height == 0)
|
||||
height = texture2d->GetBaseSize().y();
|
||||
|
||||
Bool ok = m_textureManager.SyncTextureAndGetDescriptor(*texture, descriptorImageInfo[i]);
|
||||
MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed");
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOBILEGL_ASSERT(false, "Unsupported texture target");
|
||||
}
|
||||
VkImageView attachments[] = {colorViews[i], depthStencilViews[i]};
|
||||
VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
createInfo.renderPass = m_renderPassLoad;
|
||||
createInfo.attachmentCount = static_cast<Uint32>(std::size(attachments));
|
||||
createInfo.pAttachments = attachments;
|
||||
createInfo.width = extent.width;
|
||||
createInfo.height = extent.height;
|
||||
createInfo.layers = 1;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) {
|
||||
DestroyDefaultFramebuffers();
|
||||
return false;
|
||||
}
|
||||
m_defaultFramebuffers.push_back(framebuffer);
|
||||
}
|
||||
m_defaultExtent = extent;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const {
|
||||
if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outRenderPass = m_renderPassLoad;
|
||||
outFramebuffer = m_defaultFramebuffers[imageIndex];
|
||||
outExtent = m_defaultExtent;
|
||||
outDepthStencilFormat = m_depthStencilFormat;
|
||||
return outFramebuffer != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) {
|
||||
if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE ||
|
||||
targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 ||
|
||||
targetInfo.extent.height == 0) {
|
||||
return false;
|
||||
// Attachment reference
|
||||
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
||||
attachmentRef.attachment = i;
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
const Bool hasDepthStencil =
|
||||
targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED;
|
||||
|
||||
auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex];
|
||||
if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE &&
|
||||
target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView &&
|
||||
target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView &&
|
||||
target.depthStencilFormat == targetInfo.depthStencilFormat &&
|
||||
target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DestroyOffscreenRenderTarget(target);
|
||||
// Depth attachment description
|
||||
VkAttachmentDescription depthAttachmentDescription;
|
||||
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
depthAttachmentDescription.format =
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(depthAtt.GetTexture()->GetFormat());
|
||||
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depthAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
depthAttachmentDescription.finalLayout = isDefaultFbo ?
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED;
|
||||
target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (target.renderPassLoad == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
// Depth attachment ref
|
||||
VkAttachmentReference depthAttachmentRef;
|
||||
depthAttachmentRef.attachment = 1;
|
||||
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
Array<VkImageView, 2> attachments{};
|
||||
attachments[0] = targetInfo.colorView;
|
||||
Uint32 attachmentCount = 1;
|
||||
if (hasDepthStencil) {
|
||||
attachments[1] = targetInfo.depthStencilView;
|
||||
attachmentCount = 2;
|
||||
}
|
||||
// Subpass
|
||||
VkSubpassDescription subpassDesc;
|
||||
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
|
||||
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
|
||||
subpassDesc.pDepthStencilAttachment = &depthAttachmentRef;
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
framebufferInfo.renderPass = target.renderPassLoad;
|
||||
framebufferInfo.attachmentCount = attachmentCount;
|
||||
framebufferInfo.pAttachments = attachments.data();
|
||||
framebufferInfo.width = targetInfo.extent.width;
|
||||
framebufferInfo.height = targetInfo.extent.height;
|
||||
framebufferInfo.layers = 1;
|
||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer),
|
||||
"vkCreateFramebuffer(offscreen)");
|
||||
|
||||
target.targetVersion = targetInfo.targetVersion;
|
||||
target.colorView = targetInfo.colorView;
|
||||
target.colorFormat = targetInfo.colorFormat;
|
||||
target.depthStencilView = targetInfo.depthStencilView;
|
||||
target.depthStencilFormat = targetInfo.depthStencilFormat;
|
||||
target.extent = targetInfo.extent;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const {
|
||||
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
|
||||
if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE ||
|
||||
it->second.framebuffer == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outRenderPass = it->second.renderPassLoad;
|
||||
outFramebuffer = it->second.framebuffer;
|
||||
outExtent = it->second.extent;
|
||||
outDepthStencilFormat = it->second.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) {
|
||||
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
|
||||
if (it == m_offscreenRenderTargets.end()) {
|
||||
return;
|
||||
}
|
||||
DestroyOffscreenRenderTarget(it->second);
|
||||
m_offscreenRenderTargets.erase(it);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass,
|
||||
VkFramebuffer framebuffer, VkExtent2D extent) const {
|
||||
VkRenderPassBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
beginInfo.renderPass = renderPass;
|
||||
beginInfo.framebuffer = framebuffer;
|
||||
beginInfo.renderArea.offset = {0, 0};
|
||||
beginInfo.renderArea.extent = extent;
|
||||
beginInfo.clearValueCount = 0;
|
||||
beginInfo.pClearValues = nullptr;
|
||||
vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const {
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
|
||||
const VkClearColorValue& clearColor) const {
|
||||
VkClearAttachment clearAttachment{};
|
||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clearAttachment.colorAttachment = 0;
|
||||
clearAttachment.clearValue.color = clearColor;
|
||||
|
||||
VkClearRect clearRect{};
|
||||
clearRect.rect.offset = {0, 0};
|
||||
clearRect.rect.extent = extent;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask,
|
||||
Float depth, Uint32 stencil, VkFormat depthStencilFormat) const {
|
||||
if (depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageAspectFlags aspectMask = 0;
|
||||
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
if (aspectMask == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkClearAttachment clearAttachment{};
|
||||
clearAttachment.aspectMask = aspectMask;
|
||||
clearAttachment.clearValue.depthStencil.depth = depth;
|
||||
clearAttachment.clearValue.depthStencil.stencil = stencil;
|
||||
|
||||
VkClearRect clearRect{};
|
||||
clearRect.rect.offset = {0, 0};
|
||||
clearRect.rect.extent = extent;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const {
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "VkRenderPassManager: device is null");
|
||||
MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined");
|
||||
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED,
|
||||
"VkRenderPassManager: depth/stencil format is undefined");
|
||||
return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat,
|
||||
VkAttachmentLoadOp colorLoadOp,
|
||||
VkImageLayout colorFinalLayout) const {
|
||||
VkAttachmentDescription color{};
|
||||
color.format = colorFormat;
|
||||
color.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color.loadOp = colorLoadOp;
|
||||
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
color.finalLayout = colorFinalLayout;
|
||||
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED;
|
||||
VkAttachmentDescription depthStencil{};
|
||||
if (hasDepthStencil) {
|
||||
depthStencil.format = depthStencilFormat;
|
||||
depthStencil.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
||||
VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorRef;
|
||||
if (hasDepthStencil) {
|
||||
subpass.pDepthStencilAttachment = &depthStencilRef;
|
||||
}
|
||||
|
||||
Array<VkAttachmentDescription, 2> attachments{};
|
||||
attachments[0] = color;
|
||||
Uint32 attachmentCount = 1;
|
||||
if (hasDepthStencil) {
|
||||
attachments[1] = depthStencil;
|
||||
attachmentCount = 2;
|
||||
}
|
||||
|
||||
VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
|
||||
createInfo.attachmentCount = attachmentCount;
|
||||
createInfo.pAttachments = attachments.data();
|
||||
createInfo.subpassCount = 1;
|
||||
createInfo.pSubpasses = &subpass;
|
||||
// Render Pass
|
||||
VkRenderPassCreateInfo renderPassCreateInfo;
|
||||
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassCreateInfo.attachmentCount = colorAttachmentDescriptions.size();
|
||||
renderPassCreateInfo.pAttachments = colorAttachmentDescriptions.data();
|
||||
renderPassCreateInfo.subpassCount = 1;
|
||||
renderPassCreateInfo.pSubpasses = &subpassDesc;
|
||||
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass");
|
||||
return renderPass;
|
||||
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));
|
||||
|
||||
Vector<VkImageView> attachmentViews(descriptorImageInfo.size(), VK_NULL_HANDLE);
|
||||
for (Int i = 0; i < descriptorImageInfo.size(); i++) {
|
||||
attachmentViews[i] = descriptorImageInfo[i].imageView;
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
VkFramebufferCreateInfo framebufferCreateInfo;
|
||||
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferCreateInfo.renderPass = renderPass;
|
||||
framebufferCreateInfo.attachmentCount = attachmentViews.size();
|
||||
framebufferCreateInfo.pAttachments = attachmentViews.data();
|
||||
framebufferCreateInfo.width = width;
|
||||
framebufferCreateInfo.height = height;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
||||
IntVec2 extent = {width, height};
|
||||
m_renderPasses[hash] = { renderPass, framebuffer, Move(descriptorImageInfo), extent };
|
||||
return m_renderPasses[hash];
|
||||
}
|
||||
|
||||
void VkRenderPassManager::DestroyDefaultFramebuffers() {
|
||||
for (auto framebuffer : m_defaultFramebuffers) {
|
||||
if (framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
|
||||
}
|
||||
}
|
||||
m_defaultFramebuffers.clear();
|
||||
m_defaultExtent = {0, 0};
|
||||
Bool VkRenderPassManager::StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
|
||||
if (m_activeRenderPass != nullptr)
|
||||
return false;
|
||||
|
||||
m_activeRenderPass = &renderPassEntry;
|
||||
VkRenderPassBeginInfo renderPassBeginInfo;
|
||||
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassBeginInfo.renderPass = m_activeRenderPass->renderPass;
|
||||
renderPassBeginInfo.framebuffer = m_activeRenderPass->framebuffer;
|
||||
renderPassBeginInfo.renderArea.offset = { 0, 0 };
|
||||
renderPassBeginInfo.renderArea.extent = {
|
||||
(Uint32)m_activeRenderPass->extent.x(), (Uint32)m_activeRenderPass->extent.y() };
|
||||
|
||||
// TODO: should query proper clear color
|
||||
VkClearValue clearValue;
|
||||
clearValue.color = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
clearValue.depthStencil = { 1.0f, 0 };
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) {
|
||||
if (target.framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(m_device, target.framebuffer, nullptr);
|
||||
target.framebuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.renderPassLoad != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr);
|
||||
target.renderPassLoad = VK_NULL_HANDLE;
|
||||
}
|
||||
target.targetVersion = 0;
|
||||
target.colorView = VK_NULL_HANDLE;
|
||||
target.colorFormat = VK_FORMAT_UNDEFINED;
|
||||
target.depthStencilView = VK_NULL_HANDLE;
|
||||
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
target.extent = {0, 0};
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::HasStencilComponent(VkFormat format) {
|
||||
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
||||
if (m_activeRenderPass == nullptr)
|
||||
return false;
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
return true;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -8,75 +8,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VkClearManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include "../VulkanRendererConfig.h"
|
||||
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct RenderPassEntry {
|
||||
static inline VkDevice s_device;
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
Vector<VkDescriptorImageInfo> descriptorImageInfo;
|
||||
IntVec2 extent = {0, 0};
|
||||
|
||||
~RenderPassEntry() {
|
||||
if (renderPass != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(s_device, renderPass, nullptr);
|
||||
}
|
||||
if (framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(s_device, framebuffer, nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VkRenderPassManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
};
|
||||
using HashType = Uint64;
|
||||
VkRenderPassManager(VkDevice device,
|
||||
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager);
|
||||
~VkRenderPassManager();
|
||||
|
||||
struct OffscreenRenderTargetInfo {
|
||||
Uint targetExternalIndex = 0;
|
||||
Uint16 targetVersion = 0;
|
||||
VkImageView colorView = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageView depthStencilView = VK_NULL_HANDLE;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
Bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
Bool RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
|
||||
const Vector<VkImageView>& depthStencilViews, VkExtent2D extent);
|
||||
Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
||||
|
||||
Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo);
|
||||
Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const;
|
||||
void RemoveOffscreenRenderTarget(Uint targetExternalIndex);
|
||||
|
||||
void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer,
|
||||
VkExtent2D extent) const;
|
||||
void EndRenderPass(VkCommandBuffer commandBuffer) const;
|
||||
void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
|
||||
const VkClearColorValue& clearColor) const;
|
||||
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth,
|
||||
Uint32 stencil, VkFormat depthStencilFormat) const;
|
||||
|
||||
HashType ComputeHash(const MG_State::GLState::FramebufferObject& fbo) const;
|
||||
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo);
|
||||
RenderPassEntry* GetActiveRenderPass() const { return m_activeRenderPass; }
|
||||
Bool StartRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
|
||||
Bool EndRenderPass(VkCommandBuffer commandBuffer);
|
||||
private:
|
||||
struct OffscreenRenderTarget {
|
||||
Uint16 targetVersion = 0;
|
||||
VkImageView colorView = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageView depthStencilView = VK_NULL_HANDLE;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
VkRenderPass renderPassLoad = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const;
|
||||
VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp,
|
||||
VkImageLayout colorFinalLayout) const;
|
||||
void DestroyDefaultFramebuffers();
|
||||
void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target);
|
||||
static Bool HasStencilComponent(VkFormat format);
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkFormat m_colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkRenderPass m_renderPassLoad = VK_NULL_HANDLE;
|
||||
Vector<VkFramebuffer> m_defaultFramebuffers;
|
||||
VkExtent2D m_defaultExtent = {0, 0};
|
||||
UnorderedMap<Uint, OffscreenRenderTarget> m_offscreenRenderTargets;
|
||||
const VulkanRendererConfig& m_config;
|
||||
VkClearManager& m_clearManager;
|
||||
VkTextureManager& m_textureManager;
|
||||
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
||||
RenderPassEntry* m_activeRenderPass = nullptr;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkRenderTargetManager.h"
|
||||
|
||||
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
|
||||
#include <MG_State/GLState/TextureState/TextureEnum.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkRenderTargetManager::Initialize(const InitInfo& initInfo) {
|
||||
m_device = initInfo.device;
|
||||
m_physicalDevice = initInfo.physicalDevice;
|
||||
m_allocator = initInfo.allocator;
|
||||
return m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr;
|
||||
}
|
||||
|
||||
void VkRenderTargetManager::Shutdown() {
|
||||
for (auto& [_, target] : m_offscreenColorTargets) {
|
||||
DestroyOffscreenColorTarget(target);
|
||||
}
|
||||
m_offscreenColorTargets.clear();
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_physicalDevice = VK_NULL_HANDLE;
|
||||
m_allocator = nullptr;
|
||||
}
|
||||
|
||||
Bool VkRenderTargetManager::EnsureOffscreenColorTarget(Uint glFboExternalIndex,
|
||||
const MG_State::GLState::FramebufferObject& glFbo) {
|
||||
const auto& colorAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Color0);
|
||||
if (!colorAttachment.IsValid() || colorAttachment.IsEmpty()) {
|
||||
MGLOG_W("VkFramebufferManager: FBO %u has no valid COLOR0 attachment", glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto objectVersion = glFbo.GetObjectVersion();
|
||||
auto& target = m_offscreenColorTargets[glFboExternalIndex];
|
||||
if (target.image != VK_NULL_HANDLE && target.glObjectVersion == objectVersion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion);
|
||||
}
|
||||
|
||||
Bool VkRenderTargetManager::GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage,
|
||||
VkImageLayout*& outColorLayout,
|
||||
VkImage& outDepthStencilImage,
|
||||
VkImageLayout*& outDepthStencilLayout,
|
||||
VkFormat& outDepthStencilFormat) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
if (target.image == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outColorImage = target.image;
|
||||
outColorLayout = &target.layout;
|
||||
outDepthStencilImage = target.depthStencilImage;
|
||||
outDepthStencilLayout = &target.depthStencilLayout;
|
||||
outDepthStencilFormat = target.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderTargetManager::GetOffscreenColorTargetStateByTexture(Uint textureExternalIndex,
|
||||
VkImageView& outImageView, VkImage& outImage,
|
||||
VkImageLayout*& outLayout) {
|
||||
for (auto& [_, target] : m_offscreenColorTargets) {
|
||||
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE ||
|
||||
target.imageView == VK_NULL_HANDLE) {
|
||||
continue;
|
||||
}
|
||||
outImageView = target.imageView;
|
||||
outImage = target.image;
|
||||
outLayout = &target.layout;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool VkRenderTargetManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView,
|
||||
VkFormat& outColorFormat, VkImageView& outDepthStencilView,
|
||||
VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outColorView = it->second.imageView;
|
||||
outColorFormat = it->second.format;
|
||||
outDepthStencilView = it->second.depthStencilImageView;
|
||||
outExtent = it->second.extent;
|
||||
outDepthStencilFormat = it->second.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderTargetManager::RecreateOffscreenColorTarget(
|
||||
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion) {
|
||||
DestroyOffscreenColorTarget(target);
|
||||
|
||||
const auto size = colorAttachment.GetSize();
|
||||
if (size.x() <= 0 || size.y() <= 0) {
|
||||
MGLOG_W("VkFramebufferManager: COLOR0 attachment size is invalid (%d, %d)", size.x(), size.y());
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkFormat format = ResolveColorFormat(colorAttachment);
|
||||
if (format == VK_FORMAT_UNDEFINED) {
|
||||
MGLOG_W("VkFramebufferManager: COLOR0 attachment format is unsupported for Vulkan clear");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = static_cast<Uint32>(size.x());
|
||||
imageInfo.extent.height = static_cast<Uint32>(size.y());
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VmaAllocationCreateInfo colorAllocationInfo{};
|
||||
colorAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
colorAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &colorAllocationInfo, &target.image, &target.allocation, nullptr),
|
||||
"vmaCreateImage(offscreen color)");
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = target.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView),
|
||||
"vkCreateImageView(offscreen color)");
|
||||
|
||||
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
const Bool requestedDepthStencil = (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
|
||||
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
|
||||
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
|
||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
||||
depthStencilFormat =
|
||||
FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
|
||||
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
|
||||
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
|
||||
}
|
||||
const Bool hasDepthStencil = (depthStencilFormat != VK_FORMAT_UNDEFINED);
|
||||
if (requestedDepthStencil && !hasDepthStencil) {
|
||||
MGLOG_W("VkFramebufferManager: FBO %u depth/stencil attachment exists but format is unsupported",
|
||||
glFbo.GetExternalIndex());
|
||||
}
|
||||
if (hasDepthStencil) {
|
||||
VkImageCreateInfo depthImageInfo{};
|
||||
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
depthImageInfo.extent.width = static_cast<Uint32>(size.x());
|
||||
depthImageInfo.extent.height = static_cast<Uint32>(size.y());
|
||||
depthImageInfo.extent.depth = 1;
|
||||
depthImageInfo.mipLevels = 1;
|
||||
depthImageInfo.arrayLayers = 1;
|
||||
depthImageInfo.format = depthStencilFormat;
|
||||
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VmaAllocationCreateInfo depthAllocationInfo{};
|
||||
depthAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
depthAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
VK_VERIFY(vmaCreateImage(m_allocator, &depthImageInfo, &depthAllocationInfo, &target.depthStencilImage,
|
||||
&target.depthStencilAllocation, nullptr),
|
||||
"vmaCreateImage(offscreen depth/stencil)");
|
||||
|
||||
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
VkImageViewCreateInfo depthViewInfo{};
|
||||
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
depthViewInfo.image = target.depthStencilImage;
|
||||
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthViewInfo.format = depthStencilFormat;
|
||||
depthViewInfo.subresourceRange.aspectMask = depthAspectMask;
|
||||
depthViewInfo.subresourceRange.baseMipLevel = 0;
|
||||
depthViewInfo.subresourceRange.levelCount = 1;
|
||||
depthViewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
depthViewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &depthViewInfo, nullptr, &target.depthStencilImageView),
|
||||
"vkCreateImageView(offscreen depth/stencil)");
|
||||
}
|
||||
|
||||
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
|
||||
target.format = format;
|
||||
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.depthStencilFormat = depthStencilFormat;
|
||||
target.glObjectVersion = glObjectVersion;
|
||||
target.colorTextureExternalIndex = (colorAttachment.IsTexture() && colorAttachment.GetTexture())
|
||||
? colorAttachment.GetTexture()->GetExternalIndex()
|
||||
: 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderTargetManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) {
|
||||
if (target.imageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, target.imageView, nullptr);
|
||||
target.imageView = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.depthStencilImageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, target.depthStencilImageView, nullptr);
|
||||
target.depthStencilImageView = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.image != VK_NULL_HANDLE) {
|
||||
vmaDestroyImage(m_allocator, target.image, target.allocation);
|
||||
target.image = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.depthStencilImage != VK_NULL_HANDLE) {
|
||||
vmaDestroyImage(m_allocator, target.depthStencilImage, target.depthStencilAllocation);
|
||||
target.depthStencilImage = VK_NULL_HANDLE;
|
||||
}
|
||||
target.allocation = nullptr;
|
||||
target.depthStencilAllocation = nullptr;
|
||||
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.extent = {0, 0};
|
||||
target.format = VK_FORMAT_UNDEFINED;
|
||||
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
target.glObjectVersion = 0;
|
||||
target.colorTextureExternalIndex = 0;
|
||||
}
|
||||
|
||||
VkFormat VkRenderTargetManager::ResolveColorFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment) {
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
if (colorAttachment.IsTexture()) {
|
||||
const auto texture = colorAttachment.GetTexture();
|
||||
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||
} else if (colorAttachment.IsRenderbuffer()) {
|
||||
const auto renderbuffer = colorAttachment.GetRenderbuffer();
|
||||
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
|
||||
}
|
||||
|
||||
switch (internalFormat) {
|
||||
case TextureInternalFormat::RGBA:
|
||||
case TextureInternalFormat::RGBA8:
|
||||
case TextureInternalFormat::SRGB8Alpha8:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat VkRenderTargetManager::ResolveDepthStencilFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment) {
|
||||
const auto resolveAttachmentFormat = [](const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
if (attachment.IsTexture()) {
|
||||
const auto texture = attachment.GetTexture();
|
||||
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||
} else if (attachment.IsRenderbuffer()) {
|
||||
const auto renderbuffer = attachment.GetRenderbuffer();
|
||||
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
|
||||
}
|
||||
return internalFormat;
|
||||
};
|
||||
|
||||
const auto depthFormat = resolveAttachmentFormat(depthAttachment);
|
||||
const auto stencilFormat = resolveAttachmentFormat(stencilAttachment);
|
||||
|
||||
switch (depthFormat) {
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
case TextureInternalFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TextureInternalFormat::DepthComponent16:
|
||||
return VK_FORMAT_D16_UNORM;
|
||||
case TextureInternalFormat::DepthComponent24:
|
||||
case TextureInternalFormat::DepthComponent32:
|
||||
case TextureInternalFormat::DepthComponent32F:
|
||||
case TextureInternalFormat::DepthComponent:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (stencilFormat) {
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
case TextureInternalFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat VkRenderTargetManager::FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const {
|
||||
for (auto format : candidates) {
|
||||
VkFormatProperties properties{};
|
||||
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &properties);
|
||||
if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,75 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkRenderTargetManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
VmaAllocator allocator = nullptr;
|
||||
};
|
||||
|
||||
VkRenderTargetManager() = default;
|
||||
~VkRenderTargetManager() = default;
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
||||
Bool GetOffscreenRenderSurfaceState(Uint glFboExternalIndex, VkImage& outColorImage,
|
||||
VkImageLayout*& outColorLayout, VkImage& outDepthStencilImage,
|
||||
VkImageLayout*& outDepthStencilLayout,
|
||||
VkFormat& outDepthStencilFormat);
|
||||
Bool GetOffscreenColorTargetStateByTexture(Uint textureExternalIndex, VkImageView& outImageView,
|
||||
VkImage& outImage, VkImageLayout*& outLayout);
|
||||
Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat,
|
||||
VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat,
|
||||
VkExtent2D& outExtent) const;
|
||||
|
||||
private:
|
||||
struct OffscreenColorTarget {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = nullptr;
|
||||
VkImageView imageView = VK_NULL_HANDLE;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImage depthStencilImage = VK_NULL_HANDLE;
|
||||
VmaAllocation depthStencilAllocation = nullptr;
|
||||
VkImageView depthStencilImageView = VK_NULL_HANDLE;
|
||||
VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
Uint16 glObjectVersion = 0;
|
||||
Uint colorTextureExternalIndex = 0;
|
||||
};
|
||||
|
||||
Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target,
|
||||
const MG_State::GLState::FramebufferObject& glFbo,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
||||
Uint16 glObjectVersion);
|
||||
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
||||
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
||||
static VkFormat ResolveDepthStencilFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
|
||||
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VmaAllocator m_allocator = nullptr;
|
||||
UnorderedMap<Uint, OffscreenColorTarget> m_offscreenColorTargets;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -62,7 +62,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
outImageInfo.sampler = VK_NULL_HANDLE;
|
||||
outImageInfo.imageView = it->second.view;
|
||||
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
// Will be VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
// Shouldn't hardcode VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL here
|
||||
// outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
}
|
||||
Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
|
||||
@@ -298,6 +300,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return ok;
|
||||
});
|
||||
|
||||
|
||||
@@ -205,8 +205,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
CreateAllocator();
|
||||
|
||||
CreateCommandPool();
|
||||
m_renderPassManager = MakeUnique<VkRenderPassManager>();
|
||||
m_textureManager = MakeUnique<VkTextureManager>();
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "VkTextureManager creation failed.");
|
||||
auto succeeded = false;
|
||||
succeeded = m_textureManager->Initialize(
|
||||
{m_device, m_physicalDevice.handle, m_allocator, m_commandPool, m_graphicsQueue});
|
||||
MOBILEGL_ASSERT(succeeded, "VkTextureManager initialization failed.");
|
||||
m_clearManager = MakeUnique<VkClearManager>();
|
||||
MOBILEGL_ASSERT(m_clearManager != nullptr, "VkClearManager creation failed.");
|
||||
succeeded = m_clearManager->Initialize();
|
||||
MOBILEGL_ASSERT(succeeded, "VkClearManager initialization failed.");
|
||||
m_renderPassManager = MakeUnique<VkRenderPassManager>(m_device, m_config, *m_clearManager, *m_textureManager);
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "VkRenderPassManager creation failed.");
|
||||
succeeded = m_renderPassManager->Initialize();
|
||||
MOBILEGL_ASSERT(succeeded, "VkRenderPassManager initialization failed.");
|
||||
|
||||
RecreateSwapchain();
|
||||
|
||||
@@ -214,30 +226,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory creation failed.");
|
||||
m_programFactory = MakeUnique<ProgramFactory>(m_device, m_config);
|
||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed.");
|
||||
m_textureManager = MakeUnique<VkTextureManager>();
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "VkTextureManager creation failed.");
|
||||
auto succeeded = false;
|
||||
succeeded = m_textureManager->Initialize(
|
||||
{m_device, m_physicalDevice.handle, m_allocator, m_commandPool, m_graphicsQueue});
|
||||
MOBILEGL_ASSERT(succeeded, "VkTextureManager initialization failed.");
|
||||
|
||||
m_samplerManager = MakeUnique<VkSamplerManager>();
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "VkSamplerManager creation failed.");
|
||||
succeeded = m_samplerManager->Initialize({m_device, &m_config});
|
||||
MOBILEGL_ASSERT(succeeded, "VkSamplerManager initialization failed.");
|
||||
|
||||
m_framebufferManager = MakeUnique<VkRenderTargetManager>();
|
||||
MOBILEGL_ASSERT(m_framebufferManager != nullptr, "VkFramebufferManager creation failed.");
|
||||
succeeded = m_framebufferManager->Initialize({m_device, m_physicalDevice.handle, m_allocator});
|
||||
MOBILEGL_ASSERT(succeeded, "VkFramebufferManager initialization failed.");
|
||||
|
||||
m_uniformDescriptorBinder = MakeUnique<UniformDescriptorBinder>();
|
||||
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "UniformDescriptorBinder creation failed.");
|
||||
succeeded = m_uniformDescriptorBinder->Initialize(m_device, m_allocator,
|
||||
m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment,
|
||||
m_config.MaxFramesInFlight, 16, 64, 4 * 1024 * 1024,
|
||||
m_textureManager.get(), m_samplerManager.get(),
|
||||
m_framebufferManager.get());
|
||||
m_textureManager.get(), m_samplerManager.get());
|
||||
MOBILEGL_ASSERT(succeeded, "UniformDescriptorBinder initialization failed.");
|
||||
m_vertexInputStateFactory = MakeUnique<VertexInputStateFactory>(m_config);
|
||||
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
||||
@@ -292,11 +292,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
ShutdownSwapchain();
|
||||
m_renderPassManager.reset();
|
||||
if (m_framebufferManager) {
|
||||
m_framebufferManager->Shutdown();
|
||||
m_framebufferManager.reset();
|
||||
if (m_clearManager) {
|
||||
m_clearManager->Shutdown();
|
||||
m_clearManager.reset();
|
||||
}
|
||||
|
||||
if (m_commandPool != VK_NULL_HANDLE) {
|
||||
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
||||
m_commandPool = VK_NULL_HANDLE;
|
||||
@@ -353,6 +352,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
pending.drawFboExternalIndex = drawFboExternalIndex;
|
||||
pending.targetsDefaultFramebuffer = isDefaultFramebufferTarget;
|
||||
pending.mask |= requestMask;
|
||||
|
||||
if (m_clearManager == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto* defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
const auto* defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO.get() : nullptr;
|
||||
const MG_State::GLState::FramebufferObject* drawFbo = nullptr;
|
||||
if (isDefaultFramebufferTarget) {
|
||||
drawFbo = defaultFbo;
|
||||
} else {
|
||||
drawFbo = MG_State::pGLContext->GetFramebufferObject(drawFboExternalIndex).get();
|
||||
}
|
||||
if (drawFbo == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_clearManager->QueueClear(
|
||||
requestMask,
|
||||
{
|
||||
.color = color,
|
||||
.depth = depth,
|
||||
.stencil = stencil,
|
||||
},
|
||||
*drawFbo);
|
||||
}
|
||||
|
||||
Bool VulkanRenderer::ConsumePendingColorClear(VkClearColorValue& outClearColor) {
|
||||
@@ -370,6 +392,51 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
|
||||
void VulkanRenderer::ApplyPendingClearsForActiveTarget(VkCommandBuffer commandBuffer, Uint64 drawTargetKey) {
|
||||
if (m_activeRenderExtent.width == 0 || m_activeRenderExtent.height == 0) {
|
||||
return;
|
||||
}
|
||||
auto pendingIt = m_pendingClears.find(drawTargetKey);
|
||||
if (pendingIt == m_pendingClears.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkClearRect clearRect{};
|
||||
clearRect.rect.offset = {0, 0};
|
||||
clearRect.rect.extent = m_activeRenderExtent;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
VkClearAttachment colorAttachment{};
|
||||
colorAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
colorAttachment.colorAttachment = 0;
|
||||
colorAttachment.clearValue.color = pendingIt->second.color;
|
||||
vkCmdClearAttachments(commandBuffer, 1, &colorAttachment, 1, &clearRect);
|
||||
pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
|
||||
if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||
VkClearAttachment depthStencilAttachment{};
|
||||
depthStencilAttachment.aspectMask = 0;
|
||||
if ((pendingIt->second.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if ((pendingIt->second.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
depthStencilAttachment.colorAttachment = 0;
|
||||
depthStencilAttachment.clearValue.depthStencil.depth = pendingIt->second.depth;
|
||||
depthStencilAttachment.clearValue.depthStencil.stencil = pendingIt->second.stencil;
|
||||
vkCmdClearAttachments(commandBuffer, 1, &depthStencilAttachment, 1, &clearRect);
|
||||
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if (pendingIt->second.mask == 0) {
|
||||
m_pendingClears.erase(pendingIt);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderer::TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) {
|
||||
auto layout = m_swapchainObject.GetImageLayout(imageIndex);
|
||||
Bool ok = VkTextureManager::TransitionImageLayout(commandBuffer, m_swapchainObject.GetImage(imageIndex),
|
||||
@@ -469,119 +536,42 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
|
||||
VkExtent2D offscreenExtent{};
|
||||
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!EnsureOffscreenRenderTarget(drawFboExternalIndex, *drawFbo, offscreenRenderPass, offscreenFramebuffer,
|
||||
offscreenExtent, offscreenDepthStencilFormat)) {
|
||||
MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen render target for FBO %u is unavailable",
|
||||
drawFboExternalIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
VkImage offscreenColorImage = VK_NULL_HANDLE;
|
||||
VkImageLayout* offscreenColorLayout = nullptr;
|
||||
VkImage offscreenDepthStencilImage = VK_NULL_HANDLE;
|
||||
VkImageLayout* offscreenDepthStencilLayout = nullptr;
|
||||
VkFormat offscreenDepthStencilStateFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!m_framebufferManager->GetOffscreenRenderSurfaceState(
|
||||
drawFboExternalIndex, offscreenColorImage, offscreenColorLayout, offscreenDepthStencilImage,
|
||||
offscreenDepthStencilLayout, offscreenDepthStencilStateFormat) ||
|
||||
offscreenColorLayout == nullptr) {
|
||||
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment",
|
||||
drawFboExternalIndex);
|
||||
return;
|
||||
}
|
||||
if (!VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, offscreenColorImage, *offscreenColorLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT)) {
|
||||
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen color for FBO %u",
|
||||
drawFboExternalIndex);
|
||||
return;
|
||||
}
|
||||
if (offscreenDepthStencilImage != VK_NULL_HANDLE && offscreenDepthStencilLayout != nullptr) {
|
||||
VkImageAspectFlags depthStencilAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (offscreenDepthStencilStateFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
offscreenDepthStencilStateFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
depthStencilAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
if (!VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, offscreenDepthStencilImage, *offscreenDepthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
depthStencilAspectMask)) {
|
||||
MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen depth/stencil for FBO %u",
|
||||
drawFboExternalIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
|
||||
offscreenExtent);
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null");
|
||||
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo);
|
||||
Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry);
|
||||
MOBILEGL_ASSERT(started, "EnsureFrameRecordingStarted: StartRenderPass for offscreen target failed");
|
||||
m_isMainRenderPassActive = true;
|
||||
m_activeRenderPass = offscreenRenderPass;
|
||||
m_activeRenderExtent = offscreenExtent;
|
||||
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
||||
m_activeRenderPass = renderPassEntry.renderPass;
|
||||
m_activeRenderExtent = {
|
||||
static_cast<Uint32>(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0),
|
||||
static_cast<Uint32>(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)};
|
||||
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
m_activeRenderTargetIsDefault = false;
|
||||
m_activeDrawFboExternalIndex = drawFboExternalIndex;
|
||||
auto pendingIt = m_pendingClears.find(drawTargetKey);
|
||||
if (pendingIt != m_pendingClears.end()) {
|
||||
if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color);
|
||||
pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent,
|
||||
pendingIt->second.mask, pendingIt->second.depth,
|
||||
pendingIt->second.stencil, m_activeDepthStencilFormat);
|
||||
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
if (pendingIt->second.mask == 0) {
|
||||
m_pendingClears.erase(pendingIt);
|
||||
}
|
||||
}
|
||||
ApplyPendingClearsForActiveTarget(commandBuffer, drawTargetKey);
|
||||
return;
|
||||
}
|
||||
|
||||
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
||||
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
||||
|
||||
VkRenderPass defaultRenderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer defaultFramebuffer = VK_NULL_HANDLE;
|
||||
VkExtent2D defaultExtent{};
|
||||
VkFormat defaultDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!GetDefaultRenderTargetForCurrentImage(defaultRenderPass, defaultFramebuffer, defaultExtent,
|
||||
defaultDepthStencilFormat)) {
|
||||
if (!defaultFbo) {
|
||||
MGLOG_D("EnsureFrameRecordingStarted skipped: default render target unavailable");
|
||||
return;
|
||||
}
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null");
|
||||
m_renderPassManager->BeginRenderPass(commandBuffer, defaultRenderPass, defaultFramebuffer, defaultExtent);
|
||||
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*defaultFbo);
|
||||
Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry);
|
||||
MOBILEGL_ASSERT(started, "EnsureFrameRecordingStarted: StartRenderPass for default target failed");
|
||||
m_isMainRenderPassActive = true;
|
||||
m_activeRenderPass = defaultRenderPass;
|
||||
m_activeRenderExtent = defaultExtent;
|
||||
m_activeDepthStencilFormat = defaultDepthStencilFormat;
|
||||
m_activeRenderPass = renderPassEntry.renderPass;
|
||||
m_activeRenderExtent = {
|
||||
static_cast<Uint32>(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0),
|
||||
static_cast<Uint32>(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)};
|
||||
m_activeDepthStencilFormat = m_swapchainObject.GetDepthStencilFormat();
|
||||
m_activeRenderTargetIsDefault = true;
|
||||
m_activeDrawFboExternalIndex = drawFboExternalIndex;
|
||||
auto pendingIt = m_pendingClears.find(drawTargetKey);
|
||||
if (pendingIt != m_pendingClears.end()) {
|
||||
if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color);
|
||||
pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||
m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent,
|
||||
pendingIt->second.mask, pendingIt->second.depth,
|
||||
pendingIt->second.stencil, m_activeDepthStencilFormat);
|
||||
pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
if (pendingIt->second.mask == 0) {
|
||||
m_pendingClears.erase(pendingIt);
|
||||
}
|
||||
}
|
||||
ApplyPendingClearsForActiveTarget(commandBuffer, drawTargetKey);
|
||||
}
|
||||
|
||||
void VulkanRenderer::EndFrameRecordingIfNeeded() {
|
||||
@@ -1227,71 +1217,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired);
|
||||
TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired);
|
||||
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
VkExtent2D extent{};
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) {
|
||||
const auto* defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
const auto* defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO.get() : nullptr;
|
||||
if (defaultFbo == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*defaultFbo);
|
||||
const Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry);
|
||||
if (!started) {
|
||||
return false;
|
||||
}
|
||||
m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent);
|
||||
m_isMainRenderPassActive = true;
|
||||
m_activeRenderPass = renderPass;
|
||||
m_activeRenderExtent = extent;
|
||||
m_activeDepthStencilFormat = depthStencilFormat;
|
||||
m_activeRenderPass = renderPassEntry.renderPass;
|
||||
m_activeRenderExtent = {
|
||||
static_cast<Uint32>(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0),
|
||||
static_cast<Uint32>(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)};
|
||||
m_activeDepthStencilFormat = m_swapchainObject.GetDepthStencilFormat();
|
||||
m_activeRenderTargetIsDefault = true;
|
||||
m_activeDrawFboExternalIndex = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(m_framebufferManager != nullptr, "Present: framebuffer manager is null");
|
||||
|
||||
const auto pendingFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex);
|
||||
if (!pendingFbo) {
|
||||
return false;
|
||||
}
|
||||
VkRenderPass offscreenRenderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE;
|
||||
VkExtent2D offscreenExtent{};
|
||||
VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!EnsureOffscreenRenderTarget(targetFboExternalIndex, *pendingFbo, offscreenRenderPass,
|
||||
offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) {
|
||||
return false;
|
||||
}
|
||||
VkImage offscreenColorImage = VK_NULL_HANDLE;
|
||||
VkImageLayout* offscreenColorLayout = nullptr;
|
||||
VkImage offscreenDepthStencilImage = VK_NULL_HANDLE;
|
||||
VkImageLayout* offscreenDepthStencilLayout = nullptr;
|
||||
VkFormat offscreenDepthStencilStateFormat = VK_FORMAT_UNDEFINED;
|
||||
if (!m_framebufferManager->GetOffscreenRenderSurfaceState(
|
||||
targetFboExternalIndex, offscreenColorImage, offscreenColorLayout, offscreenDepthStencilImage,
|
||||
offscreenDepthStencilLayout, offscreenDepthStencilStateFormat) ||
|
||||
offscreenColorLayout == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, offscreenColorImage, *offscreenColorLayout,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT)) {
|
||||
return false;
|
||||
}
|
||||
if (offscreenDepthStencilImage != VK_NULL_HANDLE && offscreenDepthStencilLayout != nullptr) {
|
||||
VkImageAspectFlags depthStencilAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (offscreenDepthStencilStateFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
offscreenDepthStencilStateFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
depthStencilAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
if (!VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, offscreenDepthStencilImage, *offscreenDepthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
depthStencilAspectMask)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto swapchainOldLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
|
||||
if (swapchainOldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
|
||||
@@ -1316,12 +1266,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer,
|
||||
offscreenExtent);
|
||||
auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*pendingFbo);
|
||||
const Bool started = m_renderPassManager->StartRenderPass(commandBuffer, renderPassEntry);
|
||||
if (!started) {
|
||||
return false;
|
||||
}
|
||||
m_isMainRenderPassActive = true;
|
||||
m_activeRenderPass = offscreenRenderPass;
|
||||
m_activeRenderExtent = offscreenExtent;
|
||||
m_activeDepthStencilFormat = offscreenDepthStencilFormat;
|
||||
m_activeRenderPass = renderPassEntry.renderPass;
|
||||
m_activeRenderExtent = {
|
||||
static_cast<Uint32>(renderPassEntry.extent.x() > 0 ? renderPassEntry.extent.x() : 0),
|
||||
static_cast<Uint32>(renderPassEntry.extent.y() > 0 ? renderPassEntry.extent.y() : 0)};
|
||||
m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
m_activeRenderTargetIsDefault = false;
|
||||
m_activeDrawFboExternalIndex = targetFboExternalIndex;
|
||||
return true;
|
||||
@@ -1353,20 +1308,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((activePendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
m_renderPassManager->RecordColorClear(frame.commandBuffer, m_activeRenderExtent,
|
||||
activePendingIt->second.color);
|
||||
activePendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
if ((activePendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||
m_renderPassManager->RecordDepthStencilClear(
|
||||
frame.commandBuffer, m_activeRenderExtent, activePendingIt->second.mask,
|
||||
activePendingIt->second.depth, activePendingIt->second.stencil, m_activeDepthStencilFormat);
|
||||
activePendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
if (activePendingIt->second.mask == 0) {
|
||||
m_pendingClears.erase(activePendingIt);
|
||||
}
|
||||
ApplyPendingClearsForActiveTarget(frame.commandBuffer, activeKey);
|
||||
}
|
||||
}
|
||||
EndFrameRecordingIfNeeded();
|
||||
@@ -1777,51 +1719,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_I("Command pool created");
|
||||
}
|
||||
|
||||
Bool VulkanRenderer::GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const {
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "GetDefaultRenderTargetForCurrentImage: manager is null");
|
||||
return m_renderPassManager->GetDefaultRenderTarget(m_imageIndexAcquired, outRenderPass, outFramebuffer,
|
||||
outExtent, outDepthStencilFormat);
|
||||
}
|
||||
|
||||
Bool VulkanRenderer::EnsureOffscreenRenderTarget(Uint glFboExternalIndex,
|
||||
const MG_State::GLState::FramebufferObject& glFbo,
|
||||
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) {
|
||||
MOBILEGL_ASSERT(m_framebufferManager != nullptr, "EnsureOffscreenRenderTarget: framebuffer manager is null");
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureOffscreenRenderTarget: render pass manager is null");
|
||||
|
||||
if (!m_framebufferManager->EnsureOffscreenColorTarget(glFboExternalIndex, glFbo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageView colorView = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageView depthStencilView = VK_NULL_HANDLE;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent{};
|
||||
if (!m_framebufferManager->GetOffscreenRenderSurface(glFboExternalIndex, colorView, colorFormat,
|
||||
depthStencilView, depthStencilFormat, extent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkRenderPassManager::OffscreenRenderTargetInfo targetInfo{};
|
||||
targetInfo.targetExternalIndex = glFboExternalIndex;
|
||||
targetInfo.targetVersion = glFbo.GetObjectVersion();
|
||||
targetInfo.colorView = colorView;
|
||||
targetInfo.colorFormat = colorFormat;
|
||||
targetInfo.depthStencilView = depthStencilView;
|
||||
targetInfo.depthStencilFormat = depthStencilFormat;
|
||||
targetInfo.extent = extent;
|
||||
if (!m_renderPassManager->EnsureOffscreenRenderTarget(targetInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_renderPassManager->GetOffscreenRenderTarget(glFboExternalIndex, outRenderPass, outFramebuffer,
|
||||
outExtent, outDepthStencilFormat);
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateSurface() {
|
||||
#if defined VK_USE_PLATFORM_ANDROID_KHR
|
||||
auto* nativeWindow = static_cast<ANativeWindow*>(m_window);
|
||||
@@ -1990,16 +1887,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static_cast<Uint32>(m_swapchainObject.GetImageCount())),
|
||||
"RecreateSwapchain, InitializeSwapchainSemaphores");
|
||||
MOBILEGL_ASSERT(m_renderPassManager != nullptr, "RecreateSwapchain: render pass manager is null");
|
||||
VkRenderPassManager::InitInfo renderPassInitInfo{};
|
||||
renderPassInitInfo.device = m_device;
|
||||
renderPassInitInfo.colorFormat = m_swapchainObject.GetSurfaceFormat().format;
|
||||
renderPassInitInfo.depthStencilFormat = m_swapchainObject.GetDepthStencilFormat();
|
||||
Bool ok = m_renderPassManager->Initialize(renderPassInitInfo);
|
||||
Bool ok = m_renderPassManager->Initialize();
|
||||
MOBILEGL_ASSERT(ok, "RecreateSwapchain: render pass manager initialization failed");
|
||||
ok = m_renderPassManager->RecreateDefaultFramebuffers(m_swapchainObject.GetImageViews(),
|
||||
m_swapchainObject.GetDepthStencilImageViews(),
|
||||
m_swapchainObject.GetExtent());
|
||||
MOBILEGL_ASSERT(ok, "RecreateSwapchain: default framebuffers initialization failed");
|
||||
if (m_pipelineFactory) {
|
||||
m_pipelineFactory->DestroyAll();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "UniformDescriptorBinder.h"
|
||||
#include "VertexInputStateFactory.h"
|
||||
#include "VkBufferObject.h"
|
||||
#include "VkRenderTargetManager.h"
|
||||
#include "VkClearManager.h"
|
||||
#include "VkRenderPassManager.h"
|
||||
#include "VkSamplerManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
@@ -143,7 +143,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UniquePtr<ProgramFactory> m_programFactory;
|
||||
UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder;
|
||||
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
|
||||
UniquePtr<VkRenderTargetManager> m_framebufferManager;
|
||||
UniquePtr<VkClearManager> m_clearManager;
|
||||
UniquePtr<VkRenderPassManager> m_renderPassManager;
|
||||
UniquePtr<VkTextureManager> m_textureManager;
|
||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||
@@ -160,11 +160,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void CreateSwapchain();
|
||||
void CreateCommandPool();
|
||||
void CreateFrameContexts();
|
||||
Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
||||
Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo,
|
||||
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat);
|
||||
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,
|
||||
Uint64 vertexInputHash,
|
||||
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
|
||||
@@ -177,6 +172,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkDeviceSize minCapacity, VkBufferUsageFlags usage);
|
||||
Bool UploadAndBindVertexStreams(const VertexInputStateFactory::BackendVertexInputState& vertexInputState,
|
||||
const DrawArrayPayload& payload, VkCommandBuffer commandBuffer);
|
||||
void ApplyPendingClearsForActiveTarget(VkCommandBuffer commandBuffer, Uint64 drawTargetKey);
|
||||
|
||||
void ShutdownSwapchain();
|
||||
|
||||
|
||||
@@ -0,0 +1,436 @@
|
||||
// MobileGL - MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "TextureEnumConverter.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
VkImageViewType ConvertTextureTargetToVkEnum(TextureTarget target) {
|
||||
switch (target) {
|
||||
case TextureTarget::Texture1D:
|
||||
return VK_IMAGE_VIEW_TYPE_1D;
|
||||
case TextureTarget::Texture2D:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureTarget::Texture3D:
|
||||
return VK_IMAGE_VIEW_TYPE_3D;
|
||||
case TextureTarget::TextureCubeMap:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureTarget::Texture2DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case TextureTarget::Texture2DMultisample:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureTarget::TextureCubeMapArray:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
case TextureTarget::Texture1DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
case TextureTarget::TextureRectangle:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureTarget::Texture2DMultisampleArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case TextureTarget::TextureBuffer:
|
||||
default:
|
||||
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat ConvertTextureInputFormatToVkEnum(TextureInputFormat format) {
|
||||
switch (format) {
|
||||
case TextureInputFormat::Red:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case TextureInputFormat::RG:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case TextureInputFormat::RGB:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case TextureInputFormat::BGR:
|
||||
return VK_FORMAT_B8G8R8_UNORM;
|
||||
case TextureInputFormat::RGBA:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureInputFormat::BGRA:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case TextureInputFormat::RInteger:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case TextureInputFormat::RGInteger:
|
||||
return VK_FORMAT_R8G8_UINT;
|
||||
case TextureInputFormat::RGBInteger:
|
||||
return VK_FORMAT_R8G8B8_UINT;
|
||||
case TextureInputFormat::BGRInteger:
|
||||
return VK_FORMAT_B8G8R8_UINT;
|
||||
case TextureInputFormat::RGBAInteger:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case TextureInputFormat::BGRAInteger:
|
||||
return VK_FORMAT_B8G8R8A8_UINT;
|
||||
case TextureInputFormat::StencilIndex:
|
||||
return VK_FORMAT_S8_UINT;
|
||||
case TextureInputFormat::DepthComponent:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case TextureInputFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat ConvertTextureInternalFormatToVkEnum(TextureInternalFormat format) {
|
||||
switch (format) {
|
||||
case TextureInternalFormat::R8:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case TextureInternalFormat::R8Snorm:
|
||||
return VK_FORMAT_R8_SNORM;
|
||||
case TextureInternalFormat::R16:
|
||||
return VK_FORMAT_R16_UNORM;
|
||||
case TextureInternalFormat::R16Snorm:
|
||||
return VK_FORMAT_R16_SNORM;
|
||||
case TextureInternalFormat::RG8:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case TextureInternalFormat::RG8Snorm:
|
||||
return VK_FORMAT_R8G8_SNORM;
|
||||
case TextureInternalFormat::RG16:
|
||||
return VK_FORMAT_R16G16_UNORM;
|
||||
case TextureInternalFormat::RG16Snorm:
|
||||
return VK_FORMAT_R16G16_SNORM;
|
||||
case TextureInternalFormat::R3G3B2:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB4:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB5:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB8:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case TextureInternalFormat::RGB8Snorm:
|
||||
return VK_FORMAT_R8G8B8_SNORM;
|
||||
case TextureInternalFormat::RGB10:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB12:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB16:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGB16Snorm:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGBA2:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGBA4:
|
||||
return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
case TextureInternalFormat::RGB5A1:
|
||||
return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
|
||||
case TextureInternalFormat::RGBA8:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureInternalFormat::RGBA8Snorm:
|
||||
return VK_FORMAT_R8G8B8A8_SNORM;
|
||||
case TextureInternalFormat::RGB10A2:
|
||||
return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||
case TextureInternalFormat::RGB10A2UI:
|
||||
return VK_FORMAT_A2R10G10B10_UINT_PACK32;
|
||||
case TextureInternalFormat::RGBA12:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
case TextureInternalFormat::RGBA16:
|
||||
return VK_FORMAT_R16G16B16A16_UNORM;
|
||||
case TextureInternalFormat::SRGB8:
|
||||
return VK_FORMAT_R8G8B8_SRGB;
|
||||
case TextureInternalFormat::SRGB8Alpha8:
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
case TextureInternalFormat::R16F:
|
||||
return VK_FORMAT_R16_SFLOAT;
|
||||
case TextureInternalFormat::RG16F:
|
||||
return VK_FORMAT_R16G16_SFLOAT;
|
||||
case TextureInternalFormat::RGB16F:
|
||||
return VK_FORMAT_R16G16B16_SFLOAT;
|
||||
case TextureInternalFormat::RGBA16F:
|
||||
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case TextureInternalFormat::R32F:
|
||||
return VK_FORMAT_R32_SFLOAT;
|
||||
case TextureInternalFormat::RG32F:
|
||||
return VK_FORMAT_R32G32_SFLOAT;
|
||||
case TextureInternalFormat::RGB32F:
|
||||
return VK_FORMAT_R32G32B32_SFLOAT;
|
||||
case TextureInternalFormat::RGBA32F:
|
||||
return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case TextureInternalFormat::R11FG11FB10F:
|
||||
return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
case TextureInternalFormat::RGB9E5:
|
||||
return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32;
|
||||
case TextureInternalFormat::R8I:
|
||||
return VK_FORMAT_R8_SINT;
|
||||
case TextureInternalFormat::R8UI:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case TextureInternalFormat::R16I:
|
||||
return VK_FORMAT_R16_SINT;
|
||||
case TextureInternalFormat::R16UI:
|
||||
return VK_FORMAT_R16_UINT;
|
||||
case TextureInternalFormat::R32I:
|
||||
return VK_FORMAT_R32_SINT;
|
||||
case TextureInternalFormat::R32UI:
|
||||
return VK_FORMAT_R32_UINT;
|
||||
case TextureInternalFormat::RG8I:
|
||||
return VK_FORMAT_R8G8_SINT;
|
||||
case TextureInternalFormat::RG8UI:
|
||||
return VK_FORMAT_R8G8_UINT;
|
||||
case TextureInternalFormat::RG16I:
|
||||
return VK_FORMAT_R16G16_SINT;
|
||||
case TextureInternalFormat::RG16UI:
|
||||
return VK_FORMAT_R16G16_UINT;
|
||||
case TextureInternalFormat::RG32I:
|
||||
return VK_FORMAT_R32G32_SINT;
|
||||
case TextureInternalFormat::RG32UI:
|
||||
return VK_FORMAT_R32G32_UINT;
|
||||
case TextureInternalFormat::RGB8I:
|
||||
return VK_FORMAT_R8G8B8_SINT;
|
||||
case TextureInternalFormat::RGB8UI:
|
||||
return VK_FORMAT_R8G8B8_UINT;
|
||||
case TextureInternalFormat::RGB16I:
|
||||
return VK_FORMAT_R16G16B16_SINT;
|
||||
case TextureInternalFormat::RGB16UI:
|
||||
return VK_FORMAT_R16G16B16_UINT;
|
||||
case TextureInternalFormat::RGB32I:
|
||||
return VK_FORMAT_R32G32B32_SINT;
|
||||
case TextureInternalFormat::RGB32UI:
|
||||
return VK_FORMAT_R32G32B32_UINT;
|
||||
case TextureInternalFormat::RGBA8I:
|
||||
return VK_FORMAT_R8G8B8A8_SINT;
|
||||
case TextureInternalFormat::RGBA8UI:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case TextureInternalFormat::RGBA16I:
|
||||
return VK_FORMAT_R16G16B16A16_SINT;
|
||||
case TextureInternalFormat::RGBA16UI:
|
||||
return VK_FORMAT_R16G16B16A16_UINT;
|
||||
case TextureInternalFormat::RGBA32I:
|
||||
return VK_FORMAT_R32G32B32A32_SINT;
|
||||
case TextureInternalFormat::RGBA32UI:
|
||||
return VK_FORMAT_R32G32B32A32_UINT;
|
||||
case TextureInternalFormat::DepthComponent:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case TextureInternalFormat::DepthComponent16:
|
||||
return VK_FORMAT_D16_UNORM;
|
||||
case TextureInternalFormat::DepthComponent24:
|
||||
return VK_FORMAT_X8_D24_UNORM_PACK32;
|
||||
case TextureInternalFormat::DepthComponent32F:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
case TextureInternalFormat::DepthComponent32:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case TextureInternalFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TextureInternalFormat::Red:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case TextureInternalFormat::RG:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case TextureInternalFormat::RGB:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case TextureInternalFormat::RGBA:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat ConvertTexturePixelDataTypeToVkEnum(TexturePixelDataType type) {
|
||||
switch (type) {
|
||||
case TexturePixelDataType::UnsignedByte:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case TexturePixelDataType::Byte:
|
||||
return VK_FORMAT_R8_SINT;
|
||||
case TexturePixelDataType::UnsignedShort:
|
||||
return VK_FORMAT_R16_UINT;
|
||||
case TexturePixelDataType::Short:
|
||||
return VK_FORMAT_R16_SINT;
|
||||
case TexturePixelDataType::UnsignedInt:
|
||||
return VK_FORMAT_R32_UINT;
|
||||
case TexturePixelDataType::Int:
|
||||
return VK_FORMAT_R32_SINT;
|
||||
case TexturePixelDataType::Float:
|
||||
return VK_FORMAT_R32_SFLOAT;
|
||||
case TexturePixelDataType::HalfFloat:
|
||||
return VK_FORMAT_R16_SFLOAT;
|
||||
case TexturePixelDataType::UnsignedInt248:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TexturePixelDataType::UnsignedByte332:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case TexturePixelDataType::UnsignedByte233Rev:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case TexturePixelDataType::UnsignedShort565:
|
||||
return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedShort565Rev:
|
||||
return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedShort4444:
|
||||
return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedShort4444Rev:
|
||||
return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedShort5551:
|
||||
return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedShort1555Rev:
|
||||
return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
|
||||
case TexturePixelDataType::UnsignedInt8888:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case TexturePixelDataType::UnsignedInt8888Rev:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case TexturePixelDataType::UnsignedInt1010102:
|
||||
return VK_FORMAT_A2R10G10B10_UINT_PACK32;
|
||||
case TexturePixelDataType::UnsignedInt2101010Rev:
|
||||
return VK_FORMAT_A2R10G10B10_UINT_PACK32;
|
||||
case TexturePixelDataType::UnsignedInt101111Rev:
|
||||
return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
case TexturePixelDataType::UnsignedInt5999Rev:
|
||||
return VK_FORMAT_E5B9G9R9_UFLOAT_PACK32;
|
||||
case TexturePixelDataType::Float32UnsignedInt248Rev:
|
||||
return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkImageViewType ConvertTextureUploadTargetToVkEnum(TextureUploadTarget target) {
|
||||
switch (target) {
|
||||
case TextureUploadTarget::Texture2D:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::Texture1D:
|
||||
return VK_IMAGE_VIEW_TYPE_1D;
|
||||
case TextureUploadTarget::Texture3D:
|
||||
return VK_IMAGE_VIEW_TYPE_3D;
|
||||
case TextureUploadTarget::ProxyTexture2D:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::Texture1DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
case TextureUploadTarget::ProxyTexture1DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
case TextureUploadTarget::TextureRectangle:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::ProxyTextureRectangle:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::CubeMapPositiveX:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::CubeMapNegativeX:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::CubeMapPositiveY:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::CubeMapNegativeY:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::CubeMapPositiveZ:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::CubeMapNegativeZ:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::ProxyCubeMap:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
case TextureUploadTarget::Texture2DMultisample:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::ProxyTexture2DMultisample:
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case TextureUploadTarget::CubeMapArray:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
case TextureUploadTarget::ProxyCubeMapArray:
|
||||
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||
case TextureUploadTarget::Texture2DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case TextureUploadTarget::ProxyTexture2DArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case TextureUploadTarget::Texture2DMultisampleArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
default:
|
||||
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
|
||||
VkFilter ConvertSamplerFilterModeToVkEnum(SamplerFilterMode filter, SamplerMipmapMode mipmap) {
|
||||
(void)mipmap;
|
||||
switch (filter) {
|
||||
case SamplerFilterMode::Nearest:
|
||||
return VK_FILTER_NEAREST;
|
||||
case SamplerFilterMode::Linear:
|
||||
return VK_FILTER_LINEAR;
|
||||
default:
|
||||
return VK_FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerMipmapMode ConvertSamplerMipmapModeToVkEnum(SamplerMipmapMode v) {
|
||||
switch (v) {
|
||||
case SamplerMipmapMode::Nearest:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMipmapMode::Linear:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
case SamplerMipmapMode::None:
|
||||
default:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerAddressMode ConvertSamplerWrapModeToVkEnum(SamplerWrapMode v) {
|
||||
switch (v) {
|
||||
case SamplerWrapMode::ClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case SamplerWrapMode::MirroredRepeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case SamplerWrapMode::Repeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case SamplerWrapMode::ClampToBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case SamplerWrapMode::MirrorClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
default:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
VkBool32 ConvertSamplerCompareModeToVkEnum(SamplerCompareMode v) {
|
||||
switch (v) {
|
||||
case SamplerCompareMode::None:
|
||||
return VK_FALSE;
|
||||
case SamplerCompareMode::CompareToTexture:
|
||||
return VK_TRUE;
|
||||
default:
|
||||
return VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VkCompareOp ConvertSamplerCompareFuncToVkEnum(SamplerCompareFunc v) {
|
||||
switch (v) {
|
||||
case SamplerCompareFunc::Never:
|
||||
return VK_COMPARE_OP_NEVER;
|
||||
case SamplerCompareFunc::Less:
|
||||
return VK_COMPARE_OP_LESS;
|
||||
case SamplerCompareFunc::Equal:
|
||||
return VK_COMPARE_OP_EQUAL;
|
||||
case SamplerCompareFunc::LessEqual:
|
||||
return VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
case SamplerCompareFunc::Greater:
|
||||
return VK_COMPARE_OP_GREATER;
|
||||
case SamplerCompareFunc::NotEqual:
|
||||
return VK_COMPARE_OP_NOT_EQUAL;
|
||||
case SamplerCompareFunc::GreaterEqual:
|
||||
return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||
case SamplerCompareFunc::Always:
|
||||
return VK_COMPARE_OP_ALWAYS;
|
||||
default:
|
||||
return VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
VkComponentSwizzle ConvertTextureSwizzleParamToVkEnum(TextureSwizzleParam v) {
|
||||
switch (v) {
|
||||
case TextureSwizzleParam::Red:
|
||||
return VK_COMPONENT_SWIZZLE_R;
|
||||
case TextureSwizzleParam::Green:
|
||||
return VK_COMPONENT_SWIZZLE_G;
|
||||
case TextureSwizzleParam::Blue:
|
||||
return VK_COMPONENT_SWIZZLE_B;
|
||||
case TextureSwizzleParam::Alpha:
|
||||
return VK_COMPONENT_SWIZZLE_A;
|
||||
case TextureSwizzleParam::Zero:
|
||||
return VK_COMPONENT_SWIZZLE_ZERO;
|
||||
case TextureSwizzleParam::One:
|
||||
return VK_COMPONENT_SWIZZLE_ONE;
|
||||
default:
|
||||
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
}
|
||||
}
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,27 @@
|
||||
// MobileGL - MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
VkImageViewType ConvertTextureTargetToVkEnum(TextureTarget target);
|
||||
VkFormat ConvertTextureInputFormatToVkEnum(TextureInputFormat format);
|
||||
VkFormat ConvertTextureInternalFormatToVkEnum(TextureInternalFormat internalformat);
|
||||
VkFormat ConvertTexturePixelDataTypeToVkEnum(TexturePixelDataType type);
|
||||
VkImageViewType ConvertTextureUploadTargetToVkEnum(TextureUploadTarget target);
|
||||
VkFilter ConvertSamplerFilterModeToVkEnum(SamplerFilterMode filter, SamplerMipmapMode mipmap);
|
||||
VkSamplerMipmapMode ConvertSamplerMipmapModeToVkEnum(SamplerMipmapMode value);
|
||||
VkSamplerAddressMode ConvertSamplerWrapModeToVkEnum(SamplerWrapMode value);
|
||||
VkBool32 ConvertSamplerCompareModeToVkEnum(SamplerCompareMode value);
|
||||
VkCompareOp ConvertSamplerCompareFuncToVkEnum(SamplerCompareFunc value);
|
||||
VkComponentSwizzle ConvertTextureSwizzleParamToVkEnum(TextureSwizzleParam value);
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
Reference in New Issue
Block a user