mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (MG_Backend/DirectVulkan): implement backend func for glCopyTex(Sub)Image2D
This commit is contained in:
@@ -13,10 +13,29 @@
|
|||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
|
UniquePtr<VulkanRenderer> pVulkanRenderer = nullptr;
|
||||||
|
|
||||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {}
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer");
|
||||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfi called with null GL context");
|
||||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferuiv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferiv called with null GL context");
|
||||||
|
pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value);
|
||||||
|
}
|
||||||
|
|
||||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||||
@@ -36,9 +55,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {}
|
||||||
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
|
void DrawArraysIndirect(GLenum mode, const void* indirect) {}
|
||||||
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height, GLint border) {}
|
GLsizei height, GLint border) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexImage2D called with null GL context");
|
||||||
|
pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height);
|
||||||
|
}
|
||||||
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||||
GLsizei height) {}
|
GLsizei height) {
|
||||||
|
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer");
|
||||||
|
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexSubImage2D called with null GL context");
|
||||||
|
pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||||
|
}
|
||||||
void GenerateMipmap(GLenum target) {}
|
void GenerateMipmap(GLenum target) {}
|
||||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {}
|
||||||
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {}
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {}
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
QueueClear({
|
QueueClear({
|
||||||
.color = clearPayload.color,
|
.mask = GL_COLOR_BUFFER_BIT,
|
||||||
.attachmentType = drawbuf
|
.color = clearPayload.color
|
||||||
}, drawFbo.GetAttachment(drawbuf).GetTexture());
|
}, drawFbo.GetAttachment(drawbuf).GetTexture());
|
||||||
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
|
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
|
||||||
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
|
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
|
||||||
@@ -44,8 +44,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (mask & GL_DEPTH_BUFFER_BIT &&
|
if (mask & GL_DEPTH_BUFFER_BIT &&
|
||||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
|
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
|
||||||
QueueClear({
|
QueueClear({
|
||||||
|
.mask = GL_DEPTH_BUFFER_BIT,
|
||||||
.depth = clearPayload.depth,
|
.depth = clearPayload.depth,
|
||||||
.attachmentType = FramebufferAttachmentType::Depth,
|
|
||||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
|
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
|
||||||
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
|
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
|
||||||
drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture()->GetExternalIndex(), clearPayload.depth);
|
drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture()->GetExternalIndex(), clearPayload.depth);
|
||||||
@@ -54,8 +54,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (mask & GL_STENCIL_BUFFER_BIT &&
|
if (mask & GL_STENCIL_BUFFER_BIT &&
|
||||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
|
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
|
||||||
QueueClear({
|
QueueClear({
|
||||||
|
.mask = GL_STENCIL_BUFFER_BIT,
|
||||||
.stencil = clearPayload.stencil,
|
.stencil = clearPayload.stencil,
|
||||||
.attachmentType = FramebufferAttachmentType::Stencil,
|
|
||||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
|
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
|
||||||
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
|
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
|
||||||
drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture()->GetExternalIndex(), clearPayload.stencil);
|
drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture()->GetExternalIndex(), clearPayload.stencil);
|
||||||
@@ -64,12 +64,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
||||||
|
if (clearPayload.mask == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
||||||
if (weakTexturePtr.expired())
|
if (weakTexturePtr.expired())
|
||||||
return;
|
return;
|
||||||
auto* pTexture = weakTexturePtr.lock().get();
|
auto* pTexture = weakTexturePtr.lock().get();
|
||||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
m_aliveObjects[pTexture] = weakTexturePtr;
|
||||||
m_pendingClears[pTexture] = clearPayload;
|
auto& pending = m_pendingClears[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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||||
@@ -84,9 +97,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outPayload = m_pendingClears[texture];
|
outPayload = m_pendingClears[texture];
|
||||||
MGLOG_D("%s: Got pending clear for texture %d (%s), clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
|
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(),
|
texture->GetExternalIndex(),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
|
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
|
||||||
|
static_cast<Uint32>(outPayload.mask),
|
||||||
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
|
||||||
outPayload.depth,
|
outPayload.depth,
|
||||||
outPayload.stencil);
|
outPayload.stencil);
|
||||||
|
|||||||
@@ -23,12 +23,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ClearAttachmentPayload {
|
struct ClearAttachmentPayload {
|
||||||
union {
|
GLbitfield mask = 0;
|
||||||
FloatVec4 color;
|
FloatVec4 color = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
Float depth{};
|
Float depth = 1.0f;
|
||||||
Uint32 stencil;
|
Uint32 stencil = 0;
|
||||||
};
|
|
||||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::Color0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VkClearManager {
|
class VkClearManager {
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
||||||
if (hasPayload) {
|
if (hasPayload) {
|
||||||
XXHASH_VERIFY(XXH64_update(
|
XXHASH_VERIFY(XXH64_update(m_hashState, &clearPayload.mask, sizeof(clearPayload.mask)));
|
||||||
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,14 +171,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Int width = 0;
|
Int width = 0;
|
||||||
Int height = 0;
|
Int height = 0;
|
||||||
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
|
Vector<VkAttachmentDescription> attachmentDescriptions;
|
||||||
|
attachmentDescriptions.reserve(validDrawBufCount + 1);
|
||||||
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
||||||
|
for (auto& attachmentRef : colorAttachmentRefs) {
|
||||||
|
attachmentRef.attachment = VK_ATTACHMENT_UNUSED;
|
||||||
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
}
|
||||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||||
|
pendingClearAttachments.reserve(validDrawBufCount + 1);
|
||||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||||
|
trackedAttachmentLayouts.reserve(validDrawBufCount + 1);
|
||||||
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
|
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
|
||||||
textureResources.clear();
|
textureResources.clear();
|
||||||
textureResources.resize(validDrawBufCount, nullptr);
|
textureResources.reserve(validDrawBufCount + 1);
|
||||||
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
|
Vector<VkImageView> attachmentViews;
|
||||||
|
attachmentViews.reserve(validDrawBufCount + 1);
|
||||||
// This should automatically work on default & offscreen FBO
|
// This should automatically work on default & offscreen FBO
|
||||||
// assuming default FBO has the right param
|
// assuming default FBO has the right param
|
||||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
for (Int i = 0; i < validDrawBufCount; ++i) {
|
||||||
@@ -192,9 +199,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
auto* texture = att.GetTexture().get();
|
auto* texture = att.GetTexture().get();
|
||||||
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(att.GetTextureLevel(), 0));
|
const Uint32 attachmentMipLevel = static_cast<Uint32>(std::max(att.GetTextureLevel(), 0));
|
||||||
const auto textureTarget = texture->GetTarget();
|
const auto textureTarget = texture->GetTarget();
|
||||||
|
const Uint32 attachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||||
|
attachmentDescriptions.emplace_back();
|
||||||
|
|
||||||
// Color attachment description
|
// Color attachment description
|
||||||
VkAttachmentDescription& desc = attachmentDescriptions[i];
|
VkAttachmentDescription& desc = attachmentDescriptions.back();
|
||||||
switch (textureTarget) {
|
switch (textureTarget) {
|
||||||
case TextureTarget::Texture2D: {
|
case TextureTarget::Texture2D: {
|
||||||
auto* texture2d =
|
auto* texture2d =
|
||||||
@@ -219,7 +228,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
if (hasClear) {
|
if (hasClear) {
|
||||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||||
.attachmentIndex = static_cast<Uint32>(i),
|
.attachmentIndex = attachmentIndex,
|
||||||
.texture = texture
|
.texture = texture
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -238,20 +247,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
.swapchainImageIndex = swapchainImageIndex,
|
.swapchainImageIndex = swapchainImageIndex,
|
||||||
.finalLayout = desc.finalLayout,
|
.finalLayout = desc.finalLayout,
|
||||||
});
|
});
|
||||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
textureResources.emplace_back(nullptr);
|
||||||
|
attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]);
|
||||||
} else {
|
} else {
|
||||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
auto* textureResource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||||
MOBILEGL_ASSERT(textureResources[i],
|
MOBILEGL_ASSERT(textureResource,
|
||||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
||||||
desc.format = textureResources[i]->format;
|
textureResources.emplace_back(textureResource);
|
||||||
trackedColorLayout = textureResources[i]->layout;
|
desc.format = textureResource->format;
|
||||||
|
trackedColorLayout = textureResource->layout;
|
||||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||||
.target = TrackedAttachmentTarget::Texture,
|
.target = TrackedAttachmentTarget::Texture,
|
||||||
.texture = texture,
|
.texture = texture,
|
||||||
.finalLayout = desc.finalLayout,
|
.finalLayout = desc.finalLayout,
|
||||||
});
|
});
|
||||||
attachmentViews[i] = m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel);
|
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
|
||||||
MOBILEGL_ASSERT(attachmentViews[i] != VK_NULL_HANDLE,
|
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
|
||||||
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
|
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +284,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// Attachment reference
|
// Attachment reference
|
||||||
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
||||||
attachmentRef.attachment = i;
|
attachmentRef.attachment = attachmentIndex;
|
||||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,8 +301,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||||
ClearAttachmentPayload clearPayload{};
|
ClearAttachmentPayload clearPayload{};
|
||||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
Bool clearDepth = hasClear && (clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0;
|
||||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
Bool clearStencil = hasClear && (clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0;
|
||||||
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
||||||
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
|
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
@@ -453,17 +464,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
|
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
|
|
||||||
clearValues[pending.attachmentIndex].color = {
|
clearValues[pending.attachmentIndex].color = {
|
||||||
clearPayload.color.x(),
|
clearPayload.color.x(),
|
||||||
clearPayload.color.y(),
|
clearPayload.color.y(),
|
||||||
clearPayload.color.z(),
|
clearPayload.color.z(),
|
||||||
clearPayload.color.w()
|
clearPayload.color.w()
|
||||||
};
|
};
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
|
}
|
||||||
|
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
|
}
|
||||||
|
if ((clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||||
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
||||||
#include "MG_State/GLState/SamplerState/SamplerObject.h"
|
#include "MG_State/GLState/SamplerState/SamplerObject.h"
|
||||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||||
|
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
|
||||||
#include "MG_Util/Converters/MGToVk/RenderStateEnumConverter.h"
|
#include "MG_Util/Converters/MGToVk/RenderStateEnumConverter.h"
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
@@ -84,6 +85,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RecordClearBufferError(const char* func, ErrorCode code, const char* message) {
|
||||||
|
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RecordTextureCopyError(const char* func, ErrorCode code, const char* message) {
|
||||||
|
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
|
||||||
|
}
|
||||||
|
|
||||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||||
@@ -154,6 +163,49 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GetImageTransitionDestinationState(VkImageLayout newLayout, VkPipelineStageFlags& outDstStageMask,
|
||||||
|
VkAccessFlags& outDstAccessMask) {
|
||||||
|
switch (newLayout) {
|
||||||
|
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
outDstAccessMask = 0;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||||
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||||
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
||||||
|
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
outDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||||
|
outDstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Bool ResolveColorBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
static Bool ResolveColorBlitBinding(MG_State::GLState::FramebufferObject& fbo, Bool isReadFramebuffer,
|
||||||
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
Uint32 swapchainImageIndex, SwapchainObject& swapchainObject,
|
||||||
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
||||||
@@ -218,6 +270,37 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool ResolveTextureCopyDestinationBinding(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel,
|
||||||
|
VkTextureManager& textureManager, BlitImageBinding& outBinding) {
|
||||||
|
auto* resource = textureManager.SyncTextureAndGetDescriptor(texture);
|
||||||
|
if (resource == nullptr) {
|
||||||
|
MGLOG_E("CopyTexSubImage2D skipped: failed to sync destination textureId=%d",
|
||||||
|
texture.GetExternalIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) == 0) {
|
||||||
|
MGLOG_E("CopyTexSubImage2D skipped: destination textureId=%d is not a color image",
|
||||||
|
texture.GetExternalIndex());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mipLevel >= resource->mipLevels) {
|
||||||
|
MGLOG_E("CopyTexSubImage2D skipped: destination textureId=%d mip=%u out of range (mips=%u)",
|
||||||
|
texture.GetExternalIndex(), mipLevel, resource->mipLevels);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBinding.image = resource->image;
|
||||||
|
outBinding.trackedLayout = &resource->layout;
|
||||||
|
outBinding.aspectMask = resource->aspect;
|
||||||
|
outBinding.extent = {
|
||||||
|
static_cast<Int>(std::max(1u, resource->extent.width >> mipLevel)),
|
||||||
|
static_cast<Int>(std::max(1u, resource->extent.height >> mipLevel))};
|
||||||
|
outBinding.mipLevel = mipLevel;
|
||||||
|
outBinding.mipLevelCount = 1;
|
||||||
|
outBinding.label = "destination texture";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static BlitSurfaceTransform ToBlitSurfaceTransform(VkSurfaceTransformFlagBitsKHR preTransform) {
|
static BlitSurfaceTransform ToBlitSurfaceTransform(VkSurfaceTransformFlagBitsKHR preTransform) {
|
||||||
switch (preTransform) {
|
switch (preTransform) {
|
||||||
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
|
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
|
||||||
@@ -925,6 +1008,135 @@ void main() {
|
|||||||
m_clearManager->QueueClear(mask, payload, *fbo);
|
m_clearManager->QueueClear(mask, payload, *fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer,
|
||||||
|
const ClearAttachmentPayload& clearPayload) {
|
||||||
|
m_clearManager->CollectGarbage();
|
||||||
|
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
|
||||||
|
MOBILEGL_ASSERT(fbo, "VulkanRenderer::QueueClearBufferPayload: draw framebuffer not found");
|
||||||
|
|
||||||
|
auto queueAttachmentClear = [&](FramebufferAttachmentType attachmentType) {
|
||||||
|
if (attachmentType == FramebufferAttachmentType::None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& attachment = fbo->GetAttachment(attachmentType);
|
||||||
|
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto texture = attachment.GetTexture();
|
||||||
|
if (!texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_clearManager->QueueClear(clearPayload, texture);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (buffer) {
|
||||||
|
case GL_COLOR: {
|
||||||
|
if (drawbuffer < 0 ||
|
||||||
|
drawbuffer >= static_cast<GLint>(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS)) {
|
||||||
|
RecordClearBufferError(__func__, ErrorCode::InvalidValue, "color drawbuffer index is out of range");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queueAttachmentClear(fbo->GetDrawBuffers()[drawbuffer]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case GL_DEPTH:
|
||||||
|
if (drawbuffer != 0) {
|
||||||
|
RecordClearBufferError(__func__, ErrorCode::InvalidValue, "depth clear requires drawbuffer 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queueAttachmentClear(FramebufferAttachmentType::Depth);
|
||||||
|
return;
|
||||||
|
case GL_STENCIL:
|
||||||
|
if (drawbuffer != 0) {
|
||||||
|
RecordClearBufferError(__func__, ErrorCode::InvalidValue, "stencil clear requires drawbuffer 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queueAttachmentClear(FramebufferAttachmentType::Stencil);
|
||||||
|
return;
|
||||||
|
case GL_DEPTH_STENCIL:
|
||||||
|
if (drawbuffer != 0) {
|
||||||
|
RecordClearBufferError(__func__, ErrorCode::InvalidValue, "depth/stencil clear requires drawbuffer 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queueAttachmentClear(FramebufferAttachmentType::Depth);
|
||||||
|
queueAttachmentClear(FramebufferAttachmentType::Stencil);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
RecordClearBufferError(__func__, ErrorCode::InvalidEnum, "unsupported clear buffer target");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
|
||||||
|
ClearAttachmentPayload payload{};
|
||||||
|
payload.mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||||
|
payload.depth = depth;
|
||||||
|
payload.stencil = static_cast<Uint32>(stencil);
|
||||||
|
QueueClearBufferPayload(buffer, drawbuffer, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClearAttachmentPayload payload{};
|
||||||
|
switch (buffer) {
|
||||||
|
case GL_COLOR:
|
||||||
|
payload.mask = GL_COLOR_BUFFER_BIT;
|
||||||
|
payload.color = FloatVec4(value[0], value[1], value[2], value[3]);
|
||||||
|
break;
|
||||||
|
case GL_DEPTH:
|
||||||
|
payload.mask = GL_DEPTH_BUFFER_BIT;
|
||||||
|
payload.depth = value[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QueueClearBufferPayload(buffer, drawbuffer, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClearAttachmentPayload payload{};
|
||||||
|
switch (buffer) {
|
||||||
|
case GL_COLOR:
|
||||||
|
payload.mask = GL_COLOR_BUFFER_BIT;
|
||||||
|
payload.color = FloatVec4(static_cast<Float>(value[0]), static_cast<Float>(value[1]),
|
||||||
|
static_cast<Float>(value[2]), static_cast<Float>(value[3]));
|
||||||
|
break;
|
||||||
|
case GL_STENCIL:
|
||||||
|
payload.mask = GL_STENCIL_BUFFER_BIT;
|
||||||
|
payload.stencil = value[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QueueClearBufferPayload(buffer, drawbuffer, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClearAttachmentPayload payload{};
|
||||||
|
switch (buffer) {
|
||||||
|
case GL_COLOR:
|
||||||
|
payload.mask = GL_COLOR_BUFFER_BIT;
|
||||||
|
payload.color = FloatVec4(static_cast<Float>(value[0]), static_cast<Float>(value[1]),
|
||||||
|
static_cast<Float>(value[2]), static_cast<Float>(value[3]));
|
||||||
|
break;
|
||||||
|
case GL_STENCIL:
|
||||||
|
payload.mask = GL_STENCIL_BUFFER_BIT;
|
||||||
|
payload.stencil = static_cast<Uint32>(std::max(value[0], 0));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QueueClearBufferPayload(buffer, drawbuffer, payload);
|
||||||
|
}
|
||||||
|
|
||||||
Bool VulkanRenderer::MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
Bool VulkanRenderer::MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||||
MG_State::GLState::ITextureObject& texture) {
|
MG_State::GLState::ITextureObject& texture) {
|
||||||
ClearAttachmentPayload clearPayload{};
|
ClearAttachmentPayload clearPayload{};
|
||||||
@@ -952,7 +1164,6 @@ void main() {
|
|||||||
texture.GetExternalIndex());
|
texture.GetExternalIndex());
|
||||||
|
|
||||||
VkImageSubresourceRange subresourceRange{};
|
VkImageSubresourceRange subresourceRange{};
|
||||||
subresourceRange.aspectMask = resource->aspect;
|
|
||||||
subresourceRange.baseMipLevel = 0;
|
subresourceRange.baseMipLevel = 0;
|
||||||
subresourceRange.levelCount = 1;
|
subresourceRange.levelCount = 1;
|
||||||
subresourceRange.baseArrayLayer = 0;
|
subresourceRange.baseArrayLayer = 0;
|
||||||
@@ -960,6 +1171,7 @@ void main() {
|
|||||||
|
|
||||||
VkImageLayout sampledLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
VkImageLayout sampledLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||||
|
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
VkClearColorValue clearValue{};
|
VkClearColorValue clearValue{};
|
||||||
clearValue.float32[0] = clearPayload.color.x();
|
clearValue.float32[0] = clearPayload.color.x();
|
||||||
clearValue.float32[1] = clearPayload.color.y();
|
clearValue.float32[1] = clearPayload.color.y();
|
||||||
@@ -968,6 +1180,19 @@ void main() {
|
|||||||
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
&clearValue, 1, &subresourceRange);
|
&clearValue, 1, &subresourceRange);
|
||||||
} else {
|
} 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{};
|
VkClearDepthStencilValue clearValue{};
|
||||||
clearValue.depth = clearPayload.depth;
|
clearValue.depth = clearPayload.depth;
|
||||||
clearValue.stencil = clearPayload.stencil;
|
clearValue.stencil = clearPayload.stencil;
|
||||||
@@ -1212,7 +1437,7 @@ void main() {
|
|||||||
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask);
|
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask);
|
||||||
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain source image", __func__);
|
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain source image", __func__);
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, srcLayout);
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
} else {
|
} else {
|
||||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
@@ -1230,7 +1455,7 @@ void main() {
|
|||||||
dstStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
dstStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, dstBinding.aspectMask);
|
dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, dstBinding.aspectMask);
|
||||||
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain destination image", __func__);
|
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain destination image", __func__);
|
||||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, dstLayout);
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
} else {
|
} else {
|
||||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
@@ -1259,6 +1484,172 @@ void main() {
|
|||||||
1, &blitRegion, filter == GL_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
|
1, &blitRegion, filter == GL_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanRenderer::CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||||
|
GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||||
|
if (textureTarget != TextureTarget::Texture2D) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D currently only supports GL_TEXTURE_2D destinations.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (level < 0) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidValue,
|
||||||
|
"CopyTexSubImage2D level must be non-negative.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||||
|
auto destinationTexture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject();
|
||||||
|
if (destinationTexture == nullptr) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D requires a bound destination texture.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||||
|
if (readFbo == nullptr) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D requires a framebuffer bound to GL_READ_FRAMEBUFFER.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& frame = m_frameContext.GetCurrent();
|
||||||
|
if (!frame.isCommandRecording) {
|
||||||
|
m_frameContext.BeginCommandRecording();
|
||||||
|
m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
|
||||||
|
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bool readIsDefaultFbo =
|
||||||
|
(readFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||||
|
|
||||||
|
BlitImageBinding srcBinding{};
|
||||||
|
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
|
||||||
|
srcBinding)) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D requires a complete color read buffer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlitImageBinding dstBinding{};
|
||||||
|
if (!ResolveTextureCopyDestinationBinding(*destinationTexture, static_cast<Uint32>(level), *m_textureManager,
|
||||||
|
dstBinding)) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D failed to resolve the destination texture.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readIsDefaultFbo) {
|
||||||
|
const auto& sourceAttachment = readFbo->GetAttachment(readFbo->GetReadBuffer());
|
||||||
|
auto sourceTexture = sourceAttachment.GetTexture();
|
||||||
|
MOBILEGL_ASSERT(sourceTexture != nullptr, "CopyTexSubImage2D: source texture attachment is null");
|
||||||
|
const Bool clearReady = MaterializePendingClearForTexture(frame.commandBuffer, *sourceTexture);
|
||||||
|
MOBILEGL_ASSERT(clearReady,
|
||||||
|
"CopyTexSubImage2D: failed to materialize pending clear for source textureId=%d",
|
||||||
|
sourceTexture->GetExternalIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkImageLayout srcOriginalLayout = readIsDefaultFbo
|
||||||
|
? m_swapchainObject.GetImageLayout(m_imageIndexAcquired)
|
||||||
|
: *srcBinding.trackedLayout;
|
||||||
|
if (srcOriginalLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
|
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
|
||||||
|
"CopyTexSubImage2D source image has undefined layout.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkImageLayout dstOriginalLayout = *dstBinding.trackedLayout;
|
||||||
|
const VkImageLayout dstRestoreLayout = dstOriginalLayout == VK_IMAGE_LAYOUT_UNDEFINED
|
||||||
|
? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||||
|
: dstOriginalLayout;
|
||||||
|
|
||||||
|
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags srcAccessMask = 0;
|
||||||
|
GetImageTransitionSourceState(srcOriginalLayout, srcStageMask, srcAccessMask);
|
||||||
|
if (readIsDefaultFbo) {
|
||||||
|
VkImageLayout srcTrackedLayout = srcOriginalLayout;
|
||||||
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, srcBinding.image, srcTrackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask,
|
||||||
|
srcBinding.mipLevel, srcBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain source image", __func__);
|
||||||
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, srcTrackedLayout);
|
||||||
|
} else {
|
||||||
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask,
|
||||||
|
srcBinding.mipLevel, srcBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(ok, "%s: failed to transition source image", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags dstAccessMask = 0;
|
||||||
|
GetImageTransitionSourceState(dstOriginalLayout, dstStageMask, dstAccessMask);
|
||||||
|
Bool dstReady = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
dstStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, dstBinding.aspectMask,
|
||||||
|
dstBinding.mipLevel, dstBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(dstReady, "%s: failed to transition destination image", __func__);
|
||||||
|
|
||||||
|
VkImageCopy copyRegion{};
|
||||||
|
copyRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
|
||||||
|
copyRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
|
||||||
|
copyRegion.srcSubresource.baseArrayLayer = 0;
|
||||||
|
copyRegion.srcSubresource.layerCount = 1;
|
||||||
|
copyRegion.srcOffset = {x, y, 0};
|
||||||
|
copyRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
|
||||||
|
copyRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
|
||||||
|
copyRegion.dstSubresource.baseArrayLayer = 0;
|
||||||
|
copyRegion.dstSubresource.layerCount = 1;
|
||||||
|
copyRegion.dstOffset = {xoffset, yoffset, 0};
|
||||||
|
copyRegion.extent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
|
||||||
|
vkCmdCopyImage(frame.commandBuffer,
|
||||||
|
srcBinding.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
dstBinding.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1, ©Region);
|
||||||
|
|
||||||
|
VkPipelineStageFlags srcRestoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags srcRestoreAccessMask = 0;
|
||||||
|
GetImageTransitionDestinationState(srcOriginalLayout, srcRestoreStageMask, srcRestoreAccessMask);
|
||||||
|
if (readIsDefaultFbo) {
|
||||||
|
VkImageLayout srcTrackedLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
|
||||||
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, srcBinding.image, srcTrackedLayout, srcOriginalLayout,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, srcRestoreStageMask,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT, srcRestoreAccessMask, srcBinding.aspectMask,
|
||||||
|
srcBinding.mipLevel, srcBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(ok, "%s: failed to restore swapchain source image layout", __func__);
|
||||||
|
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, srcTrackedLayout);
|
||||||
|
} else {
|
||||||
|
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, srcOriginalLayout,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, srcRestoreStageMask,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT, srcRestoreAccessMask, srcBinding.aspectMask,
|
||||||
|
srcBinding.mipLevel, srcBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(ok, "%s: failed to restore source image layout", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineStageFlags dstRestoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
VkAccessFlags dstRestoreAccessMask = 0;
|
||||||
|
GetImageTransitionDestinationState(dstRestoreLayout, dstRestoreStageMask, dstRestoreAccessMask);
|
||||||
|
Bool dstRestored = VkTextureManager::TransitionImageLayout(
|
||||||
|
frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, dstRestoreLayout,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT, dstRestoreStageMask,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT, dstRestoreAccessMask, dstBinding.aspectMask,
|
||||||
|
dstBinding.mipLevel, dstBinding.mipLevelCount);
|
||||||
|
MOBILEGL_ASSERT(dstRestored, "%s: failed to restore destination image layout", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanRenderer::DrawArrays(const DrawCmd& payload) {
|
void VulkanRenderer::DrawArrays(const DrawCmd& payload) {
|
||||||
auto& frame = m_frameContext.GetCurrent();
|
auto& frame = m_frameContext.GetCurrent();
|
||||||
|
|
||||||
@@ -1976,8 +2367,7 @@ void main() {
|
|||||||
|
|
||||||
VkClearAttachment clearAttachment{};
|
VkClearAttachment clearAttachment{};
|
||||||
clearAttachment.clearValue.depthStencil = {1.0f, 0};
|
clearAttachment.clearValue.depthStencil = {1.0f, 0};
|
||||||
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
|
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
|
|
||||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
clearAttachment.colorAttachment = pending.attachmentIndex;
|
clearAttachment.colorAttachment = pending.attachmentIndex;
|
||||||
clearAttachment.clearValue.color = {
|
clearAttachment.clearValue.color = {
|
||||||
@@ -1986,15 +2376,19 @@ void main() {
|
|||||||
clearPayload.color.z(),
|
clearPayload.color.z(),
|
||||||
clearPayload.color.w()
|
clearPayload.color.w()
|
||||||
};
|
};
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
|
|
||||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
||||||
clearAttachment.clearValue.depthStencil.depth = clearPayload.depth;
|
|
||||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
|
|
||||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
||||||
clearAttachment.clearValue.depthStencil.stencil = clearPayload.stencil;
|
|
||||||
} else {
|
} else {
|
||||||
|
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||||
|
clearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
clearAttachment.clearValue.depthStencil.depth = clearPayload.depth;
|
||||||
|
}
|
||||||
|
if ((clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
|
||||||
|
clearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
clearAttachment.clearValue.depthStencil.stencil = clearPayload.stencil;
|
||||||
|
}
|
||||||
|
if (clearAttachment.aspectMask == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||||
m_clearManager->PopPendingClear(pending.texture);
|
m_clearManager->PopPendingClear(pending.texture);
|
||||||
|
|||||||
@@ -115,9 +115,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const RenderPassEntry& compatibleRenderPassEntry);
|
const RenderPassEntry& compatibleRenderPassEntry);
|
||||||
|
|
||||||
void Clear(GLbitfield mask);
|
void Clear(GLbitfield mask);
|
||||||
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||||
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||||
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||||
GLbitfield mask, GLenum filter);
|
GLbitfield mask, GLenum filter);
|
||||||
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||||
|
GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
void DrawArrays(const DrawCmd& payload);
|
void DrawArrays(const DrawCmd& payload);
|
||||||
void DrawElements(const DrawIndexedCmd& payload);
|
void DrawElements(const DrawIndexedCmd& payload);
|
||||||
void MultiDrawElements(const MultiDrawIndexedCmd& payloads);
|
void MultiDrawElements(const MultiDrawIndexedCmd& payloads);
|
||||||
@@ -146,6 +152,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 samplerBinding = 0;
|
Uint32 samplerBinding = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload);
|
||||||
|
|
||||||
NativeWindowType m_window = 0;
|
NativeWindowType m_window = 0;
|
||||||
VulkanRendererConfig m_config;
|
VulkanRendererConfig m_config;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user