GLKTextureLoader在第一次加载某个纹理时失败,但第二次成功。

10
我正在使用GLKit制作一个使用OpenGL ES 2.0的iPhone应用程序。 我正在使用GLKTextureLoader同步加载纹理。问题在于对于某些纹理,第一次加载失败。 它显示以下错误:
The operation couldn't be completed. (GLKTextureLoaderErrorDomain error 8.)

针对此错误代码,苹果文档给出了以下说明:


GLKTextureLoaderErrorUncompressedTextureUpload
An uncompressed texture could not be uploaded.
Available in iOS 5.0 and later.
Declared in GLKTextureLoader.h.

(不是很多)。

我是否在opengl上下文处于某种繁忙状态时尝试加载纹理?

注:

  • 在加载此纹理之前,我加载其他纹理,并且这些纹理在第一次尝试时都有效。此外,完全相同的纹理文件将在第二次尝试时正常加载。
  • 应该有足够的免费视频内存,因为在此之前我只加载了几个纹理。
  • 纹理是带alpha的未压缩PNG,但我也尝试过使用TGA(24位和32位),但没有成功。

欢迎任何想法,谢谢

编辑

更多信息:

  • opengl上下文在所有屏幕之间共享。我这样做是为了在屏幕之间保持我的着色器和纹理已加载。

  • 上述问题发生在我转到第二个屏幕时。在第一个屏幕上,我绘制带纹理的东西没有问题(虽然是其他纹理)。

  • 上述问题发生在我将内容(游戏实体)加载到游戏世界中时。每个实体都尝试加载纹理。我有一个简单的缓存系统,仅加载一次纹理,然后为所有其他实体返回相同的id。我在一个方法中同步加载实体。第一个实体无法加载纹理,然后是第二个成功,然后是第三个获取缓存的id。

  • 我在viewDidAppear中调用了加载实体方法,并尝试在加载任何实体之前添加了2秒的休眠,但没有改变。

编辑:

纹理加载代码:


- (GLKTextureInfo *)loadTextureAtPath:(NSString*)path ofType:(NSString*)type withKey:(NSString *)key 
{
    GLKTextureInfo* tex;

    tex = [self textureWithKey:key];
    if (tex)
        return tex;

    NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithBool:NO],
                              GLKTextureLoaderOriginBottomLeft, 
                              nil];

    NSError * error;    
    NSString *bundlepath = [[NSBundle mainBundle] pathForResource:path ofType:type];

    tex = [GLKTextureLoader textureWithContentsOfFile:bundlepath options:options error:&error];
    if (tex == nil) 
        DLOG_LOCAL(@"Error loading texture: %@", [error localizedDescription]);                
    else
        [textures setObject:tex forKey:key];

    return tex;
}



感谢您的评论。我已经在问题中添加了更多信息。 - Andrei Stanescu
你正在使用类似于以下代码的同步方式加载纹理(而不仅仅是实体):+ (GLKTextureInfo *)textureWithContentsOfFile:(NSString *)fileName options:(NSDictionary *)textureOperations error:(NSError **)outError ? - Mike K
我已经在上面发布了我的纹理加载代码。 - Andrei Stanescu
你尝试过在viewDidLoad而不是viewDidAppear中加载实体吗? - Johnmph
另外,我刚刚再次测试了该项目,问题已经消失了。该项目保持了我提问时的状态,所以我认为可能是SDK中的一个bug导致的? - Andrei Stanescu
显示剩余4条评论
8个回答

32

我也在学习

关于IT技术的内容。
The operation couldn’t be completed. (GLKTextureLoaderErrorDomain error 8.)

在运行时较接近启动时成功加载了几个先前的纹理后,当需要在运行时晚期加载纹理时。我能够通过在GLKTextureLoader调用之前插入以下代码行来解决这个问题:before
NSLog(@"GL Error = %u", glGetError());

果然,GL报告了一个错误,但并不需要我解决这个错误才能让 GLKTextureLoader 正常工作。 仅仅得到GL错误就足够了。


是的,这是苹果代码中的一个重大错误。有人没有好好思考,他们决定如果全局GL状态存在任何错误,就返回“失败”,而不是编写一行代码来检查它在进入他们的方法时是否已经设置好了:(。 - Adam
谢谢!我花了几天的时间解决这个随机丢失纹理的问题。 - shelll
+1!对我也有用。我正在Xcode5上开发,部署在6.1设备上。看起来如果OpenGL存在任何错误,它将只会导致GLKTextureLoader不尝试加载纹理(这...好吧...我可以接受)。 - Steven Lu
它也帮助了我,在iOS 9.0设备上使用xCode 7.0。 - CryingHippo

4
在加载纹理之前启用纹理时,出现了这个问题。只需在加载后将glEnable(GL_TEXTURE)移到后面,问题就解决了。

谢谢。一定会尝试 :) - Andrei Stanescu
我刚意识到我的OpenGL ES 2.0项目中没有启用GL_TEXTURE,所以我不知道你的答案是否相关。在这种情况下,一切都取决于着色器来确定我是否正在绘制纹理三角形。 - Andrei Stanescu

3

我曾遇到过类似的问题。这是由于某个纹理的宽度或高度不是2的幂次方导致的。GLKTextureLoader无法加载这个纹理以及其后面的图片。在每次加载纹理后检查glGetError()函数可以找出问题所在。


3
也许你已经解决了这个问题,但是你是否正在使用多个上下文?也许你应该使用共享组异步加载纹理。
所以,而不是使用tex = [GLKTextureLoader textureWithContentsOfFile:bundlepath options:options error:&error];
可以使用类似以下的代码:
GLKTextureLoader *textureloader = [[GLKTextureLoader alloc] initWithSharegroup:self.eaglContext.sharegroup];
GLKTextureInfo *myTexture;
[textureloader textureWithCGImage:_currentForegroundImage.CGImage options:nil queue:nil completionHandler:^(GLKTextureInfo *textureInfo, NSError *error) {
        myTexture = textureInfo;
        if(error) {
            // log stuff
        }
        // do something
}];

2

好的,我会再试一次,因为我遇到了同样的错误。看起来是这样的,如果有其他尚未处理的glError,那么第一次加载纹理时就会出现问题。

在加载失败的纹理之前,检查是否有glError,并追踪该错误发生的位置。或者在加载纹理之前捕获一个opengl帧,并查看是否先抛出了glError。当我遇到错误8时,这两次都发生了这种情况,而且每次我修复了先前发生的错误后,这个错误都消失了。


1
我还发现,当尝试使用大于最大纹理大小的图像创建2D纹理时,会出现此错误。有关最大大小,请参见Apple的Open GL ES平台说明,尽管这些对于较新的设备似乎不正确,因此最好是直接获取该值

1

我遇到了同样的问题。除了出现多个文件操作之外,我不确定它确切地发生了什么。例如,在第一次使用纹理加载器后立即执行文件加载(用于模型数据)会导致错误8弹出。我通过在第一次调用纹理加载器后进行其他操作来修复了我的程序。


谢谢。我会调查一下。现在我正在度假……但我会在1月1日后尝试这个 :) - Andrei Stanescu
我已经研究了这个解决方案。我确保没有并发文件读取,但问题仍然存在。无论如何还是谢谢。 - Andrei Stanescu

0

我曾经遇到过非常类似的问题,通过调用setCurrentContext方法解决了。

self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.context];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接