mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-10 21:28:32 +09:00
[Fix] (MG_Impl, MG_State, MG_Backend, MG_Util): Do source audit by Codex.
This commit is contained in:
@@ -207,5 +207,53 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
|
||||
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
|
||||
m_dynamicParameters.AliasedLineWidthRangeMin = m_vulkanCaps.AliasedLineWidthRangeMin;
|
||||
m_dynamicParameters.AliasedLineWidthRangeMax = m_vulkanCaps.AliasedLineWidthRangeMax;
|
||||
m_dynamicParameters.SmoothLineWidthRangeMin = m_vulkanCaps.SmoothLineWidthRangeMin;
|
||||
m_dynamicParameters.SmoothLineWidthRangeMax = m_vulkanCaps.SmoothLineWidthRangeMax;
|
||||
m_dynamicParameters.SmoothLineWidthGranularity = m_vulkanCaps.SmoothLineWidthGranularity;
|
||||
m_dynamicParameters.PointSizeRangeMin = m_vulkanCaps.PointSizeRangeMin;
|
||||
m_dynamicParameters.PointSizeRangeMax = m_vulkanCaps.PointSizeRangeMax;
|
||||
m_dynamicParameters.PointSizeGranularity = m_vulkanCaps.PointSizeGranularity;
|
||||
m_dynamicParameters.Max3DTextureSize = m_vulkanCaps.Max3DTextureSize;
|
||||
m_dynamicParameters.MaxArrayTextureLayers = m_vulkanCaps.MaxArrayTextureLayers;
|
||||
m_dynamicParameters.MaxCubeMapTextureSize = m_vulkanCaps.MaxCubeMapTextureSize;
|
||||
m_dynamicParameters.MaxFramebufferWidth = m_vulkanCaps.MaxFramebufferWidth;
|
||||
m_dynamicParameters.MaxFramebufferHeight = m_vulkanCaps.MaxFramebufferHeight;
|
||||
m_dynamicParameters.MaxFramebufferLayers = m_vulkanCaps.MaxFramebufferLayers;
|
||||
m_dynamicParameters.MaxRenderbufferSize = m_vulkanCaps.MaxRenderbufferSize;
|
||||
m_dynamicParameters.MaxTextureSize = m_vulkanCaps.MaxTextureSize;
|
||||
m_dynamicParameters.MaxColorTextureSamples = m_vulkanCaps.MaxColorTextureSamples;
|
||||
m_dynamicParameters.MaxDepthTextureSamples = m_vulkanCaps.MaxDepthTextureSamples;
|
||||
m_dynamicParameters.MaxFramebufferSamples = m_vulkanCaps.MaxFramebufferSamples;
|
||||
m_dynamicParameters.MaxIntegerSamples = m_vulkanCaps.MaxIntegerSamples;
|
||||
m_dynamicParameters.MaxSamples = m_vulkanCaps.MaxSamples;
|
||||
m_dynamicParameters.MaxSampleMaskWords = m_vulkanCaps.MaxSampleMaskWords;
|
||||
m_dynamicParameters.MaxTextureImageUnits = m_vulkanCaps.MaxTextureImageUnits;
|
||||
m_dynamicParameters.MaxVertexTextureImageUnits = m_vulkanCaps.MaxVertexTextureImageUnits;
|
||||
m_dynamicParameters.MaxComputeTextureImageUnits = m_vulkanCaps.MaxComputeTextureImageUnits;
|
||||
m_dynamicParameters.MaxCombinedTextureImageUnits = m_vulkanCaps.MaxCombinedTextureImageUnits;
|
||||
m_dynamicParameters.MaxVertexAttribs = m_vulkanCaps.MaxVertexAttribs;
|
||||
m_dynamicParameters.MaxComputeShaderStorageBlocks = m_vulkanCaps.MaxComputeShaderStorageBlocks;
|
||||
m_dynamicParameters.MaxCombinedShaderStorageBlocks = m_vulkanCaps.MaxCombinedShaderStorageBlocks;
|
||||
m_dynamicParameters.MaxComputeUniformBlocks = m_vulkanCaps.MaxComputeUniformBlocks;
|
||||
m_dynamicParameters.MaxComputeWorkGroupInvocations = m_vulkanCaps.MaxComputeWorkGroupInvocations;
|
||||
m_dynamicParameters.MaxShaderStorageBufferBindings = m_vulkanCaps.MaxShaderStorageBufferBindings;
|
||||
m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize;
|
||||
m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings;
|
||||
m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize;
|
||||
m_dynamicParameters.MaxImageUnits = m_vulkanCaps.MaxImageUnits;
|
||||
m_dynamicParameters.MaxCombinedImageUniforms = m_vulkanCaps.MaxCombinedImageUniforms;
|
||||
m_dynamicParameters.MaxComputeImageUniforms = m_vulkanCaps.MaxComputeImageUniforms;
|
||||
m_dynamicParameters.MaxDrawBuffers = m_vulkanCaps.MaxDrawBuffers;
|
||||
m_dynamicParameters.MaxColorAttachments = m_vulkanCaps.MaxColorAttachments;
|
||||
m_dynamicParameters.MaxClipDistances = m_vulkanCaps.MaxClipDistances;
|
||||
m_dynamicParameters.MaxViewports = m_vulkanCaps.MaxViewports;
|
||||
m_dynamicParameters.MaxViewportWidth = m_vulkanCaps.MaxViewportWidth;
|
||||
m_dynamicParameters.MaxViewportHeight = m_vulkanCaps.MaxViewportHeight;
|
||||
m_dynamicParameters.ViewportBoundsRangeMin = m_vulkanCaps.ViewportBoundsRangeMin;
|
||||
m_dynamicParameters.ViewportBoundsRangeMax = m_vulkanCaps.ViewportBoundsRangeMax;
|
||||
m_dynamicParameters.ViewportSubpixelBits = m_vulkanCaps.ViewportSubpixelBits;
|
||||
m_dynamicParameters.SupportsWideLines = m_vulkanCaps.SupportsWideLines;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -188,18 +188,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return packet;
|
||||
}
|
||||
|
||||
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
|
||||
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, Uint32 imageIndex) const {
|
||||
AssertValidSwapchainImageIndex(imageIndex);
|
||||
PresentInfoPacket packet{};
|
||||
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
|
||||
packet.swapchain = swapchain;
|
||||
packet.imageIndex = &imageIndex;
|
||||
packet.imageIndex = imageIndex;
|
||||
|
||||
packet.presentInfo.waitSemaphoreCount = 1;
|
||||
packet.presentInfo.pWaitSemaphores = &packet.waitSemaphore;
|
||||
packet.presentInfo.swapchainCount = 1;
|
||||
packet.presentInfo.pSwapchains = &packet.swapchain;
|
||||
packet.presentInfo.pImageIndices = packet.imageIndex;
|
||||
packet.presentInfo.pImageIndices = &packet.imageIndex;
|
||||
packet.presentInfo.pResults = nullptr;
|
||||
return packet;
|
||||
}
|
||||
@@ -212,13 +212,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = vkResetFences(device, 1, &frame.imageInFlightFence);
|
||||
result = vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
|
||||
&outImageIndex);
|
||||
if (result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
|
||||
&outImageIndex);
|
||||
return vkResetFences(device, 1, &frame.imageInFlightFence);
|
||||
}
|
||||
|
||||
Uint32 FrameContext::GetCurrentFrameIndex() const {
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct PresentInfoPacket {
|
||||
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||
const Uint32* imageIndex = nullptr;
|
||||
Uint32 imageIndex = 0;
|
||||
VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
|
||||
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
|
||||
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
|
||||
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, Uint32 imageIndex) const;
|
||||
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
|
||||
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
|
||||
|
||||
|
||||
@@ -39,7 +39,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthBiasEnable, sizeof(payload.depthBiasEnable)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.rasterizerDiscardEnable, sizeof(payload.rasterizerDiscardEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.logicOpEnable, sizeof(payload.logicOpEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.stencilTestEnable, sizeof(payload.stencilTestEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.logicOp, sizeof(payload.logicOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontStencilFailOp, sizeof(payload.frontStencilFailOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontStencilPassOp, sizeof(payload.frontStencilPassOp)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.frontStencilDepthFailOp, sizeof(payload.frontStencilDepthFailOp)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.frontStencilCompareOp, sizeof(payload.frontStencilCompareOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.backStencilFailOp, sizeof(payload.backStencilFailOp)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.backStencilPassOp, sizeof(payload.backStencilPassOp)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.backStencilDepthFailOp, sizeof(payload.backStencilDepthFailOp)));
|
||||
XXHASH_VERIFY(
|
||||
XXH64_update(m_hashState, &payload.backStencilCompareOp, sizeof(payload.backStencilCompareOp)));
|
||||
if (payload.colorAttachmentCount > 0) {
|
||||
XXHASH_VERIFY(XXH64_update(
|
||||
m_hashState,
|
||||
@@ -86,7 +104,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
static constexpr VkDynamicState kDynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
||||
VK_DYNAMIC_STATE_DEPTH_BIAS,
|
||||
VK_DYNAMIC_STATE_LINE_WIDTH,
|
||||
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
||||
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
|
||||
VK_DYNAMIC_STATE_STENCIL_REFERENCE
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState{};
|
||||
@@ -105,6 +129,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
raster.cullMode = payload.cullMode;
|
||||
raster.frontFace = payload.frontFace;
|
||||
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
|
||||
raster.rasterizerDiscardEnable = payload.rasterizerDiscardEnable ? VK_TRUE : VK_FALSE;
|
||||
raster.lineWidth = 1.0f;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
||||
@@ -115,13 +141,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
depthStencil.depthWriteEnable = payload.depthWriteEnable ? VK_TRUE : VK_FALSE;
|
||||
depthStencil.depthCompareOp = payload.depthCompareOp;
|
||||
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
||||
depthStencil.stencilTestEnable = VK_FALSE;
|
||||
depthStencil.stencilTestEnable = payload.stencilTestEnable ? VK_TRUE : VK_FALSE;
|
||||
if (payload.stencilTestEnable) {
|
||||
depthStencil.front.failOp = payload.frontStencilFailOp;
|
||||
depthStencil.front.passOp = payload.frontStencilPassOp;
|
||||
depthStencil.front.depthFailOp = payload.frontStencilDepthFailOp;
|
||||
depthStencil.front.compareOp = payload.frontStencilCompareOp;
|
||||
depthStencil.front.compareMask = 0xffffffffu;
|
||||
depthStencil.front.writeMask = 0xffffffffu;
|
||||
depthStencil.front.reference = 0;
|
||||
depthStencil.back.failOp = payload.backStencilFailOp;
|
||||
depthStencil.back.passOp = payload.backStencilPassOp;
|
||||
depthStencil.back.depthFailOp = payload.backStencilDepthFailOp;
|
||||
depthStencil.back.compareOp = payload.backStencilCompareOp;
|
||||
depthStencil.back.compareMask = 0xffffffffu;
|
||||
depthStencil.back.writeMask = 0xffffffffu;
|
||||
depthStencil.back.reference = 0;
|
||||
}
|
||||
|
||||
Vector<VkPipelineColorBlendAttachmentState> colorAttachments(payload.colorAttachmentCount);
|
||||
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
|
||||
colorAttachments[i] = payload.colorBlendAttachments[i];
|
||||
}
|
||||
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||
blend.logicOpEnable = payload.logicOpEnable ? VK_TRUE : VK_FALSE;
|
||||
blend.logicOp = payload.logicOp;
|
||||
blend.attachmentCount = payload.colorAttachmentCount;
|
||||
blend.pAttachments = colorAttachments.empty() ? nullptr : colorAttachments.data();
|
||||
|
||||
|
||||
@@ -32,7 +32,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
Bool depthTestEnable = false;
|
||||
Bool depthWriteEnable = false;
|
||||
Bool depthBiasEnable = false;
|
||||
Bool rasterizerDiscardEnable = false;
|
||||
Bool logicOpEnable = false;
|
||||
Bool stencilTestEnable = false;
|
||||
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
VkLogicOp logicOp = VK_LOGIC_OP_COPY;
|
||||
VkStencilOp frontStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
VkStencilOp frontStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
VkStencilOp frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
VkCompareOp frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
VkStencilOp backStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
VkStencilOp backStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
VkStencilOp backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
VkCompareOp backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
Array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments{};
|
||||
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
|
||||
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
|
||||
|
||||
@@ -153,7 +153,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_I("Picked present mode: %s", string_VkPresentModeKHR(presentMode));
|
||||
|
||||
const auto& swapchainCaps = swapchainCapabilities.capabilities;
|
||||
const auto targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
|
||||
Uint32 targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
|
||||
if (swapchainCaps.maxImageCount != 0) {
|
||||
targetImageCount = std::min(targetImageCount, swapchainCaps.maxImageCount);
|
||||
}
|
||||
MGLOG_I("Set minImageCount = %u", targetImageCount);
|
||||
MGLOG_I("Swapchain currentTransform = %s",
|
||||
string_VkSurfaceTransformFlagBitsKHR(swapchainCaps.currentTransform));
|
||||
@@ -234,11 +237,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// Properly initialize Default FBO here
|
||||
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
const Int extentWidth = static_cast<Int>(createInfo.imageExtent.width);
|
||||
const Int extentHeight = static_cast<Int>(createInfo.imageExtent.height);
|
||||
const SizeT defaultAttachmentByteSize =
|
||||
static_cast<SizeT>(createInfo.imageExtent.width) * static_cast<SizeT>(createInfo.imageExtent.height) * 4;
|
||||
|
||||
auto* colorTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->colorAttachment.get());
|
||||
colorTex->AllocateStorage(
|
||||
TextureUploadTarget::Texture2D, 0, {
|
||||
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||
createInfo.imageExtent.width * (Int)createInfo.imageExtent.height * 4}); // TODO: 4 is format size
|
||||
{extentWidth, extentHeight, 1},
|
||||
defaultAttachmentByteSize}); // TODO: 4 is format size
|
||||
TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||
switch (m_depthStencilFormat) {
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
@@ -257,8 +265,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
auto* depthTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->depthAttachment.get());
|
||||
depthTex->SetInternalFormat(depthFormat);
|
||||
depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {
|
||||
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||
createInfo.imageExtent.width * createInfo.imageExtent.width * 4}); // TODO: 4 is format size
|
||||
{extentWidth, extentHeight, 1},
|
||||
defaultAttachmentByteSize}); // TODO: 4 is format size
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,19 @@
|
||||
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static SharedPtr<MG_State::GLState::ITextureObject> GetClearableAttachmentTexture(
|
||||
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
|
||||
return target >= TextureUploadTarget::CubeMapPositiveX &&
|
||||
target <= TextureUploadTarget::CubeMapNegativeZ;
|
||||
}
|
||||
|
||||
static Uint32 ResolveAttachmentBaseArrayLayer(TextureUploadTarget target) {
|
||||
if (!IsCubeMapFaceUploadTarget(target)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<Uint32>(target) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
|
||||
}
|
||||
|
||||
static const MG_State::GLState::FramebufferAttachmentObject* GetClearableAttachment(
|
||||
const MG_State::GLState::FramebufferObject& drawFbo, FramebufferAttachmentType attachmentType) {
|
||||
if (attachmentType == FramebufferAttachmentType::None) {
|
||||
return nullptr;
|
||||
@@ -23,7 +35,30 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return attachment.GetTexture();
|
||||
return &attachment;
|
||||
}
|
||||
|
||||
PendingClearKey VkClearManager::MakePendingClearKey(MG_State::GLState::ITextureObject* texture, Uint32 mipLevel,
|
||||
Uint32 baseArrayLayer, Uint32 layerCount) {
|
||||
return PendingClearKey {
|
||||
.texture = texture,
|
||||
.mipLevel = mipLevel,
|
||||
.baseArrayLayer = baseArrayLayer,
|
||||
.layerCount = layerCount,
|
||||
};
|
||||
}
|
||||
|
||||
PendingClearKey VkClearManager::MakePendingClearKey(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
MOBILEGL_ASSERT(attachment.IsTexture() && !attachment.IsRenderbuffer(),
|
||||
"MakePendingClearKey requires a texture framebuffer attachment");
|
||||
auto* texture = attachment.GetTexture().get();
|
||||
MOBILEGL_ASSERT(texture != nullptr, "MakePendingClearKey: texture attachment resolved to null");
|
||||
const Uint32 mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
|
||||
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
|
||||
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(uploadTarget);
|
||||
const Uint32 layerCount = IsCubeMapFaceUploadTarget(uploadTarget) ? 1u : 1u;
|
||||
return MakePendingClearKey(texture, mipLevel, baseArrayLayer, layerCount);
|
||||
}
|
||||
|
||||
Bool VkClearManager::Initialize() {
|
||||
@@ -40,46 +75,46 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
auto& drawbufs = drawFbo.GetDrawBuffers();
|
||||
// This should automatically work on default & offscreen FBO
|
||||
for (auto drawbuf: drawbufs) {
|
||||
auto texture = GetClearableAttachmentTexture(drawFbo, drawbuf);
|
||||
if (!texture) {
|
||||
const auto* attachment = GetClearableAttachment(drawFbo, drawbuf);
|
||||
if (!attachment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QueueClear({
|
||||
.mask = GL_COLOR_BUFFER_BIT,
|
||||
.color = clearPayload.color
|
||||
}, texture);
|
||||
}, *attachment);
|
||||
|
||||
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
|
||||
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
|
||||
texture->GetExternalIndex(),
|
||||
attachment->GetTexture()->GetExternalIndex(),
|
||||
clearPayload.color[0], clearPayload.color[1], clearPayload.color[2], clearPayload.color[3]);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & GL_DEPTH_BUFFER_BIT) {
|
||||
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Depth);
|
||||
if (texture) {
|
||||
const auto* attachment = GetClearableAttachment(drawFbo, FramebufferAttachmentType::Depth);
|
||||
if (attachment) {
|
||||
QueueClear({
|
||||
.mask = GL_DEPTH_BUFFER_BIT,
|
||||
.depth = clearPayload.depth,
|
||||
}, texture);
|
||||
}, *attachment);
|
||||
|
||||
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
|
||||
texture->GetExternalIndex(), clearPayload.depth);
|
||||
attachment->GetTexture()->GetExternalIndex(), clearPayload.depth);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & GL_STENCIL_BUFFER_BIT) {
|
||||
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Stencil);
|
||||
if (texture) {
|
||||
const auto* attachment = GetClearableAttachment(drawFbo, FramebufferAttachmentType::Stencil);
|
||||
if (attachment) {
|
||||
QueueClear({
|
||||
.mask = GL_STENCIL_BUFFER_BIT,
|
||||
.stencil = clearPayload.stencil,
|
||||
}, texture);
|
||||
}, *attachment);
|
||||
|
||||
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
|
||||
texture->GetExternalIndex(), clearPayload.stencil);
|
||||
attachment->GetTexture()->GetExternalIndex(), clearPayload.stencil);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +129,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return;
|
||||
auto* pTexture = weakTexturePtr.lock().get();
|
||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
||||
auto& pending = m_pendingClears[pTexture];
|
||||
auto& pending = m_pendingClears[MakePendingClearKey(pTexture)];
|
||||
pending.mask |= clearPayload.mask;
|
||||
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
|
||||
pending.color = clearPayload.color;
|
||||
}
|
||||
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
|
||||
pending.depth = clearPayload.depth;
|
||||
}
|
||||
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
|
||||
pending.stencil = clearPayload.stencil;
|
||||
}
|
||||
}
|
||||
|
||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
if (clearPayload.mask == 0 || !attachment.IsTexture() || attachment.IsRenderbuffer()) {
|
||||
return;
|
||||
}
|
||||
const auto texture = attachment.GetTexture();
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
||||
if (weakTexturePtr.expired()) {
|
||||
return;
|
||||
}
|
||||
auto* pTexture = weakTexturePtr.lock().get();
|
||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
||||
auto& pending = m_pendingClears[MakePendingClearKey(attachment)];
|
||||
pending.mask |= clearPayload.mask;
|
||||
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
|
||||
pending.color = clearPayload.color;
|
||||
@@ -108,20 +171,40 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
return m_pendingClears.find(texture) != m_pendingClears.end();
|
||||
if (texture == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return std::any_of(m_pendingClears.begin(), m_pendingClears.end(),
|
||||
[texture](const auto& item) { return item.first.texture == texture; });
|
||||
}
|
||||
|
||||
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()) {
|
||||
MGLOG_D("%s: Failed getting pending clear for texture %d", __func__, texture->GetExternalIndex());
|
||||
Bool VkClearManager::HasPendingClear(const PendingClearKey& key) {
|
||||
return key.texture != nullptr && m_pendingClears.find(key) != m_pendingClears.end();
|
||||
}
|
||||
|
||||
Bool VkClearManager::HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
|
||||
return false;
|
||||
}
|
||||
return HasPendingClear(MakePendingClearKey(attachment));
|
||||
}
|
||||
|
||||
Bool VkClearManager::GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload) {
|
||||
if (key.texture == nullptr || m_aliveObjects.find(key.texture) == m_aliveObjects.end()) {
|
||||
return false;
|
||||
}
|
||||
auto it = m_pendingClears.find(key);
|
||||
if (it == m_pendingClears.end()) {
|
||||
MGLOG_D("%s: Failed getting pending clear for texture %d mip=%u layer=%u count=%u", __func__,
|
||||
key.texture ? key.texture->GetExternalIndex() : 0, key.mipLevel, key.baseArrayLayer, key.layerCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = m_pendingClears[texture];
|
||||
MGLOG_D("%s: Got pending clear for texture %d (%s), mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
||||
texture->GetExternalIndex(),
|
||||
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
|
||||
outPayload = it->second;
|
||||
MGLOG_D("%s: Got pending clear for texture %d (%s), mip=%u layer=%u count=%u mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
||||
key.texture->GetExternalIndex(),
|
||||
MG_Util::ConvertTextureInternalFormatToString(key.texture->GetFormat()).c_str(),
|
||||
key.mipLevel, key.baseArrayLayer, key.layerCount,
|
||||
static_cast<Uint32>(outPayload.mask),
|
||||
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
||||
outPayload.depth,
|
||||
@@ -129,10 +212,59 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkClearManager::GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
|
||||
ClearAttachmentPayload& outPayload) {
|
||||
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
|
||||
MGLOG_D("%s: Failed getting pending clear for non-texture framebuffer attachment", __func__);
|
||||
return false;
|
||||
}
|
||||
return GetPendingClear(MakePendingClearKey(attachment), outPayload);
|
||||
}
|
||||
|
||||
Bool VkClearManager::GetPendingClears(MG_State::GLState::ITextureObject* texture,
|
||||
Vector<PendingClearEntry>& outEntries) {
|
||||
outEntries.clear();
|
||||
if (texture == nullptr || m_aliveObjects.find(texture) == m_aliveObjects.end()) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& [key, payload] : m_pendingClears) {
|
||||
if (key.texture != texture) {
|
||||
continue;
|
||||
}
|
||||
outEntries.emplace_back(PendingClearEntry{.key = key, .payload = payload});
|
||||
}
|
||||
return !outEntries.empty();
|
||||
}
|
||||
|
||||
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
MGLOG_D("%s: Pop pending clear for texture %d", __func__, texture->GetExternalIndex());
|
||||
if (texture == nullptr) {
|
||||
return;
|
||||
}
|
||||
MGLOG_D("%s: Pop all pending clears for texture %d", __func__, texture->GetExternalIndex());
|
||||
m_aliveObjects.erase(texture);
|
||||
m_pendingClears.erase(texture);
|
||||
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end();) {
|
||||
if (it->first.texture == texture) {
|
||||
it = m_pendingClears.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VkClearManager::PopPendingClear(const PendingClearKey& key) {
|
||||
if (key.texture == nullptr) {
|
||||
return;
|
||||
}
|
||||
MGLOG_D("%s: Pop pending clear for texture %d mip=%u layer=%u count=%u", __func__,
|
||||
key.texture->GetExternalIndex(), key.mipLevel, key.baseArrayLayer, key.layerCount);
|
||||
m_pendingClears.erase(key);
|
||||
}
|
||||
|
||||
void VkClearManager::PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
|
||||
return;
|
||||
}
|
||||
PopPendingClear(MakePendingClearKey(attachment));
|
||||
}
|
||||
|
||||
SizeT VkClearManager::CollectGarbage() {
|
||||
@@ -145,7 +277,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
|
||||
auto current = it++;
|
||||
if (current->second.expired()) {
|
||||
m_pendingClears.erase(current->first);
|
||||
for (auto clearIt = m_pendingClears.begin(); clearIt != m_pendingClears.end();) {
|
||||
if (clearIt->first.texture == current->first) {
|
||||
clearIt = m_pendingClears.erase(clearIt);
|
||||
} else {
|
||||
++clearIt;
|
||||
}
|
||||
}
|
||||
m_aliveObjects.erase(current);
|
||||
++count;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,43 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 stencil = 0;
|
||||
};
|
||||
|
||||
struct PendingClearKey {
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
Uint32 mipLevel = 0;
|
||||
Uint32 baseArrayLayer = 0;
|
||||
Uint32 layerCount = 1;
|
||||
|
||||
Bool operator==(const PendingClearKey& other) const {
|
||||
return texture == other.texture && mipLevel == other.mipLevel &&
|
||||
baseArrayLayer == other.baseArrayLayer && layerCount == other.layerCount;
|
||||
}
|
||||
};
|
||||
|
||||
struct PendingClearEntry {
|
||||
PendingClearKey key{};
|
||||
ClearAttachmentPayload payload{};
|
||||
};
|
||||
|
||||
struct PendingClearKeyHash {
|
||||
SizeT operator()(const PendingClearKey& key) const {
|
||||
const SizeT textureHash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
|
||||
const SizeT mipHash = std::hash<Uint32>{}(key.mipLevel);
|
||||
const SizeT layerHash = std::hash<Uint32>{}(key.baseArrayLayer);
|
||||
const SizeT layerCountHash = std::hash<Uint32>{}(key.layerCount);
|
||||
SizeT hash = textureHash;
|
||||
hash ^= mipHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= layerHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= layerCountHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class VkClearManager {
|
||||
public:
|
||||
static PendingClearKey MakePendingClearKey(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||
static PendingClearKey MakePendingClearKey(MG_State::GLState::ITextureObject* texture, Uint32 mipLevel = 0,
|
||||
Uint32 baseArrayLayer = 0, Uint32 layerCount = 1);
|
||||
|
||||
Bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
@@ -38,13 +73,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void QueueClear(
|
||||
const ClearAttachmentPayload& clearPayload,
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
|
||||
void QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
||||
Bool HasPendingClear(const PendingClearKey& key);
|
||||
Bool HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||
Bool GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload);
|
||||
Bool GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
|
||||
ClearAttachmentPayload& outPayload);
|
||||
Bool GetPendingClears(MG_State::GLState::ITextureObject* texture, Vector<PendingClearEntry>& outEntries);
|
||||
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
void PopPendingClear(const PendingClearKey& key);
|
||||
void PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
Uint8 m_gcCounter = 0;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
|
||||
UnorderedMap<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -22,6 +22,32 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return requestedAlpha;
|
||||
}
|
||||
|
||||
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
|
||||
return target >= TextureUploadTarget::CubeMapPositiveX &&
|
||||
target <= TextureUploadTarget::CubeMapNegativeZ;
|
||||
}
|
||||
|
||||
static Uint32 ResolveAttachmentBaseArrayLayer(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
|
||||
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<Uint32>(uploadTarget) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
|
||||
}
|
||||
|
||||
static Uint32 ResolveAttachmentLayerCount(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
static_cast<void>(attachment);
|
||||
return 1u;
|
||||
}
|
||||
|
||||
static VkImageViewType ResolveAttachmentViewType(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachment,
|
||||
const VkTextureManager::TextureResource& resource) {
|
||||
return IsCubeMapFaceUploadTarget(attachment.GetTextureUploadTarget()) ?
|
||||
VK_IMAGE_VIEW_TYPE_2D :
|
||||
resource.viewType;
|
||||
}
|
||||
|
||||
static MG_State::GLState::ITextureObject* ResolveCompleteColorAttachmentTexture(
|
||||
const MG_State::GLState::FramebufferObject& fbo,
|
||||
FramebufferAttachmentType attachmentType,
|
||||
@@ -79,6 +105,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
void VkRenderPassManager::Shutdown() {
|
||||
m_renderPasses.clear();
|
||||
RenderPassEntry::s_textureResourcesScratch.clear();
|
||||
s_activeRenderPass = {};
|
||||
s_hasActiveRenderPass = false;
|
||||
}
|
||||
|
||||
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
||||
@@ -117,6 +147,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (att.IsTexture()) {
|
||||
const Int textureLevel = att.GetTextureLevel();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
|
||||
const TextureUploadTarget textureUploadTarget = att.GetTextureUploadTarget();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &textureUploadTarget, sizeof(textureUploadTarget)));
|
||||
|
||||
Uint64 imageIdentity = 0;
|
||||
auto* texture = att.GetTexture().get();
|
||||
@@ -129,11 +161,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
if (includePendingClear && att.IsTexture()) {
|
||||
auto* texture = att.GetTexture().get();
|
||||
auto hasClear = m_clearManager.HasPendingClear(texture);
|
||||
const auto pendingClearKey = VkClearManager::MakePendingClearKey(att);
|
||||
auto hasClear = m_clearManager.HasPendingClear(pendingClearKey);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
|
||||
if (hasClear) {
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||
Bool hasPayload = m_clearManager.GetPendingClear(pendingClearKey, clearPayload);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
||||
if (hasPayload) {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &clearPayload.mask, sizeof(clearPayload.mask)));
|
||||
@@ -180,18 +213,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
const auto& att = fbo.GetAttachment(attachment);
|
||||
if (att.IsTexture() && m_clearManager.HasPendingClear(att.GetTexture().get())) {
|
||||
if (att.IsTexture() && m_clearManager.HasPendingClear(att)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt.GetTexture().get())) {
|
||||
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt.GetTexture().get())) {
|
||||
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -266,7 +299,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
texture2d->GetFormat());
|
||||
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||
Bool hasClear = m_clearManager.GetPendingClear(att, clearPayload);
|
||||
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
desc.loadOp = hasClear ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
@@ -280,7 +313,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = attachmentIndex,
|
||||
.texture = texture
|
||||
.key = VkClearManager::MakePendingClearKey(att)
|
||||
});
|
||||
}
|
||||
if (width == 0)
|
||||
@@ -313,7 +346,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.textureMipLevel = attachmentMipLevel,
|
||||
.finalLayout = desc.finalLayout,
|
||||
});
|
||||
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
|
||||
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(att);
|
||||
const Uint32 layerCount = ResolveAttachmentLayerCount(att);
|
||||
const VkImageViewType attachmentViewType = ResolveAttachmentViewType(att, *textureResource);
|
||||
attachmentViews.emplace_back(
|
||||
m_textureManager.GetOrCreateAttachmentViewAtMipLevel(
|
||||
*texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
|
||||
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
|
||||
}
|
||||
@@ -340,19 +378,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
// Depth attachment description
|
||||
// Depth/stencil attachment description
|
||||
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
VkAttachmentDescription depthAttachmentDescription;
|
||||
VkAttachmentReference depthAttachmentRef;
|
||||
depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
|
||||
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
VkTextureManager::TextureResource* depthTextureResource = nullptr;
|
||||
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
|
||||
auto& texture = *depthAtt.GetTexture();
|
||||
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(depthAtt.GetTextureLevel(), 0));
|
||||
const auto isUsableDepthStencilAttachment = [](const auto& attachment) {
|
||||
return attachment.IsComplete() && attachment.IsTexture();
|
||||
};
|
||||
const auto* selectedDepthStencilAttachment = isUsableDepthStencilAttachment(depthAtt) ? &depthAtt :
|
||||
(isUsableDepthStencilAttachment(stencilAtt) ? &stencilAtt : nullptr);
|
||||
const Bool hasDistinctDepthAndStencilAttachments =
|
||||
isUsableDepthStencilAttachment(depthAtt) && isUsableDepthStencilAttachment(stencilAtt) &&
|
||||
(depthAtt.GetTexture().get() != stencilAtt.GetTexture().get() ||
|
||||
depthAtt.GetTextureUploadTarget() != stencilAtt.GetTextureUploadTarget() ||
|
||||
depthAtt.GetTextureLevel() != stencilAtt.GetTextureLevel());
|
||||
if (hasDistinctDepthAndStencilAttachments) {
|
||||
MGLOG_E("GetOrCreateRenderPass: separate depth/stencil attachments are not supported yet; using the depth attachment and ignoring the standalone stencil attachment for framebuffer %u",
|
||||
fbo.GetExternalIndex());
|
||||
}
|
||||
if (selectedDepthStencilAttachment != nullptr) {
|
||||
auto& texture = *selectedDepthStencilAttachment->GetTexture();
|
||||
const Uint32 attachmentMipLevel =
|
||||
static_cast<Uint32>(std::max(selectedDepthStencilAttachment->GetTextureLevel(), 0));
|
||||
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||
Bool hasClear = m_clearManager.GetPendingClear(*selectedDepthStencilAttachment, clearPayload);
|
||||
Bool clearDepth = hasClear && (clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0;
|
||||
Bool clearStencil = hasClear && (clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0;
|
||||
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
||||
@@ -396,7 +450,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = depthAttachmentIndex,
|
||||
.texture = &texture
|
||||
.key = VkClearManager::MakePendingClearKey(*selectedDepthStencilAttachment)
|
||||
});
|
||||
}
|
||||
if (isDefaultFbo) {
|
||||
@@ -417,12 +471,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||
});
|
||||
textureResources.emplace_back(depthTextureResource);
|
||||
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(texture, attachmentMipLevel));
|
||||
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(*selectedDepthStencilAttachment);
|
||||
const Uint32 layerCount = ResolveAttachmentLayerCount(*selectedDepthStencilAttachment);
|
||||
const VkImageViewType attachmentViewType =
|
||||
ResolveAttachmentViewType(*selectedDepthStencilAttachment, *depthTextureResource);
|
||||
attachmentViews.emplace_back(
|
||||
m_textureManager.GetOrCreateAttachmentViewAtMipLevel(
|
||||
texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
|
||||
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
|
||||
if (width == 0 || height == 0) {
|
||||
width = depthAtt.GetSize().x();
|
||||
height = depthAtt.GetSize().y();
|
||||
width = selectedDepthStencilAttachment->GetSize().x();
|
||||
height = selectedDepthStencilAttachment->GetSize().y();
|
||||
}
|
||||
}
|
||||
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
||||
@@ -439,7 +499,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
|
||||
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
|
||||
subpassDesc.pResolveAttachments = nullptr;
|
||||
subpassDesc.pDepthStencilAttachment = depthAtt.IsComplete() ? &depthAttachmentRef : VK_NULL_HANDLE;
|
||||
subpassDesc.pDepthStencilAttachment = hasDepthStencilAttachment ? &depthAttachmentRef : VK_NULL_HANDLE;
|
||||
subpassDesc.preserveAttachmentCount = 0;
|
||||
subpassDesc.pPreserveAttachments = nullptr;
|
||||
|
||||
@@ -512,11 +572,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
clearValue.depthStencil = {1.0f, 0};
|
||||
}
|
||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
|
||||
if (pending.key.texture == nullptr || pending.attachmentIndex >= clearValues.size()) {
|
||||
continue;
|
||||
}
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||
if (!s_clearManager->GetPendingClear(pending.key, clearPayload)) {
|
||||
continue;
|
||||
}
|
||||
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||
@@ -524,7 +584,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
clearPayload.color.x(),
|
||||
clearPayload.color.y(),
|
||||
clearPayload.color.z(),
|
||||
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
|
||||
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
|
||||
};
|
||||
}
|
||||
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
@@ -540,7 +600,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||
s_clearManager->PopPendingClear(pending.texture);
|
||||
s_clearManager->PopPendingClear(pending.key);
|
||||
}
|
||||
s_activeRenderPass.hash = renderPassEntry.hash;
|
||||
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
struct PendingClearAttachmentInfo {
|
||||
Uint32 attachmentIndex = 0;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
PendingClearKey key{};
|
||||
};
|
||||
|
||||
struct TrackedAttachmentLayoutInfo {
|
||||
|
||||
@@ -71,6 +71,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
static VkImageLayout ResolveSampledReadOnlyLayout(VkImageAspectFlags aspectMask) {
|
||||
return (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
static void GetImageTransitionSourceState(VkImageLayout oldLayout,
|
||||
VkPipelineStageFlags& outSrcStageMask,
|
||||
VkAccessFlags& outSrcAccessMask) {
|
||||
@@ -594,7 +600,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
perMipView = CreateImageView(resource->image, resource->format, resource->aspect, resource->viewType,
|
||||
mipLevel, 1, resource->arrayLayers);
|
||||
mipLevel, 1, 0, resource->arrayLayers);
|
||||
if (perMipView == VK_NULL_HANDLE) {
|
||||
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(), mipLevel);
|
||||
return VK_NULL_HANDLE;
|
||||
@@ -603,6 +609,53 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return perMipView;
|
||||
}
|
||||
|
||||
VkImageView VkTextureManager::GetOrCreateAttachmentViewAtMipLevel(MG_State::GLState::ITextureObject& texture,
|
||||
Uint32 mipLevel, Uint32 baseArrayLayer,
|
||||
Uint32 layerCount,
|
||||
VkImageViewType viewType) {
|
||||
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
|
||||
if (resource == nullptr || resource->image == VK_NULL_HANDLE || mipLevel >= resource->mipLevels) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
if (layerCount == 0 || baseArrayLayer >= resource->arrayLayers ||
|
||||
baseArrayLayer + layerCount > resource->arrayLayers) {
|
||||
MGLOG_D("%s: invalid layer span [%u, %u) for textureId=%d arrayLayers=%u",
|
||||
__func__, baseArrayLayer, baseArrayLayer + layerCount, texture.GetExternalIndex(),
|
||||
resource->arrayLayers);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (baseArrayLayer == 0 && layerCount == resource->arrayLayers && viewType == resource->viewType) {
|
||||
return GetOrCreateViewAtMipLevel(texture, mipLevel);
|
||||
}
|
||||
|
||||
const TextureResource::AttachmentViewKey key{
|
||||
.mipLevel = mipLevel,
|
||||
.baseArrayLayer = baseArrayLayer,
|
||||
.layerCount = layerCount,
|
||||
.viewType = viewType,
|
||||
};
|
||||
auto it = resource->attachmentViews.find(key);
|
||||
if (it == resource->attachmentViews.end()) {
|
||||
it = resource->attachmentViews.emplace(key, VK_NULL_HANDLE).first;
|
||||
}
|
||||
VkImageView& attachmentView = it->second;
|
||||
if (attachmentView != VK_NULL_HANDLE) {
|
||||
return attachmentView;
|
||||
}
|
||||
|
||||
attachmentView = CreateImageView(resource->image, resource->format, resource->aspect, viewType,
|
||||
mipLevel, 1, baseArrayLayer, layerCount);
|
||||
if (attachmentView == VK_NULL_HANDLE) {
|
||||
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u baseArrayLayer=%u layerCount=%u viewType=%d",
|
||||
__func__, texture.GetExternalIndex(), mipLevel, baseArrayLayer, layerCount, static_cast<Int>(viewType));
|
||||
resource->attachmentViews.erase(it);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return attachmentView;
|
||||
}
|
||||
|
||||
VkImageView VkTextureManager::GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture,
|
||||
Uint32 mipLevel) {
|
||||
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
|
||||
@@ -622,7 +675,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
|
||||
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
|
||||
perMipSampledView = CreateImageView(resource->image, resource->format, resource->aspect, resource->viewType,
|
||||
mipLevel, 1, resource->arrayLayers, &sampledComponents);
|
||||
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents);
|
||||
if (perMipSampledView == VK_NULL_HANDLE) {
|
||||
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(),
|
||||
mipLevel);
|
||||
@@ -1109,7 +1162,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
|
||||
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
|
||||
resource.fullView = CreateImageView(resource.image, resource.format, resource.aspect, resource.viewType,
|
||||
baseMipLevel, levelCount, resource.arrayLayers, &sampledComponents);
|
||||
baseMipLevel, levelCount, 0, resource.arrayLayers, &sampledComponents);
|
||||
if (resource.fullView == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
@@ -1122,6 +1175,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
VkImageView VkTextureManager::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
|
||||
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
|
||||
Uint32 baseArrayLayer,
|
||||
Uint32 layerCount,
|
||||
const VkComponentMapping* components) const {
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
@@ -1136,7 +1190,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
viewInfo.subresourceRange.aspectMask = aspect;
|
||||
viewInfo.subresourceRange.baseMipLevel = baseMipLevel;
|
||||
viewInfo.subresourceRange.levelCount = levelCount;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
|
||||
viewInfo.subresourceRange.layerCount = layerCount;
|
||||
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
@@ -1293,17 +1347,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
1, ©);
|
||||
}
|
||||
|
||||
const VkImageLayout finalLayout = ResolveSampledReadOnlyLayout(aspectMask);
|
||||
VkImageLayout uploadLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
ok = TransitionImageLayout(commandBuffer, outResource.image,
|
||||
uploadLayout,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
kGraphicsSampledReadStages,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
aspectMask, 0, outResource.mipLevels, outResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
uploadLayout,
|
||||
finalLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
kGraphicsSampledReadStages,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
aspectMask, 0, outResource.mipLevels, outResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to sampled read-only layout failed");
|
||||
outResource.layout = finalLayout;
|
||||
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
|
||||
|
||||
@@ -1331,7 +1386,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
for (const auto& item : uploadItems) {
|
||||
mipmapTexture.MarkStorageDirty(item.target, item.level, false);
|
||||
}
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
outResource.layout = finalLayout;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,37 @@ public:
|
||||
};
|
||||
|
||||
struct TextureResource {
|
||||
struct AttachmentViewKey {
|
||||
Uint32 mipLevel = 0;
|
||||
Uint32 baseArrayLayer = 0;
|
||||
Uint32 layerCount = 1;
|
||||
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
|
||||
Bool operator==(const AttachmentViewKey& other) const {
|
||||
return mipLevel == other.mipLevel &&
|
||||
baseArrayLayer == other.baseArrayLayer &&
|
||||
layerCount == other.layerCount &&
|
||||
viewType == other.viewType;
|
||||
}
|
||||
};
|
||||
|
||||
struct AttachmentViewKeyHash {
|
||||
SizeT operator()(const AttachmentViewKey& key) const {
|
||||
SizeT hash = std::hash<Uint32>{}(key.mipLevel);
|
||||
hash ^= std::hash<Uint32>{}(key.baseArrayLayer) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= std::hash<Uint32>{}(key.layerCount) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= std::hash<Uint32>{}(static_cast<Uint32>(key.viewType)) +
|
||||
0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = nullptr;
|
||||
VkImageView fullView = VK_NULL_HANDLE;
|
||||
Vector<VkImageView> perMipViews;
|
||||
Vector<VkImageView> perMipSampledViews;
|
||||
UnorderedMap<AttachmentViewKey, VkImageView, AttachmentViewKeyHash> attachmentViews;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
Uint32 depth = 1;
|
||||
@@ -55,6 +81,7 @@ public:
|
||||
std::swap(this->fullView, that.fullView);
|
||||
std::swap(this->perMipViews, that.perMipViews);
|
||||
std::swap(this->perMipSampledViews, that.perMipSampledViews);
|
||||
std::swap(this->attachmentViews, that.attachmentViews);
|
||||
std::swap(this->layout, that.layout);
|
||||
std::swap(this->extent, that.extent);
|
||||
std::swap(this->depth, that.depth);
|
||||
@@ -82,12 +109,18 @@ public:
|
||||
vkDestroyImageView(s_device, sampledView, nullptr);
|
||||
}
|
||||
}
|
||||
for (const auto& [_, attachmentView] : attachmentViews) {
|
||||
if (attachmentView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(s_device, attachmentView, nullptr);
|
||||
}
|
||||
}
|
||||
if (image != VK_NULL_HANDLE && allocation != nullptr) {
|
||||
vmaDestroyImage(s_allocator, image, allocation);
|
||||
}
|
||||
fullView = VK_NULL_HANDLE;
|
||||
perMipViews.clear();
|
||||
perMipSampledViews.clear();
|
||||
attachmentViews.clear();
|
||||
image = VK_NULL_HANDLE;
|
||||
allocation = nullptr;
|
||||
layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
@@ -118,6 +151,9 @@ public:
|
||||
TextureResource* SyncTextureAndGetDescriptor(
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||
VkImageView GetOrCreateAttachmentViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel,
|
||||
Uint32 baseArrayLayer, Uint32 layerCount,
|
||||
VkImageViewType viewType);
|
||||
VkImageView GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
|
||||
void UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
|
||||
@@ -146,6 +182,7 @@ private:
|
||||
Bool SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource);
|
||||
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
|
||||
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
|
||||
Uint32 baseArrayLayer,
|
||||
Uint32 layerCount,
|
||||
const VkComponentMapping* components = nullptr) const;
|
||||
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
||||
|
||||
@@ -90,6 +90,78 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return requestedAlpha;
|
||||
}
|
||||
|
||||
static void ApplyGLViewportState(VkCommandBuffer commandBuffer, const IntVec2& fallbackExtent) {
|
||||
const IntVec4& viewportState = MG_State::pGLContext->GetViewport();
|
||||
const FloatVec2& depthRange = MG_State::pGLContext->GetDepthRange();
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = static_cast<float>(viewportState.x());
|
||||
viewport.y = static_cast<float>(viewportState.y());
|
||||
viewport.width =
|
||||
static_cast<float>(viewportState.z() > 0 ? viewportState.z() : fallbackExtent.x());
|
||||
viewport.height =
|
||||
static_cast<float>(viewportState.w() > 0 ? viewportState.w() : fallbackExtent.y());
|
||||
viewport.minDepth = depthRange.x();
|
||||
viewport.maxDepth = depthRange.y();
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
}
|
||||
|
||||
static void ApplyBlendConstants(VkCommandBuffer commandBuffer) {
|
||||
const FloatVec4& blendColor = MG_State::pGLContext->GetBlendColor();
|
||||
const float blendConstants[4] = {
|
||||
blendColor.x(),
|
||||
blendColor.y(),
|
||||
blendColor.z(),
|
||||
blendColor.w(),
|
||||
};
|
||||
vkCmdSetBlendConstants(commandBuffer, blendConstants);
|
||||
}
|
||||
|
||||
static Bool DrawModeUsesPolygonFill(GLenum mode) {
|
||||
switch (mode) {
|
||||
case GL_TRIANGLES:
|
||||
case GL_TRIANGLE_STRIP:
|
||||
case GL_TRIANGLE_FAN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyPolygonOffsetState(VkCommandBuffer commandBuffer) {
|
||||
vkCmdSetDepthBias(commandBuffer, MG_State::pGLContext->GetPolygonOffsetUnits(), 0.0f,
|
||||
MG_State::pGLContext->GetPolygonOffsetFactor());
|
||||
}
|
||||
|
||||
static void ApplyLineWidthState(VkCommandBuffer commandBuffer) {
|
||||
Float lineWidth = MG_State::pGLContext->GetLineWidth();
|
||||
if (MG_Backend::pActiveBackendObject != nullptr) {
|
||||
const auto& dynamicParameters = MG_Backend::pActiveBackendObject->GetDynamicParameters();
|
||||
const Float minLineWidth = dynamicParameters.AliasedLineWidthRangeMin;
|
||||
const Float maxLineWidth = dynamicParameters.AliasedLineWidthRangeMax;
|
||||
if (lineWidth < minLineWidth) {
|
||||
lineWidth = minLineWidth;
|
||||
} else if (lineWidth > maxLineWidth) {
|
||||
lineWidth = maxLineWidth;
|
||||
}
|
||||
}
|
||||
vkCmdSetLineWidth(commandBuffer, lineWidth);
|
||||
}
|
||||
|
||||
static void ApplyStencilState(VkCommandBuffer commandBuffer) {
|
||||
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
|
||||
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
|
||||
|
||||
vkCmdSetStencilCompareMask(commandBuffer, VK_STENCIL_FACE_FRONT_BIT, frontStencil.ValueMask);
|
||||
vkCmdSetStencilCompareMask(commandBuffer, VK_STENCIL_FACE_BACK_BIT, backStencil.ValueMask);
|
||||
vkCmdSetStencilWriteMask(commandBuffer, VK_STENCIL_FACE_FRONT_BIT, frontStencil.WriteMask);
|
||||
vkCmdSetStencilWriteMask(commandBuffer, VK_STENCIL_FACE_BACK_BIT, backStencil.WriteMask);
|
||||
vkCmdSetStencilReference(commandBuffer, VK_STENCIL_FACE_FRONT_BIT,
|
||||
static_cast<Uint32>(std::max(frontStencil.Ref, 0)));
|
||||
vkCmdSetStencilReference(commandBuffer, VK_STENCIL_FACE_BACK_BIT,
|
||||
static_cast<Uint32>(std::max(backStencil.Ref, 0)));
|
||||
}
|
||||
|
||||
enum class NumericDomain {
|
||||
Unknown,
|
||||
FloatLike,
|
||||
@@ -632,6 +704,51 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
|
||||
}
|
||||
|
||||
static Bool HasDistinctCompleteDepthStencilTextureAttachments(
|
||||
const MG_State::GLState::FramebufferObject& framebufferObject) {
|
||||
if (framebufferObject.GetExternalIndex() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& depthAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
const auto& stencilAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
if (!depthAttachment.IsComplete() || !stencilAttachment.IsComplete() ||
|
||||
!depthAttachment.IsTexture() || !stencilAttachment.IsTexture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return depthAttachment.GetTexture().get() != stencilAttachment.GetTexture().get() ||
|
||||
depthAttachment.GetTextureUploadTarget() != stencilAttachment.GetTextureUploadTarget() ||
|
||||
depthAttachment.GetTextureLevel() != stencilAttachment.GetTextureLevel();
|
||||
}
|
||||
|
||||
static Bool HasCompleteRenderbufferAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {
|
||||
if (framebufferObject.GetExternalIndex() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& attachment : framebufferObject.GetAllAttachmentObjects()) {
|
||||
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Bool IsUnsupportedFramebufferForDirectVulkan(
|
||||
const MG_State::GLState::FramebufferObject& framebufferObject) {
|
||||
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) ||
|
||||
HasCompleteRenderbufferAttachment(framebufferObject);
|
||||
}
|
||||
|
||||
static void RecordUnsupportedFramebufferError(const char* func) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidFramebufferOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"DirectVulkan", func,
|
||||
"DirectVulkan does not support this non-default framebuffer configuration."));
|
||||
}
|
||||
|
||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
@@ -778,6 +895,19 @@ void main() {
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
|
||||
return target >= TextureUploadTarget::CubeMapPositiveX &&
|
||||
target <= TextureUploadTarget::CubeMapNegativeZ;
|
||||
}
|
||||
|
||||
static Uint32 ResolveAttachmentBaseArrayLayer(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
|
||||
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<Uint32>(uploadTarget) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
|
||||
}
|
||||
|
||||
enum class BlitSurfaceTransform : Uint32 {
|
||||
Identity = 0,
|
||||
Rotate90 = 1,
|
||||
@@ -792,6 +922,8 @@ void main() {
|
||||
IntVec2 extent = {0, 0};
|
||||
Uint32 mipLevel = 0;
|
||||
Uint32 mipLevelCount = 1;
|
||||
Uint32 baseArrayLayer = 0;
|
||||
Uint32 layerCount = 1;
|
||||
const char* label = nullptr;
|
||||
};
|
||||
|
||||
@@ -968,6 +1100,8 @@ void main() {
|
||||
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -990,6 +1124,8 @@ void main() {
|
||||
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
|
||||
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
|
||||
outBinding.mipLevelCount = resource->mipLevels;
|
||||
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1013,6 +1149,8 @@ void main() {
|
||||
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
outBinding.trackedLayout = nullptr;
|
||||
if ((requiredAspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
|
||||
@@ -1067,6 +1205,8 @@ void main() {
|
||||
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
|
||||
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
|
||||
outBinding.mipLevelCount = resource->mipLevels;
|
||||
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1099,6 +1239,8 @@ void main() {
|
||||
static_cast<Int>(std::max(1u, resource->extent.height >> mipLevel))};
|
||||
outBinding.mipLevel = mipLevel;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
outBinding.label = "destination texture";
|
||||
return true;
|
||||
}
|
||||
@@ -1123,6 +1265,8 @@ void main() {
|
||||
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
|
||||
outBinding.mipLevel = 0;
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = 0;
|
||||
outBinding.layerCount = 1;
|
||||
outBinding.trackedLayout = nullptr;
|
||||
if ((requiredAspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
|
||||
@@ -1179,6 +1323,8 @@ void main() {
|
||||
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
|
||||
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
|
||||
outBinding.mipLevelCount = 1;
|
||||
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
|
||||
outBinding.layerCount = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2166,14 +2312,7 @@ void main() {
|
||||
|
||||
vkCmdBeginRenderPass(frame.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(dstTexelSize.x());
|
||||
viewport.height = static_cast<float>(dstTexelSize.y());
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
|
||||
ApplyGLViewportState(frame.commandBuffer, dstTexelSize.xy());
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
@@ -2345,6 +2484,16 @@ void main() {
|
||||
}
|
||||
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace);
|
||||
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest);
|
||||
auto polygonOffsetFillEnabled =
|
||||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) &&
|
||||
DrawModeUsesPolygonFill(mode);
|
||||
auto rasterizerDiscardEnabled =
|
||||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard);
|
||||
auto colorLogicOpEnabled =
|
||||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled;
|
||||
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest);
|
||||
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
|
||||
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
|
||||
auto mask = MG_State::pGLContext->GetColorMask();
|
||||
const auto colorWriteMask = static_cast<VkColorComponentFlags>(
|
||||
(mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
|
||||
@@ -2366,19 +2515,52 @@ void main() {
|
||||
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
||||
.depthTestEnable = depthTestEnabled,
|
||||
.depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(),
|
||||
.depthBiasEnable = polygonOffsetFillEnabled,
|
||||
.rasterizerDiscardEnable = rasterizerDiscardEnabled,
|
||||
.logicOpEnable = colorLogicOpEnabled,
|
||||
.stencilTestEnable = stencilTestEnabled,
|
||||
.depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_State::pGLContext->GetDepthFunc()),
|
||||
.logicOp = MG_Util::ConvertLogicOperationToVkEnum(MG_State::pGLContext->GetLogicOp()),
|
||||
.frontStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.FailOp),
|
||||
.frontStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthPassOp),
|
||||
.frontStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthFailOp),
|
||||
.frontStencilCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(frontStencil.Func),
|
||||
.backStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.FailOp),
|
||||
.backStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.PassDepthPassOp),
|
||||
.backStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.PassDepthFailOp),
|
||||
.backStencilCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(backStencil.Func),
|
||||
.stages = &programObj.stages,
|
||||
.vertexInputState = pipelineVertexInputState
|
||||
};
|
||||
if (!payload.stencilTestEnable) {
|
||||
payload.frontStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
payload.backStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
const Bool hasDepthStencilAttachment = renderPassEntry.hasDepthStencilAttachment;
|
||||
if (!hasDepthStencilAttachment && (payload.depthTestEnable || payload.depthWriteEnable)) {
|
||||
MGLOG_D("GetOrCreatePipeline: disabling depth test/write for program=%u because render pass has no depth attachment (attachmentCount=%u colorAttachmentCount=%u)",
|
||||
if (!hasDepthStencilAttachment &&
|
||||
(payload.depthTestEnable || payload.depthWriteEnable || payload.stencilTestEnable)) {
|
||||
MGLOG_D("GetOrCreatePipeline: disabling depth/stencil tests for program=%u because render pass has no depth attachment (attachmentCount=%u colorAttachmentCount=%u)",
|
||||
program.GetExternalIndex(),
|
||||
renderPassEntry.attachmentCount,
|
||||
renderPassEntry.colorAttachmentCount);
|
||||
payload.depthTestEnable = false;
|
||||
payload.depthWriteEnable = false;
|
||||
payload.stencilTestEnable = false;
|
||||
payload.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
payload.frontStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
payload.backStencilFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilPassOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask;
|
||||
MOBILEGL_ASSERT(
|
||||
@@ -2555,6 +2737,10 @@ void main() {
|
||||
m_textureManager->CollectGarbage();
|
||||
const auto& drawFbo =
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
if (drawFbo != nullptr && IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) {
|
||||
RecordUnsupportedFramebufferError(__func__);
|
||||
return false;
|
||||
}
|
||||
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
|
||||
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
|
||||
ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
|
||||
@@ -2686,14 +2872,11 @@ void main() {
|
||||
MOBILEGL_ASSERT(idxUploadOk, "SetupDraw skipped: failed to upload index buffer");
|
||||
}
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(renderPassEntry->extent.x());
|
||||
viewport.height = static_cast<float>(renderPassEntry->extent.y());
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
|
||||
ApplyGLViewportState(frame.commandBuffer, renderPassEntry->extent);
|
||||
ApplyBlendConstants(frame.commandBuffer);
|
||||
ApplyPolygonOffsetState(frame.commandBuffer);
|
||||
ApplyLineWidthState(frame.commandBuffer);
|
||||
ApplyStencilState(frame.commandBuffer);
|
||||
|
||||
Bool scissorEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest);
|
||||
VkRect2D scissor{};
|
||||
@@ -2780,6 +2963,10 @@ void main() {
|
||||
m_clearManager->CollectGarbage();
|
||||
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
|
||||
MOBILEGL_ASSERT(fbo, "VulkanRenderer::Clear: draw framebuffer not found (fbo == nullptr)");
|
||||
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
|
||||
RecordUnsupportedFramebufferError(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ClearFramebufferPayload payload {
|
||||
.color = MG_State::pGLContext->GetClearColor(),
|
||||
@@ -2794,6 +2981,10 @@ void main() {
|
||||
m_clearManager->CollectGarbage();
|
||||
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
|
||||
MOBILEGL_ASSERT(fbo, "VulkanRenderer::QueueClearBufferPayload: draw framebuffer not found");
|
||||
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
|
||||
RecordUnsupportedFramebufferError(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
auto queueAttachmentClear = [&](FramebufferAttachmentType attachmentType) {
|
||||
if (attachmentType == FramebufferAttachmentType::None) {
|
||||
@@ -2803,11 +2994,7 @@ void main() {
|
||||
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
|
||||
return;
|
||||
}
|
||||
auto texture = attachment.GetTexture();
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
m_clearManager->QueueClear(clearPayload, texture);
|
||||
m_clearManager->QueueClear(clearPayload, attachment);
|
||||
};
|
||||
|
||||
switch (buffer) {
|
||||
@@ -2920,8 +3107,8 @@ void main() {
|
||||
|
||||
Bool VulkanRenderer::MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject& texture) {
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
if (!m_clearManager->GetPendingClear(&texture, clearPayload)) {
|
||||
Vector<PendingClearEntry> pendingClears;
|
||||
if (!m_clearManager->GetPendingClears(&texture, pendingClears)) {
|
||||
return true;
|
||||
}
|
||||
MOBILEGL_ASSERT(VkRenderPassManager::GetActiveRenderPass() == nullptr,
|
||||
@@ -2940,53 +3127,65 @@ void main() {
|
||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, resource->image, resource->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
resource->aspect, 0, resource->mipLevels);
|
||||
resource->aspect, 0, resource->mipLevels, resource->arrayLayers);
|
||||
MOBILEGL_ASSERT(ok,
|
||||
"MaterializePendingClearForTexture: failed to transition textureId=%d to TRANSFER_DST",
|
||||
texture.GetExternalIndex());
|
||||
|
||||
VkImageSubresourceRange subresourceRange{};
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageLayout sampledLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkClearColorValue clearValue{};
|
||||
clearValue.float32[0] = clearPayload.color.x();
|
||||
clearValue.float32[1] = clearPayload.color.y();
|
||||
clearValue.float32[2] = clearPayload.color.z();
|
||||
clearValue.float32[3] = ResolveColorClearAlpha(&texture, clearPayload.color.w());
|
||||
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
} else {
|
||||
VkImageAspectFlags clearAspectMask = 0;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
for (const auto& pendingClear : pendingClears) {
|
||||
MOBILEGL_ASSERT(pendingClear.key.mipLevel < resource->mipLevels,
|
||||
"MaterializePendingClearForTexture: textureId=%d pending clear mip=%u out of range %u",
|
||||
texture.GetExternalIndex(), pendingClear.key.mipLevel, resource->mipLevels);
|
||||
MOBILEGL_ASSERT(pendingClear.key.baseArrayLayer + pendingClear.key.layerCount <= resource->arrayLayers,
|
||||
"MaterializePendingClearForTexture: textureId=%d pending clear layer span [%u, %u) exceeds arrayLayers=%u",
|
||||
texture.GetExternalIndex(), pendingClear.key.baseArrayLayer,
|
||||
pendingClear.key.baseArrayLayer + pendingClear.key.layerCount, resource->arrayLayers);
|
||||
|
||||
VkImageSubresourceRange subresourceRange{};
|
||||
subresourceRange.baseMipLevel = pendingClear.key.mipLevel;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = pendingClear.key.baseArrayLayer;
|
||||
subresourceRange.layerCount = pendingClear.key.layerCount;
|
||||
|
||||
const auto& clearPayload = pendingClear.payload;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkClearColorValue clearValue{};
|
||||
clearValue.float32[0] = clearPayload.color.x();
|
||||
clearValue.float32[1] = clearPayload.color.y();
|
||||
clearValue.float32[2] = clearPayload.color.z();
|
||||
clearValue.float32[3] = ResolveColorClearAlpha(&texture, clearPayload.color.w());
|
||||
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
} else {
|
||||
VkImageAspectFlags clearAspectMask = 0;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
MOBILEGL_ASSERT(clearAspectMask != 0,
|
||||
"MaterializePendingClearForTexture: textureId=%d has no matching depth/stencil clear mask",
|
||||
texture.GetExternalIndex());
|
||||
subresourceRange.aspectMask = clearAspectMask;
|
||||
VkClearDepthStencilValue clearValue{};
|
||||
clearValue.depth = clearPayload.depth;
|
||||
clearValue.stencil = clearPayload.stencil;
|
||||
vkCmdClearDepthStencilImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
sampledLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
|
||||
(clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||
clearAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
MOBILEGL_ASSERT(clearAspectMask != 0,
|
||||
"MaterializePendingClearForTexture: textureId=%d has no matching depth/stencil clear mask",
|
||||
texture.GetExternalIndex());
|
||||
subresourceRange.aspectMask = clearAspectMask;
|
||||
VkClearDepthStencilValue clearValue{};
|
||||
clearValue.depth = clearPayload.depth;
|
||||
clearValue.stencil = clearPayload.stencil;
|
||||
vkCmdClearDepthStencilImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
&clearValue, 1, &subresourceRange);
|
||||
sampledLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, resource->image, clearLayout, sampledLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels);
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels,
|
||||
resource->arrayLayers);
|
||||
MOBILEGL_ASSERT(ok,
|
||||
"MaterializePendingClearForTexture: failed to transition textureId=%d to sampled layout",
|
||||
texture.GetExternalIndex());
|
||||
@@ -3054,14 +3253,7 @@ void main() {
|
||||
const Bool ok = VkRenderPassManager::BeginRenderPass(frame.commandBuffer, renderPassEntry);
|
||||
MOBILEGL_ASSERT(ok, "%s: BeginRenderPass failed", __func__);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(renderPassEntry.extent.x());
|
||||
viewport.height = static_cast<float>(renderPassEntry.extent.y());
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
|
||||
ApplyGLViewportState(frame.commandBuffer, renderPassEntry.extent);
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
@@ -3163,6 +3355,11 @@ void main() {
|
||||
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
MOBILEGL_ASSERT(readFbo != nullptr, "VulkanRenderer::BlitFramebuffer: read framebuffer is null");
|
||||
MOBILEGL_ASSERT(drawFbo != nullptr, "VulkanRenderer::BlitFramebuffer: draw framebuffer is null");
|
||||
if (IsUnsupportedFramebufferForDirectVulkan(*readFbo) ||
|
||||
IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) {
|
||||
RecordUnsupportedFramebufferError(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frame = m_frameContext.GetCurrent();
|
||||
if (!frame.isCommandRecording) {
|
||||
@@ -3285,13 +3482,13 @@ void main() {
|
||||
VkImageCopy copyRegion{};
|
||||
copyRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
|
||||
copyRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
|
||||
copyRegion.srcSubresource.baseArrayLayer = 0;
|
||||
copyRegion.srcSubresource.layerCount = 1;
|
||||
copyRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
|
||||
copyRegion.srcSubresource.layerCount = srcBinding.layerCount;
|
||||
copyRegion.srcOffset = {srcX0, srcY0, 0};
|
||||
copyRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
|
||||
copyRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
|
||||
copyRegion.dstSubresource.baseArrayLayer = 0;
|
||||
copyRegion.dstSubresource.layerCount = 1;
|
||||
copyRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
|
||||
copyRegion.dstSubresource.layerCount = dstBinding.layerCount;
|
||||
copyRegion.dstOffset = {dstX0, dstY0, 0};
|
||||
copyRegion.extent = {static_cast<Uint32>(srcWidth), static_cast<Uint32>(srcHeight), 1};
|
||||
|
||||
@@ -3421,14 +3618,14 @@ void main() {
|
||||
VkImageBlit blitRegion{};
|
||||
blitRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
|
||||
blitRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
|
||||
blitRegion.srcSubresource.baseArrayLayer = 0;
|
||||
blitRegion.srcSubresource.layerCount = 1;
|
||||
blitRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
|
||||
blitRegion.srcSubresource.layerCount = srcBinding.layerCount;
|
||||
blitRegion.srcOffsets[0] = {srcX0, srcY0, 0};
|
||||
blitRegion.srcOffsets[1] = {srcX1, srcY1, 1};
|
||||
blitRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
|
||||
blitRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
|
||||
blitRegion.dstSubresource.baseArrayLayer = 0;
|
||||
blitRegion.dstSubresource.layerCount = 1;
|
||||
blitRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
|
||||
blitRegion.dstSubresource.layerCount = dstBinding.layerCount;
|
||||
blitRegion.dstOffsets[0] = {dstX0, dstY0, 0};
|
||||
blitRegion.dstOffsets[1] = {dstX1, dstY1, 1};
|
||||
if (drawIsDefaultFbo) {
|
||||
@@ -3503,6 +3700,11 @@ void main() {
|
||||
"CopyTexSubImage2D requires a framebuffer bound to GL_READ_FRAMEBUFFER.");
|
||||
return;
|
||||
}
|
||||
if (IsUnsupportedFramebufferForDirectVulkan(*readFbo)) {
|
||||
RecordTextureCopyError(__func__, ErrorCode::InvalidFramebufferOperation,
|
||||
"CopyTexSubImage2D does not support the current non-default read framebuffer configuration on DirectVulkan.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& frame = m_frameContext.GetCurrent();
|
||||
if (!frame.isCommandRecording) {
|
||||
@@ -3601,13 +3803,13 @@ void main() {
|
||||
VkImageCopy copyRegion{};
|
||||
copyRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
|
||||
copyRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
|
||||
copyRegion.srcSubresource.baseArrayLayer = 0;
|
||||
copyRegion.srcSubresource.layerCount = 1;
|
||||
copyRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
|
||||
copyRegion.srcSubresource.layerCount = srcBinding.layerCount;
|
||||
copyRegion.srcOffset = {x, y, 0};
|
||||
copyRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
|
||||
copyRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
|
||||
copyRegion.dstSubresource.baseArrayLayer = 0;
|
||||
copyRegion.dstSubresource.layerCount = 1;
|
||||
copyRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
|
||||
copyRegion.dstSubresource.layerCount = dstBinding.layerCount;
|
||||
copyRegion.dstOffset = {xoffset, yoffset, 0};
|
||||
copyRegion.extent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
|
||||
vkCmdCopyImage(frame.commandBuffer,
|
||||
@@ -4064,7 +4266,8 @@ void main() {
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
||||
MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result);
|
||||
RecreateSwapchain();
|
||||
result = VK_SUCCESS;
|
||||
result =
|
||||
m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired);
|
||||
}
|
||||
VK_VERIFY(result, "Present, vkAcquireNextImageKHR");
|
||||
CollectDeferredDepthMipmapCleanup(m_frameContext.GetCurrentFrameIndex());
|
||||
@@ -4350,8 +4553,11 @@ void main() {
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
|
||||
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
|
||||
deviceFeatures.logicOp = supportedDeviceFeatures.logicOp;
|
||||
deviceFeatures.shaderClipDistance = supportedDeviceFeatures.shaderClipDistance;
|
||||
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
|
||||
deviceFeatures.wideLines = supportedDeviceFeatures.wideLines;
|
||||
m_logicOpFeatureEnabled = deviceFeatures.logicOp == VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo deviceCreateInfo{};
|
||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
@@ -4416,16 +4622,20 @@ void main() {
|
||||
|
||||
deviceCreateInfo.enabledExtensionCount = static_cast<Uint32>(enabledDeviceExtensions.size());
|
||||
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
|
||||
MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s shaderClipDistance=%s shaderCullDistance=%s",
|
||||
MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s",
|
||||
supportedDeviceFeatures.geometryShader ? "true" : "false",
|
||||
supportedDeviceFeatures.independentBlend ? "true" : "false",
|
||||
supportedDeviceFeatures.logicOp ? "true" : "false",
|
||||
supportedDeviceFeatures.shaderClipDistance ? "true" : "false",
|
||||
supportedDeviceFeatures.shaderCullDistance ? "true" : "false");
|
||||
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s shaderClipDistance=%s shaderCullDistance=%s",
|
||||
supportedDeviceFeatures.shaderCullDistance ? "true" : "false",
|
||||
supportedDeviceFeatures.wideLines ? "true" : "false");
|
||||
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s",
|
||||
deviceFeatures.geometryShader ? "true" : "false",
|
||||
deviceFeatures.independentBlend ? "true" : "false",
|
||||
deviceFeatures.logicOp ? "true" : "false",
|
||||
deviceFeatures.shaderClipDistance ? "true" : "false",
|
||||
deviceFeatures.shaderCullDistance ? "true" : "false");
|
||||
deviceFeatures.shaderCullDistance ? "true" : "false",
|
||||
deviceFeatures.wideLines ? "true" : "false");
|
||||
VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
|
||||
|
||||
s_vkCmdDrawIndexedIndirectCount = reinterpret_cast<PFNDrawIndexedIndirectCountFunc>(
|
||||
@@ -4726,12 +4936,12 @@ void main() {
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
for (const auto& pending : compatibleRenderPassEntry.pendingClearAttachments) {
|
||||
if (!pending.texture) {
|
||||
if (pending.key.texture == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
if (!m_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||
if (!m_clearManager->GetPendingClear(pending.key, clearPayload)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4744,7 +4954,7 @@ void main() {
|
||||
clearPayload.color.x(),
|
||||
clearPayload.color.y(),
|
||||
clearPayload.color.z(),
|
||||
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
|
||||
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
|
||||
};
|
||||
} else {
|
||||
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
@@ -4761,7 +4971,7 @@ void main() {
|
||||
}
|
||||
|
||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||
m_clearManager->PopPendingClear(pending.texture);
|
||||
m_clearManager->PopPendingClear(pending.key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkQueue m_presentQueue = VK_NULL_HANDLE;
|
||||
Bool m_drawIndirectCountExtensionEnabled = false;
|
||||
Bool m_indexTypeUint8ExtensionEnabled = false;
|
||||
Bool m_logicOpFeatureEnabled = false;
|
||||
using PFNDrawIndexedIndirectCountFunc = void(VKAPI_PTR*)(VkCommandBuffer commandBuffer, VkBuffer buffer,
|
||||
VkDeviceSize offset, VkBuffer countBuffer,
|
||||
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
|
||||
|
||||
Reference in New Issue
Block a user