为什么设置了view的Opaque性能会提高(GPU)

本文详细解释了UIKit中Opaque属性的工作原理及其对GPU性能的影响。介绍了当UIView的Opaque属性设置为YES时,如何避免不必要的图层混合计算,从而提高渲染效率。
Opaque该属性为BOOL值,UIView的默认值是YES,但UIButton等子类的默认值都是NO。opaque表示当前UIView是否不透明,不过搞笑的是事实上 它却决定不了当前UIView是不是不透明,比如你将opaque设为NO,该UIView照样是可见的(上文说过,是否可见是由alpha或hidden属性决定的),照理说为NO就表示透明,那就应该是不可见的呀?

显示器中的每个像素点都可以显示一个由RGBA颜色空间组成的色值,比如上图中有红色和绿色两个图层色块,对于没有交叉的部分,即纯红色和绿色部分来说,对应位置的像素点只需要简单的显示红或绿,对应的RGBA为(1,0,0,1)和(0,1,0,1)就行了,负责图形显示的GPU需要很小的计算量就可以确定像素点对应的显示内容。
问题是红色和绿色还有相交的一块,其相交的颜色为黄色。这里的黄色是怎么来的呢? 原来,GPU会通过图层一和图层二的颜色进行图层混合,计算出混合部分的颜色,最理想情况的计算公式如下:

R = S + D * ( 1 – Sa )

其中,R表示混合结果的颜色,S是源颜色(位于上层的红色图层一),D是目标颜色(位于下层的绿色图层二),Sa是源颜色的alpha值,即透明度。公式中所有的S和D颜色都假定已经预先乘以了他们的透明度。

知道图层混合的基本原理以后,再回到正题说说opaque属性的作用。当UIView的opaque属性被设为YES以后,按照上面的公式,也就是Sa的值为1,这个时候公式就变成了:

R = S

即不管D为什么,结果都一样。因此GPU将不会做任何的计算合成,不需要考虑它下方的任何东西(因为都被它遮挡住了),而是简单从这个层拷贝。这节省了GPU相当大的工作量。由此看来,opaque属性的真实用处是给绘图系统提供一个性能优化开关!

