我在为项目编写片段着色器时遇到了一些问题。我正在创建一个无调色板终端仿真器,所以我想我会使用以下着色器来做到这一点:
#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的规格表指出纹理间接的最小数量应该是 4。这可能是我的程序没有正确初始化 ARB_fragment_program,系统正在回退到默认值。(我尝试将“ARB”放在尽可能多的与着色器相关的地方,但我认为 glewInit() 无论如何都会处理这个问题。)
- Mesa 的编译器对我的特定芯片有一个错误。这里的最后一篇文章 提到了这一点,并且有一个类似的 GPU。基本上,编译器错误地将所有纹理读取标记为间接纹理读取,从而错误地拒绝程序。
如果有人在这方面有任何令人难以置信的知识,我真的很想听听。通常我会说“去他妈的,买一台更好的电脑”,但拥有高端显卡只是为了运行终端仿真器的纯粹讽刺是......好吧......讽刺。
如果我忘记在这里写一些信息,请告诉我。
编辑
glxinfo -l:粘贴
ARB 程序集(部分由 cgc 生成)
禁用任何 TEX 指令会将其置于硬件模式,所有 4 条指令都将返回到软件模式。