You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity安卓平台:检测OpenGL是否不支持GPU纹理缩放操作

GPU Texture Scaling Failures: Detection & Root Cause Analysis

Let's break this down for you—first addressing how to reliably detect scaling failures, then diving into why this issue hits devices like the 2012 Nexus 7.

1. Detecting GPU Scaling Failures

Since failure behavior varies across hardware, use a combination of checks to catch issues:

  • Sample Key Pixels for Anomalies
    The Nexus 7 produces a uniform 205,205,205 gray when failing, so you can check for this or other unexpected color patterns. Add a helper function to validate the scaled result:

    private static bool IsTextureCorrupted(Texture2D tex) {
        // Sample multiple pixels to avoid false positives
        Color[] testPixels = {
            tex.GetPixel(0, 0),
            tex.GetPixel(tex.width-1, tex.height-1),
            tex.GetPixel(tex.width/2, tex.height/2)
        };
        foreach (Color c in testPixels) {
            // Check for the Nexus 7's signature gray (adjust if your failure mode differs)
            if (Mathf.Approximately(c.r, 205/255f) && Mathf.Approximately(c.g, 205/255f) && Mathf.Approximately(c.b, 205/255f)) {
                return true;
            }
        }
        return false;
    }
    

    Call this right after generating the scaled texture before using it.

  • Check OpenGL ES Errors
    GLES 2.0 devices will report errors for unsupported operations. Insert GL.GetError() calls after critical GPU steps in _gpu_scale:

    static void _gpu_scale(Texture2D src, int width, int height, FilterMode fmode) {
        src.filterMode = fmode;
        src.Apply(true);
    
        RenderTexture rtt = new RenderTexture(width, height, 32);
        Graphics.SetRenderTarget(rtt);
        Debug.Log($"GLES Error after RTT setup: {GL.GetError()}");
    
        GL.LoadPixelMatrix(0,1,1,0);
        Debug.Log($"GLES Error after matrix setup: {GL.GetError()}");
    
        GL.Clear(true,true,new Color(0,0,0,0));
        Graphics.DrawTexture(new Rect(0,0,1,1),src);
        Debug.Log($"GLES Error after draw: {GL.GetError()}");
    }
    

    Errors like GL_INVALID_OPERATION will directly point to the failing step.

  • Validate RenderTexture Integrity
    After rendering to the RTT, confirm it's active and the clear operation worked:

    Graphics.SetRenderTarget(rtt);
    if (RenderTexture.active != rtt) {
        // RTT setup failed—fall back to CPU scaling
        return;
    }
    // Check if the clear operation produced a transparent pixel (as expected)
    Color clearPixel = GL.ReadPixels(0, 0, 1, 1, 0);
    if (clearPixel.a != 0) {
        // GPU failed to clear the RTT, indicating a compatibility issue
    }
    
  • Fallback Comparison (For Critical Use Cases)
    For high-stakes scenarios, compare a small crop of the GPU-scaled result to a simple CPU-scaled reference (e.g., a 16x16 bilinear scale). Significant differences mean GPU scaling failed.

2. Root Cause Analysis (Nexus 7 & GLES 2.0 Issues)

The 2012 Nexus 7 uses a Tegra 3 GPU that only supports OpenGL ES 2.0, which has strict limitations that clash with your current code:

  • NPOT Texture Restrictions
    GLES 2.0 does not require support for Non-Power-Of-Two (NPOT) textures. While the Tegra 3 offers partial support, NPOT textures cannot use:

    • Mipmaps (required for Trilinear filtering)
    • Repeat wrap modes
      Your code defaults to FilterMode.Trilinear and calls src.Apply(true) (generating mipmaps). If your source texture is NPOT, the Tegra 3 will fail to generate mipmaps or apply Trilinear filtering, leading to corrupted output.
  • RenderTexture Format Compatibility
    Your code creates a RenderTexture with new RenderTexture(width, height, 32), which uses a default format. GLES 2.0 devices have strict format requirements, and the default ARGB32 format may not be supported for RTTs on the Nexus 7. Explicitly specifying a compatible format (like RenderTextureFormat.RGBA32) can resolve this.

  • Trilinear Filtering Limitations
    Trilinear filtering in GLES 2.0 requires mipmaps, which (as noted) often don't work with NPOT textures. Even for POT textures, older GPUs like the Tegra 3 struggle with Trilinear on RTTs. Switching to Bilinear or Point filtering for GLES 2.0 devices fixes this.

  • GL.LoadPixelMatrix Behavior
    While GL.LoadPixelMatrix(0,1,1,0) is intended to set a normalized orthographic projection, some older GPUs handle matrix transformations inconsistently. A more robust approach for GLES 2.0 is to use a custom orthographic matrix instead of relying on this helper.