按照前面的逻辑,当opaque属性被设为YES时,GPU就不会再利用图层颜色合成公式去合成真正的色值。因此, 如果opaque被设置成YES,而对应UIView的alpha属性不为1.0的时候,就会有不可预料的情况发生 ,这一点苹果在官方文档中有明确的说明:
An opaque view is expected to fill its bounds with entirely opaque content—that is, the content should have an alpha value of  1.0 . If the view is opaque and either does not fill its bounds or contains wholly or partially transparent content,the results are unpredictable. You should always set the value of this property to  NO  if the view is fully or partially transparent.
<think>我们之前讨论了VK_KHR_maintenance2扩展,现在用户询问的是VK_KHR_maintenance1扩展。这两个扩展是不同的,因此需要调整内容。 VK_KHR_maintenance1扩展主要提供以下功能: 1. 允许在创建图像视图时使用与原始图像不同的格式(在某些条件下) 2. 允许在创建帧缓冲区时使用非正方形负一视图 3. 改进了命令池重置的行为 在Unity中启用VK_KHR_maintenance1扩展的步骤与maintenance2类似,但具体功能使用有所不同。 注意:用户提供的引用[1][2][3]是关于Shader编写的,与Vulkan扩展启用没有直接关系,但我们在编写Shader部分时可以参考。 我们将按照以下步骤提供代码: 1. 编写本地插件(C++)来启用VK_KHR_maintenance1扩展 2. 编写C#脚本调用插件并控制扩展的启用 3. 提供使用该扩展特性的示例(如图像视图格式不匹配、非正方形负一视图等) 注意:VK_KHR_maintenance1扩展在Vulkan 1.0中是扩展,但在Vulkan 1.1中已经成为核心,因此我们只需要在Vulkan 1.0设备上显式启用。 步骤: 一、本地插件代码(C++): - 在Unity加载插件时获取IUnityGraphicsVulkan接口 - 提供启用扩展的函数(检查扩展是否存在并启用) - 提供使用扩展特性的辅助函数(例如检查图像格式兼容性) 二、C#脚本: - 在Start时调用插件函数启用扩展 - 提供使用扩展特性的方法(例如创建特殊图像视图) 三、Shader注意事项(参考用户提供的引用): - 使用正确的矩阵(如unity_ObjectToWorld代替_Object2World)[^2] - 使用UNITY_INITIALIZE_OUTPUT宏初始化输出结构[^1] 四、性能优化和兼容性处理 由于用户要求的是VK_KHR_maintenance1,我们重点实现该扩展的功能。 具体代码实现如下:</think># Unity 开启 VK_KHR_MAINTENANCE1_EXTENSION_NAME 最佳实践 VK_KHR_maintenance1 扩展是 Vulkan API 的重要维护性扩展,提供了多项核心功能增强,包括图像视图格式兼容性、非正方形负一视图等关键特性。以下是 Unity 中启用该扩展的最佳实现方案。 ## 核心实现代码 ### 1. 本地插件实现 (C++) ```cpp // VulkanMaintenance1Plugin.cpp #include "IUnityInterface.h" #include "IUnityGraphicsVulkan.h" #include <vector> #include <cstring> static IUnityGraphicsVulkan* s_Vulkan = nullptr; extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces) { s_Vulkan = unityInterfaces->Get<IUnityGraphicsVulkan>(); } extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API EnableMaintenance1Extension() { if (!s_Vulkan) return false; // 检查扩展支持 VkPhysicalDevice physicalDevice = s_Vulkan->PhysicalDevice(); uint32_t extensionCount = 0; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); std::vector<VkExtensionProperties> extensions(extensionCount); vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, extensions.data()); bool supportsMaintenance1 = false; const char* targetExtension = VK_KHR_MAINTENANCE1_EXTENSION_NAME; for (const auto& extension : extensions) { if (strcmp(extension.extensionName, targetExtension) == 0) { supportsMaintenance1 = true; break; } } if (!supportsMaintenance1) return false; // 启用扩展 s_Vulkan->AddEnabledDeviceExtension(targetExtension); return true; } // 检查图像格式兼容性 extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API IsImageFormatCompatible(VkFormat format) { if (!s_Vulkan) return false; VkPhysicalDevice physicalDevice = s_Vulkan->PhysicalDevice(); // 检查格式兼容性 VkImageFormatProperties formatProps; VkResult result = vkGetPhysicalDeviceImageFormatProperties( physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, // 使用可变格式标志 &formatProps ); return result == VK_SUCCESS; } // 创建非正方形负一视图 extern "C" VkImageView UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API CreateNonSquareImageView(VkImage image, VkFormat format, VkImageViewType viewType, VkImageAspectFlags aspectMask) { if (!s_Vulkan) return VK_NULL_HANDLE; VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; viewInfo.viewType = viewType; viewInfo.format = format; viewInfo.subresourceRange.aspectMask = aspectMask; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; // 设置兼容性标志 viewInfo.flags = VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT; VkImageView imageView; if (vkCreateImageView(s_Vulkan->Device(), &viewInfo, nullptr, &imageView) != VK_SUCCESS) { return VK_NULL_HANDLE; } return imageView; } ``` ### 2. C# 控制器脚本 ```csharp // Maintenance1Controller.cs using UnityEngine; using System.Runtime.InteropServices; using UnityEngine.Rendering; public class Maintenance1Controller : MonoBehaviour { [DllImport("VulkanMaintenance1Plugin")] private static extern bool EnableMaintenance1Extension(); [DllImport("VulkanMaintenance1Plugin")] private static extern bool IsImageFormatCompatible(TextureFormat format); [DllImport("VulkanMaintenance1Plugin")] private static extern System.IntPtr CreateNonSquareImageView( System.IntPtr image, TextureFormat format, int viewType, uint aspectMask); void Start() { // 仅在Vulkan API下启用 if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Vulkan) { Debug.LogWarning("Maintenance1 extension requires Vulkan API"); return; } // 启用扩展 if (EnableMaintenance1Extension()) { Debug.Log("VK_KHR_maintenance1 enabled"); // 检查纹理格式兼容性 CheckTextureFormats(); // 创建非正方形视图示例 CreateSpecialImageViews(); } else { Debug.LogWarning("Failed to enable maintenance1 extension"); } } void CheckTextureFormats() { TextureFormat[] formatsToCheck = { TextureFormat.RGBA32, TextureFormat.RGB24, TextureFormat.BC7, TextureFormat.ASTC_4x4 }; foreach (var format in formatsToCheck) { bool compatible = IsImageFormatCompatible(format); Debug.Log($"Format {format} compatible: {compatible}"); } } void CreateSpecialImageViews() { // 创建特殊尺寸纹理 Texture2D nonSquareTexture = new Texture2D(128, 256, TextureFormat.RGBA32, false); // 获取底层Vulkan图像句柄 System.IntPtr vkImage = nonSquareTexture.GetNativeTexturePtr(); // 创建非正方形视图 System.IntPtr imageView = CreateNonSquareImageView( vkImage, TextureFormat.RGBA32, (int)VkImageViewType.VK_IMAGE_VIEW_TYPE_2D, (uint)VkImageAspectFlagBits.VK_IMAGE_ASPECT_COLOR_BIT ); if (imageView != System.IntPtr.Zero) { Debug.Log("Non-square image view created successfully"); } } } ``` ### 3. 着色器适配(使用正确语法) ```glsl Shader "Custom/NonSquareTextureShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; // 正确初始化输出结构[^1] UNITY_INITIALIZE_OUTPUT(v2f, o); }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; // 使用正确的变换矩阵[^2] o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } } ``` ## VK_KHR_maintenance1 核心功能 | 功能 | 描述 | Unity 应用场景 | |------|------|---------------| | **非正方形负一视图** | 支持非正方形纹理的负一视图 | 特殊尺寸纹理处理 | | **图像视图格式兼容性** | 支持更多图像格式组合 | 高级纹理压缩格式支持 | | **命令池重置改进** | 优化命令池重置行为 | 提升渲染效率 | | **图像布局转换** | 更灵活的图像布局转换 | 复杂渲染管线优化 | | **视图创建限制放宽** | 放宽图像视图创建限制 | 高级渲染效果实现 | ## 平台兼容性处理 ```cpp // 在插件中添加平台检测和优化 #if defined(UNITY_ANDROID) // Android设备需要检查Vulkan版本 if (s_Vulkan->GetVulkanVersion() < VK_API_VERSION_1_1) { // 使用扩展的兼容模式 s_Vulkan->AddEnabledDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); } #endif // Windows平台 #if defined(UNITY_STANDALONE_WIN) // 直接启用扩展 s_Vulkan->AddEnabledDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); #endif // iOS/Metal兼容处理 #if defined(UNITY_IOS) // iOS上使用保守设置 // 注意:iOS使用Metal,但可通过Vulkan兼容层支持 #endif ``` ## 性能优化建议 1. **纹理格式动态选择**: ```csharp public TextureFormat SelectOptimalTextureFormat() { TextureFormat[] preferredFormats = { TextureFormat.BC7, // 高质量压缩 TextureFormat.ASTC_4x4, // 移动设备优化 TextureFormat.DXT5, // 桌面设备优化 TextureFormat.RGBA32 // 回退格式 }; foreach (var format in preferredFormats) { if (IsImageFormatCompatible(format)) { return format; } } return TextureFormat.RGBA32; } ``` 2. **非正方形纹理处理**: ```csharp Texture2D CreateNonSquareTexture(int width, int height) { TextureFormat format = SelectOptimalTextureFormat(); var texture = new Texture2D(width, height, format, false); // 应用特殊视图 System.IntPtr vkImage = texture.GetNativeTexturePtr(); System.IntPtr imageView = CreateNonSquareImageView( vkImage, format, (int)VkImageViewType.VK_IMAGE_VIEW_TYPE_2D, (uint)VkImageAspectFlagBits.VK_IMAGE_ASPECT_COLOR_BIT ); return texture; } ``` 3. **渲染管线优化**: ```csharp void ConfigureRenderPipeline() { if (IsMaintenance1Supported()) { // 启用高级图像布局转换 GraphicsSettings.advancedImageLayoutTransitions = true; // 优化命令池管理 GraphicsSettings.commandPoolResetMode = CommandPoolResetMode.ResetOnly; } } ``` ## 验证扩展是否启用 ```csharp public bool IsMaintenance1Supported() { if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Vulkan) return false; // 获取支持的Vulkan扩展列表 var extensions = new List<string>(); try { var prop = typeof(UnityEngine.Rendering.GraphicsDeviceSettings) .GetProperty("vulkanDeviceExtensions"); if (prop != null) { extensions = prop.GetValue(null) as List<string>; } } catch {} return extensions != null && extensions.Contains("VK_KHR_maintenance1"); } ``` ## 应用场景 1. **特殊尺寸纹理处理**: ```csharp // 创建宽高比非1:1的纹理 Texture2D CreateBannerTexture(int width, int height) { if (IsMaintenance1Supported()) { return CreateNonSquareTexture(width, height); } else { // 回退方案:创建正方形纹理并调整UV int size = Mathf.Max(width, height); return new Texture2D(size, size, TextureFormat.RGBA32, false); } } ``` 2. **高级纹理压缩**: ```csharp void LoadCompressedTexture(string path) { byte[] data = File.ReadAllBytes(path); TextureFormat format = SelectOptimalTextureFormat(); Texture2D texture = new Texture2D(2, 2, format, false); texture.LoadRawTextureData(data); texture.Apply(); } ``` 3. **复杂渲染效果**: ```glsl // 在着色器中使用特殊视图 sampler2D _NonSquareTex; fixed4 frag (v2f i) : SV_Target { // 使用非正方形纹理的特殊采样 float2 adjustedUV = float2(i.uv.x * 0.5, i.uv.y); fixed4 col = tex2D(_NonSquareTex, adjustedUV); return col; } ``` ## 注意事项 1. **Unity版本要求**: - 最低版本: Unity 2018.3+ - 推荐版本: Unity 2020.3 LTS+ - 必须使用Vulkan图形API 2. **硬件兼容性**: - Vulkan 1.0设备需要显式启用扩展 - Vulkan 1.1+设备已包含核心功能 - 移动设备: Adreno 500+/Mali-G71+支持良好 - 桌面设备: NVIDIA 600系列+/AMD GCN 1.0+ 3. **性能考量**: - 非正方形纹理可能增加内存占用 - 复杂图像格式转换可能增加GPU负载 - 建议在性能关键路径进行兼容性检查 4. **着色器兼容性**: - 使用`UnityObjectToClipPos`替换旧版`_Object2World`[^2] - 正确初始化输出变量`UNITY_INITIALIZE_OUTPUT`[^1] - 使用`TRANSFORM_TEX`进行纹理坐标变换 通过以上实现,您可以在Unity项目中充分利用VK_KHR_maintenance1扩展,优化特殊尺寸纹理处理、高级格式支持和渲染管线性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值