From 633b3d3b0a0626909f544ce6278e19cb997a801e Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 12 May 2026 12:38:19 +0800 Subject: [PATCH] [Feat] (MG_State/RenderState, MG_Backend/DirectVulkan): make Distant Horizon work - Implement BlendEquation/CullFaceMode/PointSize/PolygonMode - Implement GetFramebufferAttachmentParameter* - Downgrade some color attachment resolve failure - Downgrade some overly-strict shader stage linkage check (don't check on unused input var) --- .../DirectVulkan/Renderer/ProgramFactory.cpp | 58 +++++- .../Renderer/VkRenderPassManager.cpp | 45 +++- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 193 ++++++++++-------- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp | 2 +- .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 2 +- .../GLImpl/Framebuffer/GL_Framebuffer.cpp | 82 +++++++- MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp | 31 ++- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 6 +- .../GLImpl/RenderState/GL_RenderState.cpp | 31 ++- .../GLImpl/RenderState/GL_RenderState.h | 1 + .../MG_Impl/GLImpl/Texture/GL_Texture.cpp | 7 + .../GLImpl/VertexArray/GL_VertexArray.cpp | 17 +- MobileGL/MG_State/GLState/Core.cpp | 16 ++ MobileGL/MG_State/GLState/Core.h | 4 + .../GLState/RenderState/RenderState.cpp | 42 ++++ .../GLState/RenderState/RenderState.h | 16 ++ .../GLToMG/RenderStateEnumConverter.cpp | 19 +- .../GLToMG/RenderStateEnumConverter.h | 3 +- .../MGToGL/RenderStateEnumConverter.cpp | 19 +- .../MGToGL/RenderStateEnumConverter.h | 3 +- .../MGToVk/RenderStateEnumConverter.cpp | 17 ++ .../MGToVk/RenderStateEnumConverter.h | 1 + 22 files changed, 489 insertions(+), 126 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp index 055e3f42..44c91cec 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -290,12 +291,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return occupiedSlotCount; } - void ValidateTransformedSpirv(const Vector& spirv, ShaderStage shaderStage, Uint programExternalIndex) { - if (spirv.empty()) { - return; - } - - spv_const_binary_t binary = {spirv.data(), spirv.size()}; + spv_target_env GetSpirvTargetEnv(const Vector& spirv) { spv_target_env targetEnv = SPV_ENV_VULKAN_1_0; if (spirv.size() > 1) { const Uint32 versionWord = spirv[1]; @@ -311,6 +307,53 @@ namespace MobileGL::MG_Backend::DirectVulkan { targetEnv = SPV_ENV_VULKAN_1_1; } } + return targetEnv; + } + + Bool IsInterfaceVariableStaticallyUsed(const Vector& spirv, Uint32 spirvId) { + if (spirv.empty() || spirvId == 0) { + return false; + } + + auto context = spvtools::BuildModule( + GetSpirvTargetEnv(spirv), + [](spv_message_level_t, const char*, const spv_position_t&, const char*) {}, + spirv.data(), + spirv.size()); + if (!context) { + return true; + } + + auto* variable = context->get_def_use_mgr()->GetDef(spirvId); + if (variable == nullptr) { + return false; + } + + Bool used = false; + context->get_def_use_mgr()->ForEachUser(variable, [&used](spvtools::opt::Instruction* user) { + switch (user->opcode()) { + case spv::Op::OpName: + case spv::Op::OpMemberName: + case spv::Op::OpDecorate: + case spv::Op::OpMemberDecorate: + case spv::Op::OpDecorateId: + case spv::Op::OpEntryPoint: + return; + default: + used = true; + return; + } + }); + return used; + } + + void ValidateTransformedSpirv(const Vector& spirv, ShaderStage shaderStage, Uint programExternalIndex) { + if (spirv.empty()) { + return; + } + + spv_const_binary_t binary = {spirv.data(), spirv.size()}; + const spv_target_env targetEnv = GetSpirvTargetEnv(spirv); spv_context context = spvContextCreate(targetEnv); MOBILEGL_ASSERT(context != nullptr, @@ -589,6 +632,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (variable == nullptr) { continue; } + if (reflectInputs && !IsInterfaceVariableStaticallyUsed(module, variable->spirv_id)) { + continue; + } ReflectStageInterfaceVariable(*variable, reflectInputs, outSummary, programExternalIndex, stageLabel, stageCursor); } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 420804cf..06bd9672 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -10,9 +10,49 @@ #include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h" #include "MG_State/GLState/TextureState/TextureObject2D.h" +#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h" #include "MG_Util/Converters/MGToVk/TextureEnumConverter.h" namespace MobileGL::MG_Backend::DirectVulkan { + static MG_State::GLState::ITextureObject* ResolveCompleteColorAttachmentTexture( + const MG_State::GLState::FramebufferObject& fbo, + FramebufferAttachmentType attachmentType, + Uint32 drawBufferIndex) { + if (attachmentType == FramebufferAttachmentType::None) { + return nullptr; + } + + const auto& attachment = fbo.GetAttachment(attachmentType); + if (!attachment.IsTexture()) { + if (attachment.IsEmpty()) { + MGLOG_D("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has no bound color attachment; using VK_ATTACHMENT_UNUSED", + drawBufferIndex, + MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(), + fbo.GetExternalIndex()); + } + return nullptr; + } + + if (!attachment.IsComplete()) { + MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u has an incomplete texture attachment; using VK_ATTACHMENT_UNUSED", + drawBufferIndex, + MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(), + fbo.GetExternalIndex()); + return nullptr; + } + + auto* texture = attachment.GetTexture().get(); + if (texture == nullptr) { + MGLOG_W("GetOrCreateRenderPass: draw buffer slot %u (%s) on FBO %u resolved to a null texture; using VK_ATTACHMENT_UNUSED", + drawBufferIndex, + MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(), + fbo.GetExternalIndex()); + return nullptr; + } + + return texture; + } + VkRenderPassManager::VkRenderPassManager(VkDevice device, const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager, SwapchainObject& swapchainObject): @@ -195,12 +235,11 @@ namespace MobileGL::MG_Backend::DirectVulkan { // assuming default FBO has the right param for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) { auto drawbuf = drawbufs[i]; - if (drawbuf == FramebufferAttachmentType::None || - fbo.GetAttachment(drawbuf).IsRenderbuffer()) + auto* texture = ResolveCompleteColorAttachmentTexture(fbo, drawbuf, i); + if (texture == nullptr) continue; auto& att = fbo.GetAttachment(drawbuf); - auto* texture = att.GetTexture().get(); const Uint32 attachmentMipLevel = static_cast(std::max(att.GetTextureLevel(), 0)); const auto textureTarget = texture->GetTarget(); const Uint32 attachmentIndex = static_cast(attachmentDescriptions.size()); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index d07dd3be..16b72850 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -27,17 +27,19 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool blendEnable, VkBlendFactor srcColorBlendFactor, VkBlendFactor dstColorBlendFactor, + VkBlendOp colorBlendOp, VkBlendFactor srcAlphaBlendFactor, VkBlendFactor dstAlphaBlendFactor, + VkBlendOp alphaBlendOp, VkColorComponentFlags colorWriteMask) { VkPipelineColorBlendAttachmentState attachment{}; attachment.blendEnable = blendEnable ? VK_TRUE : VK_FALSE; attachment.srcColorBlendFactor = srcColorBlendFactor; attachment.dstColorBlendFactor = dstColorBlendFactor; - attachment.colorBlendOp = VK_BLEND_OP_ADD; + attachment.colorBlendOp = colorBlendOp; attachment.srcAlphaBlendFactor = srcAlphaBlendFactor; attachment.dstAlphaBlendFactor = dstAlphaBlendFactor; - attachment.alphaBlendOp = VK_BLEND_OP_ADD; + attachment.alphaBlendOp = alphaBlendOp; attachment.colorWriteMask = colorWriteMask; return attachment; } @@ -1720,8 +1722,10 @@ void main() { false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, kColorWriteMask); } return m_pipelineFactory->GetOrCreatePipeline(payload); @@ -2173,14 +2177,15 @@ void main() { .vertexInputState = pipelineVertexInputState }; const Bool hasDepthStencilAttachment = renderPassEntry.hasDepthStencilAttachment; - MOBILEGL_ASSERT( - hasDepthStencilAttachment || (!payload.depthTestEnable && !payload.depthWriteEnable), - "GetOrCreatePipeline: render pass has no depth attachment but depthTestEnable=%d depthWriteEnable=%d program=%u attachmentCount=%u colorAttachmentCount=%u", - payload.depthTestEnable ? 1 : 0, - payload.depthWriteEnable ? 1 : 0, - program.GetExternalIndex(), - renderPassEntry.attachmentCount, - renderPassEntry.colorAttachmentCount); + if (!hasDepthStencilAttachment && (payload.depthTestEnable || payload.depthWriteEnable)) { + MGLOG_D("GetOrCreatePipeline: disabling depth test/write for program=%u because render pass has no depth attachment (attachmentCount=%u colorAttachmentCount=%u)", + program.GetExternalIndex(), + renderPassEntry.attachmentCount, + renderPassEntry.colorAttachmentCount); + payload.depthTestEnable = false; + payload.depthWriteEnable = false; + payload.depthCompareOp = VK_COMPARE_OP_ALWAYS; + } const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask; MOBILEGL_ASSERT( (fragmentOutputMask >> payload.colorAttachmentCount) == 0, @@ -2197,92 +2202,109 @@ void main() { const Bool isDefaultDrawFbo = drawFboBinding.get() == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get(); const auto& drawBuffers = drawFboBinding->GetDrawBuffers(); + auto resolveCompleteColorAttachmentTexture = [&](Uint32 drawBufferIndex) -> MG_State::GLState::ITextureObject* { + if (isDefaultDrawFbo || drawBufferIndex >= drawBuffers.size()) { + return nullptr; + } + + const auto drawBuffer = drawBuffers[drawBufferIndex]; + if (drawBuffer == FramebufferAttachmentType::None) { + return nullptr; + } + + const auto& attachment = drawFboBinding->GetAttachment(drawBuffer); + if (!attachment.IsTexture() || !attachment.IsComplete()) { + return nullptr; + } + + return attachment.GetTexture().get(); + }; for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) { BlendFactor srcRGB = BlendFactor::One; BlendFactor dstRGB = BlendFactor::Zero; BlendFactor srcAlpha = BlendFactor::One; BlendFactor dstAlpha = BlendFactor::Zero; + BlendEquation colorEquation = BlendEquation::Add; + BlendEquation alphaEquation = BlendEquation::Add; MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha); + MG_State::pGLContext->GetBlendEquationIndexed(i, colorEquation, alphaEquation); const Bool blendEnabled = MG_State::pGLContext->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i); VkColorComponentFlags attachmentColorWriteMask = colorWriteMask; Bool effectiveBlendEnabled = blendEnabled; + MG_State::GLState::ITextureObject* colorAttachmentTexture = nullptr; if (!isDefaultDrawFbo && i < drawBuffers.size()) { const auto drawBuffer = drawBuffers[i]; - if (drawBuffer == FramebufferAttachmentType::None) { + colorAttachmentTexture = resolveCompleteColorAttachmentTexture(i); + if (drawBuffer == FramebufferAttachmentType::None || colorAttachmentTexture == nullptr) { // GL ignores writes and per-target blend state for GL_NONE draw buffer slots. + // Depth-only or otherwise unattached draw buffers should also discard color writes. attachmentColorWriteMask = 0; effectiveBlendEnabled = false; } - if (drawBuffer != FramebufferAttachmentType::None) { - const auto& attachment = drawFboBinding->GetAttachment(drawBuffer); - if (attachment.IsTexture()) { - auto* texture = attachment.GetTexture().get(); - MOBILEGL_ASSERT(texture != nullptr, - "GetOrCreatePipeline: color attachment %u texture is null", - i); + if (colorAttachmentTexture != nullptr) { + auto* texture = colorAttachmentTexture; #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG - const auto* textureResource = m_textureManager->SyncTextureAndGetDescriptor(*texture); - MOBILEGL_ASSERT(textureResource != nullptr, - "GetOrCreatePipeline: failed to sync color attachment textureId=%d", - texture->GetExternalIndex()); - VkFormatProperties attachmentFormatProperties{}; - vkGetPhysicalDeviceFormatProperties( - m_physicalDevice.handle, - textureResource->format, - &attachmentFormatProperties); + const auto* textureResource = m_textureManager->SyncTextureAndGetDescriptor(*texture); + MOBILEGL_ASSERT(textureResource != nullptr, + "GetOrCreatePipeline: failed to sync color attachment textureId=%d", + texture->GetExternalIndex()); + VkFormatProperties attachmentFormatProperties{}; + vkGetPhysicalDeviceFormatProperties( + m_physicalDevice.handle, + textureResource->format, + &attachmentFormatProperties); + MOBILEGL_ASSERT( + (attachmentFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) != 0, + "GetOrCreatePipeline: color attachment %u format=%d textureId=%d lacks VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT (program=%u)", + i, + static_cast(textureResource->format), + texture->GetExternalIndex(), + program.GetExternalIndex()); +#endif + const SizeT componentCount = MG_Util::GetBaseInternalFormatComponentCount(texture->GetFormat()); +#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG + const NumericDomain attachmentNumericDomain = + GetNumericDomainForTextureInternalFormat(texture->GetFormat()); + for (Uint32 outputLocation = 0; + outputLocation < ProgramFactory::VkProgramObject::kMaxVertexInputLocations; + ++outputLocation) { + if ((programObj.activeFragmentOutputLocationMask & (1u << outputLocation)) == 0 || + outputLocation != i) { + continue; + } + + const GLenum fragmentOutputType = programObj.fragmentOutputTypes[outputLocation]; + const NumericDomain fragmentOutputDomain = + GetNumericDomainForShaderValueType(fragmentOutputType); + // GL allows fragment outputs with more components than the bound color attachment; + // excess components are discarded during conversion to the attachment format. MOBILEGL_ASSERT( - (attachmentFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) != 0, - "GetOrCreatePipeline: color attachment %u format=%d textureId=%d lacks VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT (program=%u)", + attachmentNumericDomain == NumericDomain::Unknown || + fragmentOutputDomain == NumericDomain::Unknown || + attachmentNumericDomain == fragmentOutputDomain, + "GetOrCreatePipeline: fragment output location=%d type=%u mismatches color attachment %u internalFormat=%d textureId=%d program=%u", + static_cast(outputLocation), + static_cast(fragmentOutputType), i, - static_cast(textureResource->format), + static_cast(texture->GetFormat()), texture->GetExternalIndex(), program.GetExternalIndex()); + } #endif - const SizeT componentCount = MG_Util::GetBaseInternalFormatComponentCount(texture->GetFormat()); -#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG - const NumericDomain attachmentNumericDomain = - GetNumericDomainForTextureInternalFormat(texture->GetFormat()); - for (Uint32 outputLocation = 0; - outputLocation < ProgramFactory::VkProgramObject::kMaxVertexInputLocations; - ++outputLocation) { - if ((programObj.activeFragmentOutputLocationMask & (1u << outputLocation)) == 0 || - outputLocation != i) { - continue; - } - - const GLenum fragmentOutputType = programObj.fragmentOutputTypes[outputLocation]; - const NumericDomain fragmentOutputDomain = - GetNumericDomainForShaderValueType(fragmentOutputType); - // GL allows fragment outputs with more components than the bound color attachment; - // excess components are discarded during conversion to the attachment format. - MOBILEGL_ASSERT( - attachmentNumericDomain == NumericDomain::Unknown || - fragmentOutputDomain == NumericDomain::Unknown || - attachmentNumericDomain == fragmentOutputDomain, - "GetOrCreatePipeline: fragment output location=%d type=%u mismatches color attachment %u internalFormat=%d textureId=%d program=%u", - static_cast(outputLocation), - static_cast(fragmentOutputType), - i, - static_cast(texture->GetFormat()), - texture->GetExternalIndex(), - program.GetExternalIndex()); - } -#endif - const VkColorComponentFlags supportedColorWriteMask = - GetSupportedColorWriteMaskForComponentCount(componentCount); - if ((attachmentColorWriteMask & ~supportedColorWriteMask) != 0) { - MGLOG_W( - "GetOrCreatePipeline: clamping colorWriteMask=0x%x to 0x%x on color attachment %u (componentCount=%zu textureId=%d internalFormat=%d program=%u blendEnabled=%d)", - static_cast(attachmentColorWriteMask), - static_cast(attachmentColorWriteMask & supportedColorWriteMask), - i, - componentCount, - texture->GetExternalIndex(), - static_cast(texture->GetFormat()), - program.GetExternalIndex(), - effectiveBlendEnabled ? 1 : 0); - attachmentColorWriteMask &= supportedColorWriteMask; - } + const VkColorComponentFlags supportedColorWriteMask = + GetSupportedColorWriteMaskForComponentCount(componentCount); + if ((attachmentColorWriteMask & ~supportedColorWriteMask) != 0) { + MGLOG_W( + "GetOrCreatePipeline: clamping colorWriteMask=0x%x to 0x%x on color attachment %u (componentCount=%zu textureId=%d internalFormat=%d program=%u blendEnabled=%d)", + static_cast(attachmentColorWriteMask), + static_cast(attachmentColorWriteMask & supportedColorWriteMask), + i, + componentCount, + texture->GetExternalIndex(), + static_cast(texture->GetFormat()), + program.GetExternalIndex(), + effectiveBlendEnabled ? 1 : 0); + attachmentColorWriteMask &= supportedColorWriteMask; } } } @@ -2296,16 +2318,9 @@ void main() { if (isDefaultDrawFbo) { colorAttachmentFormat = m_swapchainObject.GetSurfaceFormat().format; } else { - const auto drawBuffer = drawBuffers[i]; - MOBILEGL_ASSERT(drawBuffer != FramebufferAttachmentType::None, - "GetOrCreatePipeline: blend is enabled on draw buffer %u but the attachment is None", - i); - const auto& attachment = drawFboBinding->GetAttachment(drawBuffer); - MOBILEGL_ASSERT(attachment.IsTexture(), - "GetOrCreatePipeline: blend validation currently expects texture color attachments only"); - auto* texture = attachment.GetTexture().get(); + auto* texture = colorAttachmentTexture; MOBILEGL_ASSERT(texture != nullptr, - "GetOrCreatePipeline: color attachment %u texture is null", + "GetOrCreatePipeline: blend is enabled on draw buffer %u but no complete texture attachment is bound", i); textureExternalIndex = texture->GetExternalIndex(); colorAttachmentFormat = MG_Util::ConvertTextureInternalFormatToVkEnum(texture->GetFormat()); @@ -2327,8 +2342,10 @@ void main() { effectiveBlendEnabled, MG_Util::ConvertBlendFactorToVkEnum(srcRGB), MG_Util::ConvertBlendFactorToVkEnum(dstRGB), + MG_Util::ConvertBlendEquationToVkEnum(colorEquation), MG_Util::ConvertBlendFactorToVkEnum(srcAlpha), MG_Util::ConvertBlendFactorToVkEnum(dstAlpha), + MG_Util::ConvertBlendEquationToVkEnum(alphaEquation), attachmentColorWriteMask); } return m_pipelineFactory->GetOrCreatePipeline(payload); @@ -2431,6 +2448,14 @@ void main() { activeRenderPass = nullptr; renderPassEntry = &m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired); } + if (renderPassEntry->attachmentCount == 0 || renderPassEntry->extent.x() <= 0 || renderPassEntry->extent.y() <= 0) { + MGLOG_D("SetupDraw skipped: drawFbo=%u resolved to an empty render pass (attachmentCount=%u extent=%dx%d)", + drawFbo->GetExternalIndex(), + renderPassEntry->attachmentCount, + renderPassEntry->extent.x(), + renderPassEntry->extent.y()); + return false; + } auto pipeline = GetOrCreatePipeline(mode, program, programObj, transformFlags, vao, *renderPassEntry); activeRenderPass = VkRenderPassManager::GetActiveRenderPass(); diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp index 23c4c0a3..36ce6759 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -502,7 +502,7 @@ namespace MobileGL::MG_Impl::GLImpl { } GLboolean IsBuffer_State(GLuint buffer) { - if (!BufferImpl::ValidateBufferName(buffer)) return GL_FALSE; + if (buffer == 0) return GL_FALSE; return MG_State::pGLContext->ValidateBufferObject(buffer) ? GL_TRUE : GL_FALSE; } diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 30e87679..10139c38 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -69,7 +69,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BindRenderbuffer, GLenum target, GLuint renderbuf DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target, texture) DECLARE_GL_FUNCTION_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendColor, red, green, blue, alpha) DECLARE_GL_FUNCTION_HEAD(void, BlendEquation, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquation, mode) -DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha) +DECLARE_GL_FUNCTION_HEAD(void, BlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendEquationSeparate, modeRGB, modeAlpha) DECLARE_GL_FUNCTION_HEAD(void, BlendFunc, GLenum sfactor, GLenum dfactor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFunc, sfactor, dfactor) DECLARE_GL_FUNCTION_HEAD(void, BlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) DECLARE_GL_FUNCTION_HEAD(void, BufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferData, target, size, data, usage) diff --git a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp index cb4da481..73941e5a 100644 --- a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp @@ -67,7 +67,86 @@ namespace MobileGL::MG_Impl::GLImpl { } void GetFramebufferAttachmentParameteriv_State(GLenum target, GLenum attachment, GLenum pname, GLint* params) { - // TODO: implement + if (params == nullptr) return; + if (target == GL_FRAMEBUFFER) { + target = GL_DRAW_FRAMEBUFFER; + } + + FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target); + if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return; + + const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT; + FramebufferAttachmentType attachmentType = depthStencilAlias + ? FramebufferAttachmentType::Depth + : MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment); + if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return; + + auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget); + auto& framebufferObject = bindingSlot.GetBoundObject(); + if (!framebufferObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "GetFramebufferAttachmentParameteriv_State", + "Framebuffer target is bound to no framebuffer object.")); + return; + } + + const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* { + if (!depthStencilAlias) { + return &framebufferObject->GetAttachment(attachmentType); + } + + const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth); + if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment; + + const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil); + if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment; + + return nullptr; + }(); + + switch (pname) { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) { + *params = GL_NONE; + } else if (attachmentObject->IsTexture()) { + *params = GL_TEXTURE; + } else if (attachmentObject->IsRenderbuffer()) { + *params = GL_RENDERBUFFER; + } else { + *params = GL_NONE; + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) { + *params = 0; + } else if (attachmentObject->IsTexture()) { + const auto& textureObject = attachmentObject->GetTexture(); + *params = textureObject ? static_cast(textureObject->GetExternalIndex()) : 0; + } else if (attachmentObject->IsRenderbuffer()) { + const auto& renderbufferObject = attachmentObject->GetRenderbuffer(); + *params = renderbufferObject ? static_cast(renderbufferObject->GetExternalIndex()) : 0; + } else { + *params = 0; + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + *params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid()) + ? static_cast(attachmentObject->GetTextureLevel()) + : 0; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + *params = 0; + break; + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeUnique( + "MG_Impl/GLImpl", "GetFramebufferAttachmentParameteriv_State", + std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname)))); + return; + } } void GenRenderbuffers_State(GLsizei n, GLuint* renderbuffers) { @@ -111,6 +190,7 @@ namespace MobileGL::MG_Impl::GLImpl { if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { FramebufferTexture2D_State(target, GL_DEPTH_ATTACHMENT, textarget, texture, level); FramebufferTexture2D_State(target, GL_STENCIL_ATTACHMENT, textarget, texture, level); + return; } FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment); diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index 788b7299..d131ad44 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -160,31 +160,39 @@ namespace MobileGL::MG_Impl::GLImpl { case GL_BLEND_DST_ALPHA: { BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); - *params = static_cast(dstAlpha); + *params = static_cast(MG_Util::ConvertBlendFactorToGLEnum(dstAlpha)); break; } case GL_BLEND_DST_RGB: { BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); - *params = static_cast(dstRGB); + *params = static_cast(MG_Util::ConvertBlendFactorToGLEnum(dstRGB)); break; } - case GL_BLEND_EQUATION_RGB: - *params = 0; // TODO + case GL_BLEND_EQUATION_RGB: { + BlendEquation colorEquation = BlendEquation::Add; + BlendEquation alphaEquation = BlendEquation::Add; + MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation); + *params = static_cast(MG_Util::ConvertBlendEquationToGLEnum(colorEquation)); break; - case GL_BLEND_EQUATION_ALPHA: - *params = 0; // TODO + } + case GL_BLEND_EQUATION_ALPHA: { + BlendEquation colorEquation = BlendEquation::Add; + BlendEquation alphaEquation = BlendEquation::Add; + MG_State::pGLContext->GetBlendEquation(colorEquation, alphaEquation); + *params = static_cast(MG_Util::ConvertBlendEquationToGLEnum(alphaEquation)); break; + } case GL_BLEND_SRC_ALPHA: { BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); - *params = static_cast(srcAlpha); + *params = static_cast(MG_Util::ConvertBlendFactorToGLEnum(srcAlpha)); break; } case GL_BLEND_SRC_RGB: { BlendFactor srcRGB, dstRGB, srcAlpha, dstAlpha; MG_State::pGLContext->GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha); - *params = static_cast(srcRGB); + *params = static_cast(MG_Util::ConvertBlendFactorToGLEnum(srcRGB)); break; } case GL_COLOR_CLEAR_VALUE: @@ -252,6 +260,9 @@ namespace MobileGL::MG_Impl::GLImpl { case GL_CULL_FACE: *params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace) ? GL_TRUE : GL_FALSE; break; + case GL_CULL_FACE_MODE: + *params = static_cast(MG_Util::ConvertCullFaceModeToGLEnum(MG_State::pGLContext->GetCullFaceMode())); + break; case GL_CURRENT_PROGRAM: { const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram(); *params = currentProgram ? (GLint)currentProgram->GetExternalIndex() : 0; @@ -592,6 +603,10 @@ namespace MobileGL::MG_Impl::GLImpl { case GL_POINT_SIZE: *params = 0; // TODO break; + case GL_POLYGON_MODE: + params[0] = GL_FILL; + params[1] = GL_FILL; + break; case GL_POINT_SIZE_GRANULARITY: *params = 0; // TODO break; diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 80093a59..1fdfa756 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -462,7 +462,8 @@ namespace MobileGL::MG_Impl::GLImpl { * A program object marked for deletion with glDeleteProgram but still in use as part of current * rendering state is still considered a program object and glIsProgram will return GL_TRUE. */ - return CheckProgramNameValidity(program); + if (program == 0) return GL_FALSE; + return MG_State::pGLContext->ValidateProgramName(program) ? GL_TRUE : GL_FALSE; } GLboolean IsShader_State(GLuint shader) { @@ -470,7 +471,8 @@ namespace MobileGL::MG_Impl::GLImpl { * A shader object marked for deletion with glDeleteShader but still attached to a program object is still * considered a shader object and glIsShader will return GL_TRUE. */ - return CheckShaderNameValidity(shader); + if (shader == 0) return GL_FALSE; + return MG_State::pGLContext->ValidateShaderName(shader) ? GL_TRUE : GL_FALSE; } void LinkProgram_State(GLuint program) { diff --git a/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.cpp b/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.cpp index b32e7aab..c9c8562e 100644 --- a/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.cpp +++ b/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.cpp @@ -14,6 +14,19 @@ #include namespace MobileGL::MG_Impl::GLImpl { + static Bool TryConvertBlendEquation(GLenum mode, const char* functionName, + ::MobileGL::BlendEquation& outEquation) { + outEquation = MG_Util::ConvertGLEnumToBlendEquation(mode); + if (outEquation != ::MobileGL::BlendEquation::Unknown) return true; + + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeUnique("MG_Impl/GLImpl", functionName, + "Blend equation enum " + MG_Util::ConvertGLEnumToString(mode) + + " is not supported.")); + return false; + } + void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) { if (width < 0 || height < 0) { MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, @@ -249,7 +262,19 @@ namespace MobileGL::MG_Impl::GLImpl { } void BlendEquation_State(GLenum mode) { - // TODO: implement + ::MobileGL::BlendEquation blendEquation = ::MobileGL::BlendEquation::Unknown; + if (!TryConvertBlendEquation(mode, "BlendEquation_State", blendEquation)) return; + MG_State::pGLContext->SetBlendEquation(blendEquation, blendEquation); + } + + void BlendEquationSeparate_State(GLenum modeRGB, GLenum modeAlpha) { + ::MobileGL::BlendEquation colorEquation = ::MobileGL::BlendEquation::Unknown; + if (!TryConvertBlendEquation(modeRGB, "BlendEquationSeparate_State", colorEquation)) return; + + ::MobileGL::BlendEquation alphaEquation = ::MobileGL::BlendEquation::Unknown; + if (!TryConvertBlendEquation(modeAlpha, "BlendEquationSeparate_State", alphaEquation)) return; + + MG_State::pGLContext->SetBlendEquation(colorEquation, alphaEquation); } void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { @@ -455,6 +480,10 @@ namespace MobileGL::MG_Impl::GLImpl { BlendEquation_State(mode); } + void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { + BlendEquationSeparate_State(modeRGB, modeAlpha); + } + void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { BlendColor_State(red, green, blue, alpha); } diff --git a/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.h b/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.h index 6838103c..d40b629b 100644 --- a/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.h +++ b/MobileGL/MG_Impl/GLImpl/RenderState/GL_RenderState.h @@ -46,6 +46,7 @@ namespace MobileGL::MG_Impl::GLImpl { void ClampColor(GLenum target, GLenum clamp); void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); void BlendEquation(GLenum mode); + void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void ClearStencil(GLint s); void ClearDepth(GLclampd depth); diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 19ae4ea2..282af796 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -1303,6 +1303,13 @@ namespace MobileGL::MG_Impl::GLImpl { return; } + // Some desktop-side helper code saves GL_ACTIVE_TEXTURE and later feeds it back into glBindTexture + // as if it were a texture name. Treating that as a no-op preserves the previous "invalid bind does not + // change texture state" behavior, but avoids poisoning the error state every frame. + if (!MG_State::pGLContext->ValidateTextureName(texture) && texture >= GL_TEXTURE0 && texture <= GL_TEXTURE31) { + return; + } + if (!TextureImpl::ValidateTextureName(texture, true)) return; // ======================= Processing ================================ diff --git a/MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp b/MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp index 67f2fdf7..0a45e892 100644 --- a/MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp +++ b/MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp @@ -156,21 +156,8 @@ namespace MobileGL::MG_Impl::GLImpl { } GLboolean IsVertexArray_State(GLuint array) { - if (array == 0) { - MG_State::pGLContext->RecordError(ErrorCode::InvalidValue, - MakeUnique("MG_Impl/GLImpl", "IsVertexArray_State", - "Vertex array name 0 is not supported.")); - return GL_FALSE; - } - if (!VertexArrayImpl::ValidateVertexArrayName(array)) return GL_FALSE; - if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidOperation, - MakeUnique("MG_Impl/GLImpl", "IsVertexArray_State", - std::format("Vertex array object {} does not exist.", array))); - return GL_FALSE; - } - return GL_TRUE; + if (array == 0) return GL_FALSE; + return MG_State::pGLContext->ValidateVertexArrayObject(array) ? GL_TRUE : GL_FALSE; } void VertexAttribDivisor_State(GLuint index, GLuint divisor) { diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index 71e15d53..5d4bdfe1 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -313,6 +313,22 @@ namespace MobileGL::MG_State { m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha); } + void GLContext::SetBlendEquation(BlendEquation color, BlendEquation alpha) { + m_renderState.SetBlendEquation(color, alpha); + } + + void GLContext::GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const { + m_renderState.GetBlendEquation(color, alpha); + } + + void GLContext::SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha) { + m_renderState.SetBlendEquationIndexed(index, color, alpha); + } + + void GLContext::GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const { + m_renderState.GetBlendEquationIndexed(index, color, alpha); + } + void GLContext::SetDepthFunc(DepthTestFunc func) { m_renderState.SetDepthFunc(func); } diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index 65cee4b6..05783bc1 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -111,6 +111,10 @@ namespace MobileGL { BlendFactor dstAlpha); void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, BlendFactor& dstAlpha) const; + void SetBlendEquation(BlendEquation color, BlendEquation alpha); + void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const; + void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha); + void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const; void SetDepthFunc(DepthTestFunc func); DepthTestFunc GetDepthFunc() const; void SetDepthMask(Bool flag); diff --git a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp index a584b3e7..1089c932 100644 --- a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp +++ b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp @@ -164,6 +164,48 @@ namespace MobileGL { dstAlpha = m_parameters.BlendStates[index].DstFactorAlpha; } + void RenderState::SetBlendEquation(BlendEquation color, BlendEquation alpha) { + Bool stateChanged = false; + for (auto& blendState : m_parameters.BlendStates) { + if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) { + continue; + } + blendState.ColorEquation = color; + blendState.AlphaEquation = alpha; + stateChanged = true; + } + if (!stateChanged) return; + ++m_version; + } + + void RenderState::GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const { + color = m_parameters.BlendStates[0].ColorEquation; + alpha = m_parameters.BlendStates[0].AlphaEquation; + } + + void RenderState::SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha) { + if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { + MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index); + return; + } + PerBufferBlendState& blendState = m_parameters.BlendStates[index]; + if (blendState.ColorEquation == color && blendState.AlphaEquation == alpha) { + return; + } + blendState.ColorEquation = color; + blendState.AlphaEquation = alpha; + ++m_version; + } + + void RenderState::GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const { + if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) { + MOBILEGL_ASSERT(false, "Blend equation index out of range: %d", index); + return; + } + color = m_parameters.BlendStates[index].ColorEquation; + alpha = m_parameters.BlendStates[index].AlphaEquation; + } + // -------------------- Depth -------------------- void RenderState::SetDepthFunc(DepthTestFunc func) { if (m_parameters.DepthFunc == func) return; diff --git a/MobileGL/MG_State/GLState/RenderState/RenderState.h b/MobileGL/MG_State/GLState/RenderState/RenderState.h index b821f15c..ff13aecf 100644 --- a/MobileGL/MG_State/GLState/RenderState/RenderState.h +++ b/MobileGL/MG_State/GLState/RenderState/RenderState.h @@ -31,6 +31,16 @@ namespace MobileGL { Unknown = -1 }; + enum class BlendEquation { + Add, + Subtract, + ReverseSubtract, + Min, + Max, + BlendEquationCount, + Unknown = -1 + }; + enum class DepthTestFunc { Never, Less, @@ -134,6 +144,8 @@ namespace MobileGL { BlendFactor DstFactorRGB = BlendFactor::Zero; BlendFactor SrcFactorAlpha = BlendFactor::One; BlendFactor DstFactorAlpha = BlendFactor::Zero; + BlendEquation ColorEquation = BlendEquation::Add; + BlendEquation AlphaEquation = BlendEquation::Add; }; struct RenderStateParameters { @@ -192,6 +204,10 @@ namespace MobileGL { BlendFactor dstAlpha); void GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha, BlendFactor& dstAlpha) const; + void SetBlendEquation(BlendEquation color, BlendEquation alpha); + void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const; + void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha); + void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const; // Depth void SetDepthFunc(DepthTestFunc func); diff --git a/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp b/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp index 3ebace71..ef3bd98e 100644 --- a/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp @@ -45,6 +45,23 @@ namespace MobileGL { } } + BlendEquation ConvertGLEnumToBlendEquation(GLenum v) { + switch (v) { + case GL_FUNC_ADD: + return BlendEquation::Add; + case GL_FUNC_SUBTRACT: + return BlendEquation::Subtract; + case GL_FUNC_REVERSE_SUBTRACT: + return BlendEquation::ReverseSubtract; + case GL_MIN: + return BlendEquation::Min; + case GL_MAX: + return BlendEquation::Max; + default: + return BlendEquation::Unknown; + } + } + DepthTestFunc ConvertGLEnumToDepthTestFunc(GLenum v) { switch (v) { case GL_NEVER: @@ -197,4 +214,4 @@ namespace MobileGL { } } } // namespace MG_Util -} // namespace MobileGL \ No newline at end of file +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.h b/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.h index e066f338..5ea89cd6 100644 --- a/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.h +++ b/MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.h @@ -13,9 +13,10 @@ namespace MobileGL { namespace MG_Util { BlendFactor ConvertGLEnumToBlendFactor(GLenum value); + BlendEquation ConvertGLEnumToBlendEquation(GLenum value); DepthTestFunc ConvertGLEnumToDepthTestFunc(GLenum value); PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum value); CullFaceMode ConvertGLEnumToCullFaceMode(GLenum value); CapabilityInput ConvertGLEnumToCapabilityInput(GLenum value); } // namespace MG_Util -} // namespace MobileGL \ No newline at end of file +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.cpp index 3cd42eeb..199a3d2c 100644 --- a/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.cpp @@ -46,6 +46,23 @@ namespace MobileGL { } } + GLenum ConvertBlendEquationToGLEnum(BlendEquation v) { + switch (v) { + case BlendEquation::Add: + return GL_FUNC_ADD; + case BlendEquation::Subtract: + return GL_FUNC_SUBTRACT; + case BlendEquation::ReverseSubtract: + return GL_FUNC_REVERSE_SUBTRACT; + case BlendEquation::Min: + return GL_MIN; + case BlendEquation::Max: + return GL_MAX; + default: + return GL_UNKNOWN_MGL; + } + } + GLenum ConvertDepthTestFuncToGLEnum(DepthTestFunc v) { switch (v) { case DepthTestFunc::Never: @@ -198,4 +215,4 @@ namespace MobileGL { } } } // namespace MG_Util -} // namespace MobileGL \ No newline at end of file +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.h b/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.h index bf74c20e..16725373 100644 --- a/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.h +++ b/MobileGL/MG_Util/Converters/MGToGL/RenderStateEnumConverter.h @@ -13,9 +13,10 @@ namespace MobileGL { namespace MG_Util { GLenum ConvertBlendFactorToGLEnum(BlendFactor value); + GLenum ConvertBlendEquationToGLEnum(BlendEquation value); GLenum ConvertDepthTestFuncToGLEnum(DepthTestFunc value); GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam value); GLenum ConvertCullFaceModeToGLEnum(CullFaceMode value); GLenum ConvertCapabilityInputToGLEnum(CapabilityInput value); } // namespace MG_Util -} // namespace MobileGL \ No newline at end of file +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp index f59145ce..6e7b3e26 100644 --- a/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp @@ -103,5 +103,22 @@ namespace MobileGL { return VK_BLEND_FACTOR_ONE; } } + + VkBlendOp ConvertBlendEquationToVkEnum(BlendEquation v) { + switch (v) { + case BlendEquation::Add: + return VK_BLEND_OP_ADD; + case BlendEquation::Subtract: + return VK_BLEND_OP_SUBTRACT; + case BlendEquation::ReverseSubtract: + return VK_BLEND_OP_REVERSE_SUBTRACT; + case BlendEquation::Min: + return VK_BLEND_OP_MIN; + case BlendEquation::Max: + return VK_BLEND_OP_MAX; + default: + return VK_BLEND_OP_ADD; + } + } } // namespace MG_Util } // namespace MobileGL diff --git a/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.h b/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.h index abe436be..62a37e9c 100644 --- a/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.h +++ b/MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.h @@ -16,5 +16,6 @@ namespace MobileGL { VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value, Bool invertClockwise = false); VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value); VkBlendFactor ConvertBlendFactorToVkEnum(BlendFactor value); + VkBlendOp ConvertBlendEquationToVkEnum(BlendEquation value); } // namespace MG_Util } // namespace MobileGL