Quick Fixes for GLES 2.0 Compatibility

To make your code work on devices like the Nexus 7:

  1. Adjust Filtering Based on GLES Version
    if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL ES 2.")) {
        fmode = FilterMode.Bilinear; // Avoid Trilinear which requires mipmaps
    }
    
  2. Handle NPOT Textures
    bool isNPOT = (src.width & (src.width - 1)) != 0 || (src.height & (src.height - 1)) != 0;
    if (isNPOT) {
        src.wrapMode = TextureWrapMode.Clamp; // Required for NPOT in GLES 2.0
        src.Apply(false); // Skip mipmap generation
    }
    
  3. Explicitly Define RenderTexture Format
    RenderTexture rtt = new RenderTexture(width, height, 32, RenderTextureFormat.RGBA32);
    

Original TextureScaler Code Reference

using UnityEngine;

/// A utility class with functions to scale Texture2D Data.
/// 
/// Scale is performed on the GPU using RTT, so it's blazing fast.
/// Setting up and Getting back the texture data is the bottleneck.
/// But Scaling itself costs only 1 draw call and 1 RTT State setup!
/// WARNING: This script overrides the RTT Setup! (It sets a RTT!)
/// 
/// Note: This scaler does NOT support aspect ratio based scaling. You will have to do it yourself!
/// It supports Alpha, but you will have to divide by alpha in your shaders,
/// because of premultiplied alpha effect. Or you should use blend modes.
public class TextureScaler {
    /// <summary>
    /// Returns a scaled copy of given texture.
    /// </summary>
    /// <param name="tex">Source texture to scale</param>
    /// <param name="width">Destination texture width</param>
    /// <param name="height">Destination texture height</param>
    /// <param name="mode">Filtering mode</param>
    public static Texture2D scaled(Texture2D src, int width, int height, FilterMode mode = FilterMode.Trilinear) {
        Rect texR = new Rect(0,0,width,height);
        _gpu_scale(src,width,height,mode);
        //Get rendered data back to a new texture
        Texture2D result = new Texture2D(width, height, TextureFormat.ARGB32, true);
        result.Resize(width, height);
        result.ReadPixels(texR,0,0,true);
        return result;
    }

    /// <summary>
    /// Scales the texture data of the given texture.
    /// </summary>
    /// <param name="tex">Texture to scale</param>
    /// <param name="width">New width</param>
    /// <param name="height">New height</param>
    /// <param name="mode">Filtering mode</param>
    public static void scale(Texture2D tex, int width, int height, FilterMode mode = FilterMode.Trilinear) {
        Rect texR = new Rect(0,0,width,height);
        _gpu_scale(tex,width,height,mode);
        // Update new texture
        tex.Resize(width, height);
        tex.ReadPixels(texR,0,0,true);
        tex.Apply(true); //Remove this if you don't want us applying textures for you :)
    }

    // Internal utility that renders the source texture into the RTT - the scaling method itself.
    static void _gpu_scale(Texture2D src, int width, int height, FilterMode fmode) {
        //We need the source texture in VRAM because we render with it
        src.filterMode = fmode;
        src.Apply(true);

        //Using RTT for best quality and performance. Thanks, Unity 5
        RenderTexture rtt = new RenderTexture(width, height, 32);
        //Set the RTT in order to render to it
        Graphics.SetRenderTarget(rtt);

        //Setup 2D matrix in range 0..1, so nobody needs to care about size
        GL.LoadPixelMatrix(0,1,1,0);

        //Then clear & draw the texture to fill the entire RTT.
        GL.Clear(true,true,new Color(0,0,0,0));
        Graphics.DrawTexture(new Rect(0,0,1,1),src);
    }
}

内容的提问来源于stack exchange,提问作者pertz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:24