mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Chore] (MG_Backend/DirectVulkan): implements BlitFramebuffer using backend manager APIs
This commit is contained in:
@@ -538,6 +538,28 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
|
||||
const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const {
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
||||
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
|
||||
if (resource == nullptr || !IsValidSampledImageLayout(resource->layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outImageInfo = {
|
||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler),
|
||||
.imageView = resource->view,
|
||||
.imageLayout = resource->layout,
|
||||
};
|
||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||
@@ -786,7 +808,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
Uint32 frameIndex) {
|
||||
return BindProgramUniformBuffers(commandBuffer, program, frameIndex, nullptr);
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride) {
|
||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
||||
MOBILEGL_ASSERT(layout != nullptr,
|
||||
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
||||
|
||||
auto& frame = m_frames[frameIndex];
|
||||
if (frame.descriptorPools.empty()) {
|
||||
@@ -903,7 +934,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
dynamicOffsets.push_back(static_cast<Uint32>(payloadOffset));
|
||||
} else {
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
Bool hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
|
||||
Bool hasImage = false;
|
||||
if (samplerBindingOverride != nullptr &&
|
||||
samplerBindingOverride->binding == binding &&
|
||||
samplerBindingOverride->texture != nullptr &&
|
||||
samplerBindingOverride->sampler != nullptr) {
|
||||
hasImage = ResolveSamplerDescriptorOverride(*samplerBindingOverride, imageInfo);
|
||||
} else {
|
||||
hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
|
||||
}
|
||||
if (!hasImage) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
|
||||
binding);
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject;
|
||||
class ProgramObject;
|
||||
class SamplerObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
@@ -28,6 +30,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
CombinedImageSampler
|
||||
};
|
||||
|
||||
struct SamplerBindingOverride {
|
||||
Uint32 binding = 0;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
const MG_State::GLState::SamplerObject* sampler = nullptr;
|
||||
};
|
||||
|
||||
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
|
||||
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
|
||||
@@ -40,6 +48,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride);
|
||||
|
||||
private:
|
||||
struct DescriptorPoolBucket {
|
||||
@@ -79,6 +90,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
|
||||
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
||||
Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset);
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_Util/ShaderTranspiler/ShaderCompiler.h"
|
||||
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
||||
#include "MG_State/GLState/SamplerState/SamplerObject.h"
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
#include "MG_Util/Converters/MGToVk/RenderStateEnumConverter.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
@@ -74,6 +75,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
namespace {
|
||||
static constexpr Uint kHiddenBlitProgramId = 0xFFFFFFF0u;
|
||||
static constexpr Uint kHiddenBlitVertexShaderId = 0xFFFFFFF1u;
|
||||
static constexpr Uint kHiddenBlitFragmentShaderId = 0xFFFFFFF2u;
|
||||
static constexpr Uint kHiddenBlitNearestSamplerId = 0xFFFFFFF3u;
|
||||
static constexpr Uint kHiddenBlitLinearSamplerId = 0xFFFFFFF4u;
|
||||
|
||||
enum class BlitSurfaceTransform : Uint32 {
|
||||
Identity = 0,
|
||||
Rotate90 = 1,
|
||||
@@ -513,25 +520,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VulkanRenderer::InitializeBlitResources() {
|
||||
ShutdownBlitResources();
|
||||
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
|
||||
static constexpr StringView kVertexShaderSource = R"(#version 450
|
||||
layout(push_constant) uniform BlitPushConstants {
|
||||
vec4 srcRect;
|
||||
vec4 dstRect;
|
||||
uint surfaceTransform;
|
||||
} pc;
|
||||
static constexpr const char* kVertexShaderSource = R"(#version 460 core
|
||||
uniform vec4 uSrcRect;
|
||||
uniform vec4 uDstRect;
|
||||
uniform int uSurfaceTransform;
|
||||
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
|
||||
vec2 ApplySurfaceTransform(vec2 position, uint transform) {
|
||||
vec2 ApplySurfaceTransform(vec2 position, int transform) {
|
||||
vec2 p = position;
|
||||
p.y = -p.y;
|
||||
if (transform == 1u) {
|
||||
if (transform == 1) {
|
||||
p = vec2(-p.y, p.x);
|
||||
} else if (transform == 2u) {
|
||||
} else if (transform == 2) {
|
||||
p = -p;
|
||||
} else if (transform == 3u) {
|
||||
} else if (transform == 3) {
|
||||
p = vec2(p.y, -p.x);
|
||||
}
|
||||
return p;
|
||||
@@ -543,16 +546,16 @@ void main() {
|
||||
vec2(2.0, 0.0),
|
||||
vec2(0.0, 2.0)
|
||||
);
|
||||
vec2 uv = uvTri[gl_VertexIndex];
|
||||
vec2 dst = pc.dstRect.xy + uv * pc.dstRect.zw;
|
||||
vec2 uv = uvTri[gl_VertexID];
|
||||
vec2 dst = uDstRect.xy + uv * uDstRect.zw;
|
||||
vec2 clip = dst * 2.0 - 1.0;
|
||||
clip = ApplySurfaceTransform(clip, pc.surfaceTransform);
|
||||
clip = ApplySurfaceTransform(clip, uSurfaceTransform);
|
||||
gl_Position = vec4(clip, 0.0, 1.0);
|
||||
vTexCoord = pc.srcRect.xy + uv * pc.srcRect.zw;
|
||||
vTexCoord = uSrcRect.xy + uv * uSrcRect.zw;
|
||||
}
|
||||
)";
|
||||
static constexpr StringView kFragmentShaderSource = R"(#version 450
|
||||
layout(set = 0, binding = 0) uniform sampler2D uSource;
|
||||
static constexpr const char* kFragmentShaderSource = R"(#version 460 core
|
||||
layout(binding = 0) uniform sampler2D uSource;
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
@@ -561,145 +564,77 @@ void main() {
|
||||
}
|
||||
)";
|
||||
|
||||
auto vs = ShaderCompiler::CompileShader({GL_VERTEX_SHADER, kVertexShaderSource, {}});
|
||||
if (!vs) {
|
||||
MGLOG_E("InitializeBlitResources failed: vertex shader compile error: %s", vs.error().log.c_str());
|
||||
return false;
|
||||
}
|
||||
auto fs = ShaderCompiler::CompileShader({GL_FRAGMENT_SHADER, kFragmentShaderSource, {}});
|
||||
if (!fs) {
|
||||
MGLOG_E("InitializeBlitResources failed: fragment shader compile error: %s", fs.error().log.c_str());
|
||||
return false;
|
||||
}
|
||||
auto program = ShaderCompiler::LinkProgram({{vs.value(), fs.value()}, {}, {}});
|
||||
if (!program) {
|
||||
MGLOG_E("InitializeBlitResources failed: link error: %s", program.error().log.c_str());
|
||||
return false;
|
||||
}
|
||||
auto spirv = ShaderCompiler::GetSpirvBinaryFromProgram({{GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}, *program.value()});
|
||||
if (!spirv || spirv->size() != 2) {
|
||||
MGLOG_E("InitializeBlitResources failed: SPIR-V generation failed");
|
||||
auto vertexShader = MakeShared<MG_State::GLState::ShaderObject>(ShaderStage::Vertex, kHiddenBlitVertexShaderId);
|
||||
vertexShader->SetShaderSource(kVertexShaderSource);
|
||||
vertexShader->Compile();
|
||||
if (!vertexShader->GetCompileStatus()) {
|
||||
MGLOG_E("InitializeBlitResources failed: vertex shader compile error: %s", vertexShader->GetInfoLog().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (SizeT i = 0; i < spirv->size(); ++i) {
|
||||
const auto& moduleSpv = spirv.value()[i];
|
||||
VkShaderModuleCreateInfo smci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
||||
smci.codeSize = moduleSpv.size() * sizeof(Uint);
|
||||
smci.pCode = moduleSpv.data();
|
||||
|
||||
VkShaderModule module = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateShaderModule(m_device, &smci, nullptr, &module), "InitializeBlitResources, vkCreateShaderModule");
|
||||
m_blitPipelineResources.shaderModules.push_back(module);
|
||||
|
||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||
stage.stage = (i == 0) ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
stage.module = module;
|
||||
stage.pName = "main";
|
||||
m_blitPipelineResources.shaderStages.push_back(stage);
|
||||
auto fragmentShader = MakeShared<MG_State::GLState::ShaderObject>(ShaderStage::Fragment, kHiddenBlitFragmentShaderId);
|
||||
fragmentShader->SetShaderSource(kFragmentShaderSource);
|
||||
fragmentShader->Compile();
|
||||
if (!fragmentShader->GetCompileStatus()) {
|
||||
MGLOG_E("InitializeBlitResources failed: fragment shader compile error: %s", fragmentShader->GetInfoLog().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutBinding binding{};
|
||||
binding.binding = 0;
|
||||
binding.descriptorCount = 1;
|
||||
binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
m_blitResources.program = MakeShared<MG_State::GLState::ProgramObject>(kHiddenBlitProgramId);
|
||||
m_blitResources.program->AttachShader(vertexShader);
|
||||
m_blitResources.program->AttachShader(fragmentShader);
|
||||
m_blitResources.program->Link(false);
|
||||
if (!m_blitResources.program->GetLinkStatus()) {
|
||||
MGLOG_E("InitializeBlitResources failed: program link error: %s", m_blitResources.program->GetInfoLog().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo setLayoutInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
|
||||
setLayoutInfo.bindingCount = 1;
|
||||
setLayoutInfo.pBindings = &binding;
|
||||
VK_VERIFY(vkCreateDescriptorSetLayout(m_device, &setLayoutInfo, nullptr, &m_blitPipelineResources.descriptorSetLayout),
|
||||
"InitializeBlitResources, vkCreateDescriptorSetLayout");
|
||||
m_blitResources.srcRectLocation = m_blitResources.program->GetUniformLocation("uSrcRect");
|
||||
m_blitResources.dstRectLocation = m_blitResources.program->GetUniformLocation("uDstRect");
|
||||
m_blitResources.surfaceTransformLocation = m_blitResources.program->GetUniformLocation("uSurfaceTransform");
|
||||
MOBILEGL_ASSERT(m_blitResources.srcRectLocation >= 0, "InitializeBlitResources: missing uSrcRect");
|
||||
MOBILEGL_ASSERT(m_blitResources.dstRectLocation >= 0, "InitializeBlitResources: missing uDstRect");
|
||||
MOBILEGL_ASSERT(m_blitResources.surfaceTransformLocation >= 0,
|
||||
"InitializeBlitResources: missing uSurfaceTransform");
|
||||
MOBILEGL_ASSERT(m_blitResources.program->GetUBOSize() > 0,
|
||||
"InitializeBlitResources: blit program global UBO is empty");
|
||||
|
||||
VkPushConstantRange pushConstantRange{};
|
||||
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
pushConstantRange.offset = 0;
|
||||
pushConstantRange.size = sizeof(BlitPushConstants);
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
pipelineLayoutInfo.setLayoutCount = 1;
|
||||
pipelineLayoutInfo.pSetLayouts = &m_blitPipelineResources.descriptorSetLayout;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
|
||||
VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_blitPipelineResources.pipelineLayout),
|
||||
"InitializeBlitResources, vkCreatePipelineLayout");
|
||||
|
||||
VkDescriptorPoolSize poolSize{};
|
||||
poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
poolSize.descriptorCount = m_frameContext.GetFrameCount() > 0 ? m_frameContext.GetFrameCount() : m_config.MaxFramesInFlight;
|
||||
VkDescriptorPoolCreateInfo poolInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO};
|
||||
poolInfo.maxSets = poolSize.descriptorCount;
|
||||
poolInfo.poolSizeCount = 1;
|
||||
poolInfo.pPoolSizes = &poolSize;
|
||||
VK_VERIFY(vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &m_blitPipelineResources.descriptorPool),
|
||||
"InitializeBlitResources, vkCreateDescriptorPool");
|
||||
|
||||
const Uint32 setCount = std::max<Uint32>(1, m_config.MaxFramesInFlight);
|
||||
m_blitPipelineResources.descriptorSets.resize(setCount, VK_NULL_HANDLE);
|
||||
Vector<VkDescriptorSetLayout> layouts(setCount, m_blitPipelineResources.descriptorSetLayout);
|
||||
VkDescriptorSetAllocateInfo allocInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||
allocInfo.descriptorPool = m_blitPipelineResources.descriptorPool;
|
||||
allocInfo.descriptorSetCount = setCount;
|
||||
allocInfo.pSetLayouts = layouts.data();
|
||||
VK_VERIFY(vkAllocateDescriptorSets(m_device, &allocInfo, m_blitPipelineResources.descriptorSets.data()),
|
||||
"InitializeBlitResources, vkAllocateDescriptorSets");
|
||||
|
||||
auto createSampler = [&](VkFilter filter, VkSampler& outSampler) {
|
||||
VkSamplerCreateInfo samplerInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
||||
samplerInfo.magFilter = filter;
|
||||
samplerInfo.minFilter = filter;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.minLod = 0.f;
|
||||
samplerInfo.maxLod = 0.f;
|
||||
samplerInfo.maxAnisotropy = 1.f;
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &outSampler),
|
||||
"InitializeBlitResources, vkCreateSampler");
|
||||
auto createSampler = [](Uint externalIndex, SamplerFilterMode filter) {
|
||||
auto sampler = MakeShared<MG_State::GLState::SamplerObject>(externalIndex);
|
||||
sampler->SetWrapS(SamplerWrapMode::ClampToEdge);
|
||||
sampler->SetWrapT(SamplerWrapMode::ClampToEdge);
|
||||
sampler->SetWrapR(SamplerWrapMode::ClampToEdge);
|
||||
sampler->SetMinFilter(filter);
|
||||
sampler->SetMagFilter(filter);
|
||||
sampler->SetMipmapMode(SamplerMipmapMode::None);
|
||||
sampler->SetLodRange(0.0f, 0.0f);
|
||||
return sampler;
|
||||
};
|
||||
createSampler(VK_FILTER_NEAREST, m_blitPipelineResources.nearestSampler);
|
||||
createSampler(VK_FILTER_LINEAR, m_blitPipelineResources.linearSampler);
|
||||
|
||||
m_blitResources.nearestSampler = createSampler(kHiddenBlitNearestSamplerId, SamplerFilterMode::Nearest);
|
||||
m_blitResources.linearSampler = createSampler(kHiddenBlitLinearSamplerId, SamplerFilterMode::Linear);
|
||||
m_blitResources.samplerBinding = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanRenderer::ShutdownBlitResources() {
|
||||
if (m_device == VK_NULL_HANDLE) {
|
||||
m_blitPipelineResources = {};
|
||||
return;
|
||||
}
|
||||
if (m_blitPipelineResources.nearestSampler != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(m_device, m_blitPipelineResources.nearestSampler, nullptr);
|
||||
}
|
||||
if (m_blitPipelineResources.linearSampler != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(m_device, m_blitPipelineResources.linearSampler, nullptr);
|
||||
}
|
||||
if (m_blitPipelineResources.descriptorPool != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorPool(m_device, m_blitPipelineResources.descriptorPool, nullptr);
|
||||
}
|
||||
if (m_blitPipelineResources.pipelineLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyPipelineLayout(m_device, m_blitPipelineResources.pipelineLayout, nullptr);
|
||||
}
|
||||
if (m_blitPipelineResources.descriptorSetLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayout(m_device, m_blitPipelineResources.descriptorSetLayout, nullptr);
|
||||
}
|
||||
for (auto module : m_blitPipelineResources.shaderModules) {
|
||||
if (module != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(m_device, module, nullptr);
|
||||
}
|
||||
}
|
||||
m_blitPipelineResources = {};
|
||||
m_blitResources = {};
|
||||
}
|
||||
|
||||
VkPipeline VulkanRenderer::GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry) {
|
||||
MOBILEGL_ASSERT(m_blitResources.program != nullptr, "GetOrCreateBlitPipeline: blit program is null");
|
||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "GetOrCreateBlitPipeline: program factory is null");
|
||||
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "GetOrCreateBlitPipeline: descriptor binder is null");
|
||||
|
||||
static const VkPipelineVertexInputStateCreateInfo kEmptyVertexInputState {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
|
||||
};
|
||||
ProgramFactory::CompileOptionFlags transformFlags = 0;
|
||||
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(*m_blitResources.program, transformFlags);
|
||||
PipelineFactory::PipelineCreatePayload payload{
|
||||
.programHash = 0xB17FB17FULL,
|
||||
.programHash = m_programFactory->ComputeHash(*m_blitResources.program, transformFlags),
|
||||
.vertexInputHash = 0,
|
||||
.pipelineLayout = m_blitPipelineResources.pipelineLayout,
|
||||
.pipelineLayout = m_uniformDescriptorBinder->GetOrCreatePipelineLayout(*m_blitResources.program),
|
||||
.renderPass = renderPassEntry.renderPass,
|
||||
.subpass = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
@@ -715,7 +650,7 @@ void main() {
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
.stages = &m_blitPipelineResources.shaderStages,
|
||||
.stages = &stages,
|
||||
.vertexInputState = &kEmptyVertexInputState
|
||||
};
|
||||
return m_pipelineFactory->GetOrCreatePipeline(payload);
|
||||
@@ -952,8 +887,7 @@ void main() {
|
||||
sourceTexture->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
auto* sourceResource = m_textureManager->SyncTextureAndGetDescriptor(*sourceTexture);
|
||||
if (sourceResource == nullptr) {
|
||||
if (m_textureManager->SyncTextureAndGetDescriptor(*sourceTexture) == nullptr) {
|
||||
MGLOG_E("BlitFramebuffer skipped: failed to resolve source textureId=%d after sampling transition",
|
||||
sourceTexture->GetExternalIndex());
|
||||
return false;
|
||||
@@ -977,30 +911,16 @@ void main() {
|
||||
scissor.extent = {static_cast<Uint32>(renderPassEntry.extent.x()), static_cast<Uint32>(renderPassEntry.extent.y())};
|
||||
vkCmdSetScissor(frame.commandBuffer, 0, 1, &scissor);
|
||||
|
||||
MOBILEGL_ASSERT(m_blitResources.program != nullptr, "TryBlitToDefaultFramebufferWithShader: blit program is null");
|
||||
const VkPipeline pipeline = GetOrCreateBlitPipeline(renderPassEntry);
|
||||
MOBILEGL_ASSERT(pipeline != VK_NULL_HANDLE, "TryBlitToDefaultFramebufferWithShader: blit pipeline is null");
|
||||
vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
const Uint32 frameIndex = m_frameContext.GetCurrentFrameIndex() % static_cast<Uint32>(m_blitPipelineResources.descriptorSets.size());
|
||||
const VkSampler sampler = (filter == GL_LINEAR) ? m_blitPipelineResources.linearSampler
|
||||
: m_blitPipelineResources.nearestSampler;
|
||||
VkDescriptorImageInfo imageInfo{
|
||||
.sampler = sampler,
|
||||
.imageView = sourceResource->view,
|
||||
.imageLayout = sourceResource->layout,
|
||||
};
|
||||
VkWriteDescriptorSet write{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
|
||||
write.dstSet = m_blitPipelineResources.descriptorSets[frameIndex];
|
||||
write.dstBinding = 0;
|
||||
write.descriptorCount = 1;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write.pImageInfo = &imageInfo;
|
||||
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);
|
||||
auto* blitProgramData = static_cast<Uint8*>(m_blitResources.program->MapUBO());
|
||||
MOBILEGL_ASSERT(blitProgramData != nullptr, "TryBlitToDefaultFramebufferWithShader: blit UBO is null");
|
||||
std::fill(blitProgramData, blitProgramData + m_blitResources.program->GetUBOSize(), Uint8{0});
|
||||
|
||||
vkCmdBindDescriptorSets(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_blitPipelineResources.pipelineLayout, 0, 1,
|
||||
&m_blitPipelineResources.descriptorSets[frameIndex], 0, nullptr);
|
||||
|
||||
BlitPushConstants pushConstants{};
|
||||
BlitUniformData blitUniformData{};
|
||||
const float srcWidth = static_cast<float>(srcBinding.extent.x());
|
||||
const float srcHeight = static_cast<float>(srcBinding.extent.y());
|
||||
const float dstWidth = static_cast<float>(dstBinding.extent.x());
|
||||
@@ -1016,19 +936,38 @@ void main() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pushConstants.srcRect[0] = static_cast<float>(srcX0) / srcWidth;
|
||||
pushConstants.srcRect[1] = static_cast<float>(srcY0) / srcHeight;
|
||||
pushConstants.srcRect[2] = static_cast<float>(srcX1 - srcX0) / srcWidth;
|
||||
pushConstants.srcRect[3] = static_cast<float>(srcY1 - srcY0) / srcHeight;
|
||||
pushConstants.dstRect[0] = static_cast<float>(dstX0) / dstNormWidth;
|
||||
pushConstants.dstRect[1] = static_cast<float>(dstY0) / dstNormHeight;
|
||||
pushConstants.dstRect[2] = static_cast<float>(dstX1 - dstX0) / dstNormWidth;
|
||||
pushConstants.dstRect[3] = static_cast<float>(dstY1 - dstY0) / dstNormHeight;
|
||||
pushConstants.surfaceTransform = static_cast<Uint32>(ToBlitSurfaceTransform(m_swapchainObject.GetPreTransform()));
|
||||
blitUniformData.srcRect[0] = static_cast<float>(srcX0) / srcWidth;
|
||||
blitUniformData.srcRect[1] = static_cast<float>(srcY0) / srcHeight;
|
||||
blitUniformData.srcRect[2] = static_cast<float>(srcX1 - srcX0) / srcWidth;
|
||||
blitUniformData.srcRect[3] = static_cast<float>(srcY1 - srcY0) / srcHeight;
|
||||
blitUniformData.dstRect[0] = static_cast<float>(dstX0) / dstNormWidth;
|
||||
blitUniformData.dstRect[1] = static_cast<float>(dstY0) / dstNormHeight;
|
||||
blitUniformData.dstRect[2] = static_cast<float>(dstX1 - dstX0) / dstNormWidth;
|
||||
blitUniformData.dstRect[3] = static_cast<float>(dstY1 - dstY0) / dstNormHeight;
|
||||
blitUniformData.surfaceTransform = static_cast<Int>(ToBlitSurfaceTransform(m_swapchainObject.GetPreTransform()));
|
||||
|
||||
vkCmdPushConstants(frame.commandBuffer, m_blitPipelineResources.pipelineLayout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
||||
sizeof(pushConstants), &pushConstants);
|
||||
auto writeUniform = [&](Int location, const void* data, SizeT size) {
|
||||
MOBILEGL_ASSERT(location >= 0, "TryBlitToDefaultFramebufferWithShader: invalid uniform location");
|
||||
const Uint offset = m_blitResources.program->GetUniformOffset(static_cast<Uint>(location));
|
||||
MOBILEGL_ASSERT(offset + size <= m_blitResources.program->GetUBOSize(),
|
||||
"TryBlitToDefaultFramebufferWithShader: uniform write out of bounds");
|
||||
memcpy(blitProgramData + offset, data, size);
|
||||
};
|
||||
writeUniform(m_blitResources.srcRectLocation, blitUniformData.srcRect, sizeof(blitUniformData.srcRect));
|
||||
writeUniform(m_blitResources.dstRectLocation, blitUniformData.dstRect, sizeof(blitUniformData.dstRect));
|
||||
writeUniform(m_blitResources.surfaceTransformLocation, &blitUniformData.surfaceTransform,
|
||||
sizeof(blitUniformData.surfaceTransform));
|
||||
|
||||
const auto samplerBindingOverride = UniformDescriptorBinder::SamplerBindingOverride{
|
||||
.binding = m_blitResources.samplerBinding,
|
||||
.texture = sourceTexture.get(),
|
||||
.sampler = (filter == GL_LINEAR ? m_blitResources.linearSampler.get()
|
||||
: m_blitResources.nearestSampler.get()),
|
||||
};
|
||||
const Bool bound = m_uniformDescriptorBinder->BindProgramUniformBuffers(
|
||||
frame.commandBuffer, *m_blitResources.program, m_frameContext.GetCurrentFrameIndex(),
|
||||
&samplerBindingOverride);
|
||||
MOBILEGL_ASSERT(bound, "TryBlitToDefaultFramebufferWithShader: BindProgramUniformBuffers failed");
|
||||
vkCmdDraw(frame.commandBuffer, 3, 1, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class FramebufferObject;
|
||||
class ProgramObject;
|
||||
class SamplerObject;
|
||||
class VertexArrayObject;
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -96,22 +97,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void RecreateSwapchain();
|
||||
|
||||
private:
|
||||
struct BlitPushConstants {
|
||||
struct BlitUniformData {
|
||||
float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
Uint32 surfaceTransform = 0;
|
||||
Uint32 padding[3] = {0, 0, 0};
|
||||
Int surfaceTransform = 0;
|
||||
Int padding[3] = {0, 0, 0};
|
||||
};
|
||||
|
||||
struct BlitPipelineResources {
|
||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
||||
Vector<VkDescriptorSet> descriptorSets;
|
||||
Vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||
Vector<VkShaderModule> shaderModules;
|
||||
VkSampler nearestSampler = VK_NULL_HANDLE;
|
||||
VkSampler linearSampler = VK_NULL_HANDLE;
|
||||
struct BlitResources {
|
||||
SharedPtr<MG_State::GLState::ProgramObject> program;
|
||||
SharedPtr<MG_State::GLState::SamplerObject> nearestSampler;
|
||||
SharedPtr<MG_State::GLState::SamplerObject> linearSampler;
|
||||
Int srcRectLocation = -1;
|
||||
Int dstRectLocation = -1;
|
||||
Int surfaceTransformLocation = -1;
|
||||
Uint32 samplerBinding = 0;
|
||||
};
|
||||
|
||||
NativeWindowType m_window = 0;
|
||||
@@ -156,7 +156,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UniquePtr<VkRenderPassManager> m_renderPassManager;
|
||||
UniquePtr<VkTextureManager> m_textureManager;
|
||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||
BlitPipelineResources m_blitPipelineResources;
|
||||
BlitResources m_blitResources;
|
||||
|
||||
void CreateInstance();
|
||||
VkResult SetupDebugMessenger();
|
||||
|
||||
Reference in New Issue
Block a user