【发布时间】:2015-03-06 10:40:16
【问题描述】:
我在为项目编写片段着色器时遇到了一些问题。我正在创建一个无调色板的终端模拟器,所以我想我会使用以下着色器:
#version 110
uniform sampler2D tileset;
uniform sampler2D indices;
uniform sampler2D colors;
uniform sampler2D bgcolors;
uniform vec2 tileset_size;
uniform vec2 size;
varying vec2 tex_coord;
void main(void)
{
// Calculated texture coordinate
vec2 screen_pos = vec2(gl_FragCoord.x / 800.0, 1.0 - gl_FragCoord.y / 500.0);
// Indirect texture lookup 1
vec2 index = texture2D(indices, screen_pos.st).rg;
vec4 color = texture2D(colors, screen_pos.st);
vec4 bgcolor = texture2D(bgcolors, screen_pos.st);
// Calculated texture coordinate
vec2 tileCoord;
//256.0 because the [0,256) byte value is normalized on [0,1)
tileCoord.x = mod(screen_pos.x, 1.0/size.x)*(size.x/tileset_size.x) + floor(index.x*256.0)/tileset_size.x;
tileCoord.y = mod(screen_pos.y, 1.0/size.y)*(size.y/tileset_size.y) + floor(index.y*256.0)/tileset_size.y;
// Indirect texture lookup 2
vec4 tile = texture2D(tileset, tileCoord);
vec4 final = tile*color;
gl_FragColor = vec4(mix(bgcolor.rgb, final.rgb, final.a), 1.0);
}
为了将它渲染到屏幕上,我绘制了一个大四边形,然后让着色器完成其余的工作。
此代码生成所需的输出。但是,它以每 帧 5 秒 的速度执行此操作。根据我的研究,这可能是由于显示驱动程序在软件而不是硬件中执行我的着色器。我发现通过取消注释texture2D() 调用,事情又顺利进行了。
这导致我得到以下代码:
void main(void)
{
//vec2 screen_pos = vec2(gl_FragCoord.x / 800.0, 1.0 - gl_FragCoord.y / 500.0);
vec2 screen_pos = vec2(0.5, 0.5);
vec2 index = texture2D(indices, screen_pos.st).rg;
vec4 color = texture2D(colors, screen_pos.st);
vec4 bgcolor = texture2D(bgcolors, screen_pos.st);
vec4 tiles = texture2D(tileset, screen_pos.st);
gl_FragColor = vec4(index.rgg + color.rgb + bgcolor.rgb + tiles.rgb, 1.0);
}
结果同样非常缓慢。注释掉最后一行 vec4 tiles = ...,并将其从输出中删除,再次顺利运行。所以我查看了我的设备支持的 texture2D 调用的数量。我得到了以下结果:
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB: 8
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB: 16
GL_MAX_TEXTURE_IMAGE_UNITS_ARB: 8
GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: 8
所以一定有什么事情发生了。即使我的每个调用都是间接访问(我很确定它们不是),我最多应该有 8 个!另外,glGetShaderInfoLog() 和glGetProgramInfoLog() 无话可说。
我应该列出我的规格:
- 机器:运行 Linux 3.17.1 的 Intel Atom Duo(特别是 Arch)
- GPU:英特尔 945GM/GMS/GME、943/940GML 集成图形控制器 Mesa
- 版本:10.4.5
是的,我在调用标准 glewInit() 过程后检查 GL_ARB_fragment_program。
所以,我想到了两种可能的解决方案。
- ARB_fragment_shader 的 spec sheet 声明最小 纹理间接数应该是 4。这可能是我的 程序没有正确初始化 ARB_fragment_program,并且 系统正在回退到默认值。 (我尝试将“ARB”放入尽可能多的 尽可能与着色器相关的地方,但我认为 glewInit() 可以解决这个问题 无论如何。)
- Mesa 的编译器在我的特定芯片上存在错误。最后发帖here 提到了这一点,并且有一个类似的声音 GPU。基本上,编译器 错误地将所有纹理读取标记为间接纹理读取,从而 错误地拒绝程序。
如果有人在这方面有任何令人难以置信的知识,我真的很想听听。通常我会说“搞砸了,买一台更好的电脑”,但拥有高端显卡只是为了运行终端仿真器的纯粹讽刺是......好吧......讽刺。
如果我忘记在这里写一些信息,请告诉我。
编辑
glxinfo -l:pastebin
ARB assembly(部分由cgc生成)
禁用任何 TEX 指令使其进入硬件模式,所有 4 条指令都将返回到软件模式。
【问题讨论】:
-
不能对阅读表示感谢?我认为这是一篇很长的帖子。
-
你能添加
glxinfo -l的输出吗(片段程序和片段着色器部分)?您也可以尝试就地计算结果颜色,例如vec4 result = vec4(0); vec4 texresult = texture2D(...); result += texresult; texresult = texture2D(...); ...- 可能是您受到临时寄存器数量的限制。 -
作为辅助解决方案,您可以使用 ARB_fragment_program 代替片段着色器,这可以让您更好地控制代码。这将需要在 ARB 程序集中编写着色器,或者使用可以输出它的编译器(例如 nvidia cgc)。
-
我安装了cgc编译器。我是否以同样的方式将其发送到 OpenGL? (自动检测 ARB 程序集)我也找到了 glProgramBinary(),也许用这个?
-
对于一个理智的 GLSL 编译器,第二个着色器中的这些纹理提取都不是间接的。它们都使用恒定坐标。因此,如果您仍然遇到性能问题,那么您可以将间接纹理提取作为问题扔掉。也许您的实际问题是
tileset使用的图像格式/过滤器?那个特定的采样器似乎是两个着色器中的问题。
标签: opengl glsl fragment-shader mesa