diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index 5f26ae9b..96a7f841 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -291,20 +291,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding]; outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject(); - if (!outTexture) { - for (const auto& bindingSlot : textureUnit.GetAllBindingSlots()) { - const auto& fallbackTexture = bindingSlot.GetBoundObject(); - if (!fallbackTexture) { - continue; - } - outTexture = fallbackTexture; - MGLOG_D( - "ResolveSamplerTexture: falling back to bound textureId=%d for sampler binding=%u location=%d unit=%d target=%d", - outTexture->GetExternalIndex(), binding, location, unit, static_cast(preferredTarget)); - break; - } - } - if (!outTexture) { MGLOG_E("ResolveSamplerTexture: no texture bound for sampler binding=%u location=%d unit=%d target=%d", binding, location, unit, static_cast(preferredTarget)); @@ -592,12 +578,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { } else { hasImage = ResolveSamplerDescriptor(commandBuffer, program, programObj, binding, imageInfo); } - MOBILEGL_ASSERT(hasImage, - "UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor", - binding); - MOBILEGL_ASSERT(imageInfo.sampler != VK_NULL_HANDLE && imageInfo.imageView != VK_NULL_HANDLE, - "UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView", - binding); + if (!hasImage) { + MGLOG_E( + "UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor", + binding); + return false; + } + if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) { + MGLOG_E( + "UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView", + binding); + return false; + } imageInfos.push_back(imageInfo); write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write.pImageInfo = &imageInfos.back(); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp index e8987524..c759487e 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp @@ -148,49 +148,61 @@ namespace MobileGL::MG_Backend::DirectVulkan { case DataType::Int16: switch (size) { case 1: - return isInteger ? VK_FORMAT_R16_SINT : VK_FORMAT_R16_SNORM; + return isInteger ? VK_FORMAT_R16_SINT : (normalized ? VK_FORMAT_R16_SNORM : VK_FORMAT_R16_SSCALED); case 2: - return isInteger ? VK_FORMAT_R16G16_SINT : VK_FORMAT_R16G16_SNORM; + return isInteger ? VK_FORMAT_R16G16_SINT + : (normalized ? VK_FORMAT_R16G16_SNORM : VK_FORMAT_R16G16_SSCALED); case 3: - return isInteger ? VK_FORMAT_R16G16B16_SINT : VK_FORMAT_R16G16B16_SNORM; + return isInteger ? VK_FORMAT_R16G16B16_SINT + : (normalized ? VK_FORMAT_R16G16B16_SNORM : VK_FORMAT_R16G16B16_SSCALED); case 4: - return isInteger ? VK_FORMAT_R16G16B16A16_SINT : VK_FORMAT_R16G16B16A16_SNORM; + return isInteger ? VK_FORMAT_R16G16B16A16_SINT + : (normalized ? VK_FORMAT_R16G16B16A16_SNORM : VK_FORMAT_R16G16B16A16_SSCALED); default: return VK_FORMAT_UNDEFINED; } case DataType::Uint16: switch (size) { case 1: - return isInteger ? VK_FORMAT_R16_UINT : VK_FORMAT_R16_UNORM; + return isInteger ? VK_FORMAT_R16_UINT : (normalized ? VK_FORMAT_R16_UNORM : VK_FORMAT_R16_USCALED); case 2: - return isInteger ? VK_FORMAT_R16G16_UINT : VK_FORMAT_R16G16_UNORM; + return isInteger ? VK_FORMAT_R16G16_UINT + : (normalized ? VK_FORMAT_R16G16_UNORM : VK_FORMAT_R16G16_USCALED); case 3: - return isInteger ? VK_FORMAT_R16G16B16_UINT : VK_FORMAT_R16G16B16_UNORM; + return isInteger ? VK_FORMAT_R16G16B16_UINT + : (normalized ? VK_FORMAT_R16G16B16_UNORM : VK_FORMAT_R16G16B16_USCALED); case 4: - return isInteger ? VK_FORMAT_R16G16B16A16_UINT : VK_FORMAT_R16G16B16A16_UNORM; + return isInteger ? VK_FORMAT_R16G16B16A16_UINT + : (normalized ? VK_FORMAT_R16G16B16A16_UNORM : VK_FORMAT_R16G16B16A16_USCALED); default: return VK_FORMAT_UNDEFINED; } case DataType::Int8: switch (size) { case 1: - return isInteger ? VK_FORMAT_R8_SINT : VK_FORMAT_R8_SNORM; + return isInteger ? VK_FORMAT_R8_SINT : (normalized ? VK_FORMAT_R8_SNORM : VK_FORMAT_R8_SSCALED); case 2: - return isInteger ? VK_FORMAT_R8G8_SINT : VK_FORMAT_R8G8_SNORM; + return isInteger ? VK_FORMAT_R8G8_SINT + : (normalized ? VK_FORMAT_R8G8_SNORM : VK_FORMAT_R8G8_SSCALED); case 3: - return isInteger ? VK_FORMAT_R8G8B8_SINT : VK_FORMAT_R8G8B8_SNORM; + return isInteger ? VK_FORMAT_R8G8B8_SINT + : (normalized ? VK_FORMAT_R8G8B8_SNORM : VK_FORMAT_R8G8B8_SSCALED); case 4: - return isInteger ? VK_FORMAT_R8G8B8A8_SINT : VK_FORMAT_R8G8B8A8_SNORM; + return isInteger ? VK_FORMAT_R8G8B8A8_SINT + : (normalized ? VK_FORMAT_R8G8B8A8_SNORM : VK_FORMAT_R8G8B8A8_SSCALED); default: return VK_FORMAT_UNDEFINED; } case DataType::Uint8: switch (size) { case 1: - return isInteger ? VK_FORMAT_R8_UINT : VK_FORMAT_R8_UNORM; + return isInteger ? VK_FORMAT_R8_UINT : (normalized ? VK_FORMAT_R8_UNORM : VK_FORMAT_R8_USCALED); case 2: - return isInteger ? VK_FORMAT_R8G8_UINT : VK_FORMAT_R8G8_UNORM; + return isInteger ? VK_FORMAT_R8G8_UINT + : (normalized ? VK_FORMAT_R8G8_UNORM : VK_FORMAT_R8G8_USCALED); case 3: - return isInteger ? VK_FORMAT_R8G8B8_UINT : VK_FORMAT_R8G8B8_UNORM; + return isInteger ? VK_FORMAT_R8G8B8_UINT + : (normalized ? VK_FORMAT_R8G8B8_UNORM : VK_FORMAT_R8G8B8_USCALED); case 4: - return isInteger ? VK_FORMAT_R8G8B8A8_UINT : VK_FORMAT_R8G8B8A8_UNORM; + return isInteger ? VK_FORMAT_R8G8B8A8_UINT + : (normalized ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_R8G8B8A8_USCALED); default: return VK_FORMAT_UNDEFINED; } default: diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 5bea6c94..7b199e4b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -20,6 +20,25 @@ #include namespace MobileGL::MG_Backend::DirectVulkan { + static VkPipelineColorBlendAttachmentState MakeColorBlendAttachmentState( + Bool blendEnable, + VkBlendFactor srcColorBlendFactor, + VkBlendFactor dstColorBlendFactor, + VkBlendFactor srcAlphaBlendFactor, + VkBlendFactor dstAlphaBlendFactor, + VkColorComponentFlags colorWriteMask) { + VkPipelineColorBlendAttachmentState attachment{}; + attachment.blendEnable = blendEnable ? VK_TRUE : VK_FALSE; + attachment.srcColorBlendFactor = srcColorBlendFactor; + attachment.dstColorBlendFactor = dstColorBlendFactor; + attachment.colorBlendOp = VK_BLEND_OP_ADD; + attachment.srcAlphaBlendFactor = srcAlphaBlendFactor; + attachment.dstAlphaBlendFactor = dstAlphaBlendFactor; + attachment.alphaBlendOp = VK_BLEND_OP_ADD; + attachment.colorWriteMask = colorWriteMask; + return attachment; + } + static Bool ShouldUseTransientVertexIndexBuffer(const MG_State::GLState::BufferObject& bufferObject) { switch (bufferObject.GetUsage()) { case BufferUsage::StreamDraw: @@ -802,16 +821,24 @@ void main() { .depthTestEnable = false, .depthWriteEnable = false, .depthCompareOp = VK_COMPARE_OP_ALWAYS, - .blendEnable = false, - .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, - .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .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 = &programObj.stages, .vertexInputState = &kEmptyVertexInputState }; + static constexpr VkColorComponentFlags kColorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + MOBILEGL_ASSERT(payload.colorAttachmentCount <= PipelineFactory::PipelineCreatePayload::kMaxColorAttachments, + "GetOrCreateBlitPipeline: colorAttachmentCount=%u exceeds payload capacity", + payload.colorAttachmentCount); + for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) { + payload.colorBlendAttachments[i] = MakeColorBlendAttachmentState( + false, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + kColorWriteMask); + } return m_pipelineFactory->GetOrCreatePipeline(payload); } @@ -832,12 +859,12 @@ void main() { auto& vis = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao); auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace); auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest); - BlendFactor srcRGB = BlendFactor::One; - BlendFactor dstRGB = BlendFactor::Zero; - BlendFactor srcAlpha = BlendFactor::One; - BlendFactor dstAlpha = BlendFactor::Zero; - MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); auto mask = MG_State::pGLContext->GetColorMask(); + const auto colorWriteMask = static_cast( + (mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) | + (mask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) | + (mask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) | + (mask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u)); PipelineFactory::PipelineCreatePayload payload { .programHash = programObj.hash, @@ -854,19 +881,26 @@ void main() { .depthTestEnable = depthTestEnabled, .depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(), .depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_State::pGLContext->GetDepthFunc()), - .blendEnable = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::Blend), - .srcColorBlendFactor = MG_Util::ConvertBlendFactorToVkEnum(srcRGB), - .dstColorBlendFactor = MG_Util::ConvertBlendFactorToVkEnum(dstRGB), - .srcAlphaBlendFactor = MG_Util::ConvertBlendFactorToVkEnum(srcAlpha), - .dstAlphaBlendFactor = MG_Util::ConvertBlendFactorToVkEnum(dstAlpha), - .colorWriteMask = ( - (mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) | - (mask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) | - (mask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) | - (mask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u) ), .stages = &programObj.stages, .vertexInputState = &vis.state }; + MOBILEGL_ASSERT(payload.colorAttachmentCount <= PipelineFactory::PipelineCreatePayload::kMaxColorAttachments, + "GetOrCreatePipeline: colorAttachmentCount=%u exceeds payload capacity", + payload.colorAttachmentCount); + for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) { + BlendFactor srcRGB = BlendFactor::One; + BlendFactor dstRGB = BlendFactor::Zero; + BlendFactor srcAlpha = BlendFactor::One; + BlendFactor dstAlpha = BlendFactor::Zero; + MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha); + payload.colorBlendAttachments[i] = MakeColorBlendAttachmentState( + MG_State::pGLContext->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i), + MG_Util::ConvertBlendFactorToVkEnum(srcRGB), + MG_Util::ConvertBlendFactorToVkEnum(dstRGB), + MG_Util::ConvertBlendFactorToVkEnum(srcAlpha), + MG_Util::ConvertBlendFactorToVkEnum(dstAlpha), + colorWriteMask); + } return m_pipelineFactory->GetOrCreatePipeline(payload); } diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 79014bef..80093a59 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -541,6 +541,9 @@ namespace MobileGL::MG_Impl::GLImpl { } else { auto* ttype = programObject.GetUniformTType(location); if (ttype->isTexture() || ttype->isImage()) { + MGLOG_D("%s: program = %d, opaque uniform location = %d, name = '%s', unit = %d", __func__, + programObject.GetExternalIndex(), location, programObject.GetUniformName(location).c_str(), + static_cast(*value)); programObject.SetUniformSamplerOrImageUnitIndex(location, *value); } } diff --git a/MobileGL/MG_Impl/GLImpl/Sampler/GL_Sampler.cpp b/MobileGL/MG_Impl/GLImpl/Sampler/GL_Sampler.cpp index 786f2ce2..2a46e49d 100644 --- a/MobileGL/MG_Impl/GLImpl/Sampler/GL_Sampler.cpp +++ b/MobileGL/MG_Impl/GLImpl/Sampler/GL_Sampler.cpp @@ -167,6 +167,7 @@ namespace MobileGL::MG_Impl::GLImpl { } void BindSampler_State(GLuint unit, GLuint sampler) { + MGLOG_D("BindSampler_State: unit = %u, sampler = %u", unit, sampler); if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) { MG_State::pGLContext->RecordError( ErrorCode::InvalidValue, diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 71d881fc..e7df7fe1 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -1292,7 +1292,8 @@ namespace MobileGL::MG_Impl::GLImpl { } void BindTexture_State(GLenum target, GLuint texture) { - MGLOG_D("BindTexture_State called with target: 0x%X, texture: %u", target, texture); + const Int activeUnit = MG_State::pGLContext->GetActiveTextureUnit(); + MGLOG_D("BindTexture_State called with target: 0x%X, texture: %u, unit: %d", target, texture, activeUnit); // ======================= Converting ================================ TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); @@ -1301,7 +1302,7 @@ namespace MobileGL::MG_Impl::GLImpl { // Name 0 unbinds the current target from the active texture unit. if (texture == 0) { - auto& currentUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); + auto& currentUnit = MG_State::pGLContext->GetTextureUnitObject(activeUnit); auto& bindingSlot = currentUnit.GetBindingSlot(textureTarget); bindingSlot.Bind(nullptr); return; @@ -1339,7 +1340,9 @@ namespace MobileGL::MG_Impl::GLImpl { } // ======================= Processing ================================ - MG_State::pGLContext->SetActiveTextureUnit((Int)texture - GL_TEXTURE0); + const Int unit = (Int)texture - GL_TEXTURE0; + MGLOG_D("ActiveTexture_State: unit = %d", unit); + MG_State::pGLContext->SetActiveTextureUnit(unit); } void GetTexImage_Backend(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {