- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试改进 Henry Thasler 的 GLSL 双单算法实现(来自他的 GLSL Mandelbrot 演示),以便在 Linux 上的 NVIDIA 图形上可靠地工作。我最近了解到,自从 OpenGL 4.0(§4.7 The Precise Qualifier in the spec)或 GL_ARB_gpu_shader5
扩展(spec)我们可以使用 precise
使计算遵循 GLSL 源中指定的精确算术运算序列的限定符。
但是下面的尝试似乎并没有带来任何改善:
#version 330
#extension GL_ARB_gpu_shader5 : require
vec2 ds_add(vec2 dsa, vec2 dsb)
{
precise float t1 = dsa.x + dsb.x;
precise float e = t1 - dsa.x;
precise float t2 = ((dsb.x - e) + (dsa.x - (t1 - e))) + dsa.y + dsb.y;
precise vec2 dsc;
dsc.x = t1 + t2;
dsc.y = t2 - (dsc.x - t1);
return dsc;
}
结果与未添加 precise
相同。我检查了算法本身是否正确:它在 Intel Core i7-4765T 内置显卡上按原样工作(即使没有 precise
),如果我隐藏一些变量以抑制优化,那么 NVidia也给出了正确的结果。以下是我如何抑制优化:
#version 330
#define hide(x) ((x)*one)
uniform float one=1;
vec2 ds_add(vec2 dsa, vec2 dsb)
{
float t1 = dsa.x + dsb.x;
float e = hide(t1) - dsa.x;
float t2 = ((dsb.x - e) + (dsa.x - (t1 - e))) + dsa.y + dsb.y;
vec2 dsc;
dsc.x = t1 + t2;
dsc.y = t2 - (hide(dsc.x) - t1);
return dsc;
}
所以,显然,我错误地使用了 precise
限定词。但这里到底出了什么问题?
作为引用,我使用的是带有二进制 nvidia 驱动程序 390.116 的 NVidia GeForce GTX 750Ti。这是完整的 C++ 测试:
#include <cmath>
#include <vector>
#include <string>
#include <limits>
#include <iomanip>
#include <iostream>
// glad.h is generated by the following command:
// glad --out-path=. --generator=c --omit-khrplatform --api="gl=3.3" --profile=core --extensions=
#include "glad/glad.h"
#include <GL/freeglut.h>
#include <glm/glm.hpp>
using glm::vec4;
GLuint vao, vbo;
GLuint texFBO;
GLuint program;
GLuint fbo;
int width=1, height=2;
void printShaderOutput(int texW, int texH)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texFBO);
std::vector<vec4> data(texW*texH);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data.data());
std::cout << "a,b,sum,relError(sum),note\n";
for(int i=0;i<width;++i)
{
const auto a=double(data[i+width*0].x)+double(data[i+width*0].y);
const auto b=double(data[i+width*0].z)+double(data[i+width*0].w);
const auto sum=double(data[i+width*1].x)+double(data[i+width*1].y);
const auto trueSum=a+b;
const auto sumErr=(sum-trueSum)/trueSum;
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< a << ',' << b << ','
<< sum << ','
<< std::setprecision(3)
<< sumErr << ','
<< (std::abs(sumErr)>1e-14 ? "WARN" : "OK")
<< '\n';
}
std::cout.flush();
}
GLuint makeShader(GLenum type, std::string const& srcStr)
{
const auto shader=glCreateShader(type);
const GLint srcLen=srcStr.size();
const GLchar*const src=srcStr.c_str();
glShaderSource(shader, 1, &src, &srcLen);
glCompileShader(shader);
GLint status=-1;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
assert(glGetError()==GL_NO_ERROR);
assert(status);
return shader;
}
void loadShaders()
{
program=glCreateProgram();
const auto vertexShader=makeShader(GL_VERTEX_SHADER, 1+R"(
#version 330
in vec4 vertex;
void main() { gl_Position=vertex; }
)");
glAttachShader(program, vertexShader);
const auto fragmentShader=makeShader(GL_FRAGMENT_SHADER, 1+R"(
#version 330
#extension GL_ARB_gpu_shader5 : require
vec2 ds_add(vec2 dsa, vec2 dsb)
{
precise float t1 = dsa.x + dsb.x;
precise float e = t1 - dsa.x;
precise float t2 = ((dsb.x - e) + (dsa.x - (t1 - e))) + dsa.y + dsb.y;
precise vec2 dsc;
dsc.x = t1 + t2;
dsc.y = t2 - (dsc.x - t1);
return dsc;
}
uniform vec2 a, b;
out vec4 color;
void main()
{
if(gl_FragCoord.y<1) // first row
color=vec4(a,b);
else if(gl_FragCoord.y<2) // second row
color=vec4(ds_add(a,b),0,0);
}
)");
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint status=0;
glGetProgramiv(program, GL_LINK_STATUS, &status);
assert(glGetError()==GL_NO_ERROR);
assert(status);
glDetachShader(program, fragmentShader);
glDeleteShader(fragmentShader);
glDetachShader(program, vertexShader);
glDeleteShader(vertexShader);
}
void setupBuffers()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
const GLfloat vertices[]=
{
-1, -1,
1, -1,
-1, 1,
1, 1,
};
glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
constexpr GLuint attribIndex=0;
constexpr int coordsPerVertex=2;
glVertexAttribPointer(attribIndex, coordsPerVertex, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(attribIndex);
glBindVertexArray(0);
}
bool init()
{
if(!gladLoadGL())
{
std::cerr << "Failed to initialize GLAD\n";
return false;
}
if(!GLAD_GL_VERSION_3_3)
{
std::cerr << "OpenGL 3.3 not supported\n";
return false;
}
glGenTextures(1, &texFBO);
glGenFramebuffers(1,&fbo);
loadShaders();
setupBuffers();
glViewport(0,0,width,height);
glBindTexture(GL_TEXTURE_2D,texFBO);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA32F,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,nullptr);
glBindTexture(GL_TEXTURE_2D,0);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,texFBO,0);
const auto status=glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(status==GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER,0);
return true;
}
void display()
{
const static bool inited=init();
if(!inited) std::exit(1);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glUseProgram(program);
#define SPLIT_DOUBLE_TO_FLOATS(x) GLfloat(x),GLfloat(x-GLfloat(x))
glUniform2f(glGetUniformLocation(program,"a"),SPLIT_DOUBLE_TO_FLOATS(3.1415926535897932));
glUniform2f(glGetUniformLocation(program,"b"),SPLIT_DOUBLE_TO_FLOATS(2.7182818284590452));
glUniform1f(glGetUniformLocation(program,"rtWidth"),width);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
printShaderOutput(width, height);
std::exit(0);
glFinish();
}
int main(int argc, char** argv)
{
glutInitContextVersion(3,3);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(width, height);
glutCreateWindow("Test");
glutDisplayFunc(display);
glutMainLoop();
}
在不同情况下,我已经能够从 GLSL 程序二进制文件中提取 NVfp5.0 程序集:
hide
和 precise
的简单案例:!!NVfp5.0
OPTION NV_internal;
OPTION NV_bindless_texture;
PARAM c[2] = { program.local[0..1] };
TEMP R0;
TEMP T;
TEMP RC, HC;
OUTPUT result_color0 = result.color;
SLT.F R0.x, fragment.position.y, {1, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
MOV.F result_color0.xy, c[0];
MOV.F result_color0.zw, c[1].xyxy;
ELSE;
SLT.F R0.x, fragment.position.y, {2, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
ADD.F R0.y, -c[0].x, c[0].x;
ADD.F R0.x, -c[1], c[1];
ADD.F R0.x, R0, R0.y;
ADD.F R0.x, R0, c[0].y;
ADD.F R0.y, R0.x, c[1];
ADD.F R0.x, c[0], c[1];
ADD.F result_color0.x, R0, R0.y;
ADD.F result_color0.y, R0, -R0;
MOV.F result_color0.zw, {0, 0, 0, 0}.x;
ENDIF;
ENDIF;
END
precise
的情况(请注意,除了“说明”中的 .PREC
后缀外,没有任何变化):!!NVfp5.0
OPTION NV_internal;
OPTION NV_bindless_texture;
PARAM c[2] = { program.local[0..1] };
TEMP R0;
TEMP T;
TEMP RC, HC;
OUTPUT result_color0 = result.color;
SLT.F R0.x, fragment.position.y, {1, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
MOV.F result_color0.xy, c[0];
MOV.F result_color0.zw, c[1].xyxy;
ELSE;
SLT.F R0.x, fragment.position.y, {2, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
ADD.F.PREC R0.y, -c[0].x, c[0].x;
ADD.F.PREC R0.x, -c[1], c[1];
ADD.F.PREC R0.x, R0, R0.y;
ADD.F.PREC R0.x, R0, c[0].y;
ADD.F.PREC R0.y, R0.x, c[1];
ADD.F.PREC R0.x, c[0], c[1];
ADD.F.PREC result_color0.x, R0, R0.y;
ADD.F.PREC result_color0.y, R0, -R0;
MOV.F result_color0.zw, {0, 0, 0, 0}.x;
ENDIF;
ENDIF;
END
hide
的情况确实有效,并且显然具有不同的算术运算顺序:!!NVfp5.0
OPTION NV_internal;
OPTION NV_bindless_texture;
PARAM c[3] = { program.local[0..2] };
TEMP R0, R1;
TEMP T;
TEMP RC, HC;
OUTPUT result_color0 = result.color;
SLT.F R0.x, fragment.position.y, {1, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
MOV.F result_color0.xy, c[1];
MOV.F result_color0.zw, c[2].xyxy;
ELSE;
SLT.F R0.x, fragment.position.y, {2, 0, 0, 0};
TRUNC.U.CC HC.x, R0;
IF NE.x;
ADD.F R0.x, c[1], c[2];
MAD.F R0.y, R0.x, c[0].x, -c[1].x;
ADD.F R0.z, R0.x, -R0.y;
ADD.F R0.z, -R0, c[1].x;
ADD.F R0.y, -R0, c[2].x;
ADD.F R0.y, R0, R0.z;
ADD.F R0.y, R0, c[1];
ADD.F R0.y, R0, c[2];
ADD.F R1.x, R0, R0.y;
MAD.F R0.x, R1, c[0], -R0;
MOV.F R1.zw, {0, 0, 0, 0}.x;
ADD.F R1.y, R0, -R0.x;
MOV.F result_color0, R1;
ENDIF;
ENDIF;
END
最佳答案
我自己从未使用过 precise,但您可能会从此处学习 OpenCL 或 CUDA 中受益。
无论如何,你的GLSL version is 3.30, which is tied with OpenGL 3.3 .可以通过扩展获得精确限定符,但如果可以的话,我总是会尝试使用 OpenGL 的内置功能。</p>
扩展可能不会以相同的方式实现,我建议您至少尝试使用 GLSL 版本 4.0,最好是最新的 OpenGL/GLSL 版本。
有时,如果没有人使用这些旧扩展,它们可能会在较新的 GPU 上出现性能下降。
GPU 编译器倾向于更加自由地进行优化。您可能会从编译着色器的输出中受益,可能有一些方法可以使用 GLSL 查看 Nvidia 编译器的 PTX 程序集输出。使用 CUDA,您绝对可以预览汇编输出以确保编译器不会重新排序操作。
规范提到 MAD 是限定符的主要原因——它将强制编译器不使用 MAD 指令。也许很少用带有精确限定符的加法/减法进行测试。
如果 hide 为您解决了这个问题,最好就此结束,我怀疑 GLSL 方面是否已经彻底检查了精确的限定符。为此,我强烈推荐 CUDA 或 OpenCL,如果您还想快速显示纹理,则可以使用 CL-GL 互操作,这不是很痛苦。
precise 限定符可确保不会对操作进行重新排序,但不会提及不影响排序的优化。似乎 AMD 在使用它时只是关闭了优化。 Nvidia 仍然有可能应用影响您结果的优化,这些优化与操作顺序无关,而是与正在执行的加法的特定优化有关。
precise float t1 = dsa.x + dsb.x;
precise float e = t1 - dsa.x;
这可能会将 e
计算为简单的 dsb.x
。编译器可能仍在添加不影响操作顺序的优化,因为这是规范所保证的。除了重新排序的操作之外,我想不出任何会影响此结果的操作,但我不是这方面的专家。
另一件需要注意的事情是,根据我对规范的粗略阅读,ds_add 的结果可能也需要存储到一个精确的变量中,以便计算准确。该函数可能仅在 Nvidia 上内联(它们有更好的优化,至少在历史上是这样),所以我想编译器可能会执行内联,然后如果您将结果存储到一个非精确变量中,那么所有现有的精确限定符都是忽略。
关于c++ - 为什么 `precise`限定符不生效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56308534/
我想打印精度为 4 的 float 。我使用 numpy , jupyter notebook我试过: %precision %.4g %precision 2 np.set_printoptions
我不知道如何解决这个问题,我知道浮点数的显式、隐式和 IEEE-754 规范化表示,但如何将其分解为小问题。请帮我想象一下。 最佳答案 让我们假设 IEEE-754 单精度浮点数。在这样一个浮点数中,
我有一个从 Azure Log Analytics 查询返回的值(以字节表示): 我想将其转换为兆字节并使其更易于阅读。在本例中为“4.19 MB”。 当我尝试将字节值转换为兆字节时,我似乎无法让 K
我最近收到的一项家庭作业要求我们采用在计算机中执行时可能会造成精度损失的表达式,并对其进行更改以避免这种损失。 不幸的是,执行此操作的指示尚未非常明确。通过观察各种正在执行的示例,我知道有一些方法可以
这更多的是一个数值分析问题,而不是编程问题,但我想你们中的一些人能够回答它。 在两个 float 相加中,是否有精度损失?为什么? float 和整数相加时,是否有精度损失?为什么? 谢谢。 最佳答案
所以我知道浮点精度(以及 1.1 之类的东西如何不能用二进制精确表示)等等,但我想知道:那么,与数学相关的库如何实现无限精度?换句话说,例如,您将如何以二进制形式准确地表示 1.1?只是一个简短的描述
阅读本文 http://en.wikibooks.org/wiki/Ada_Programming/Types/delta 让我想知道 delta 的极限值是多少是。 例如 delta 127 ran
我有一个文档数据库,我可以在其中执行搜索。对于每一次搜索,都有 n 个肯定。现在,如果我通过 precision@k 和 recall@k 来评估搜索的性能,那么对于后者来说一切都很好: recall
我注意到在 Modelica(使用 Wolfram System Modeler 4.3)中集成延迟固定时间量的脉冲输入的数值问题: model PulseTest "Test FixedDelay
我看过很多关于系统时钟的讨论,据说例如标准 PC 时钟,例如Windows 的精确度仅为+/-10 毫秒,而实时系统时钟的精确度为亚毫秒级。但这些说法意味着什么?这种时序变化的严重程度完全取决于测量时
我一直在阅读一些内容,但我很难理解如何解释“数字 x”。即: type something is digits 6 我知道它的精度是 6 位数字,但我想让我困惑的是这是什么意思。 1) Y.XXXXX
我的 Elasticsearch 映射(我使用的是 ES 2.1)中有一个 date 类型的字段(输入格式 epoch_second)。我知道我可以在该字段上进行排序 { "sort": [
我在 C++ 中使用 CPLEX 来解决集线器位置问题,即 MIP,并且我最近发现了一组非常精确的输入,CPLEX 认为这些输入是不可行的(即 CPXMIP_INFEASIBLE),即使该问题确实可行
简单地说,魔术函数 %precision 不考虑简单变量输出的浮点精度。 #Configure matplotlib to run on the browser %matplotlib noteboo
我正在尝试使用 sass + compass 来制作流体网格,并且在计算它们时我需要我的 % 至少有 8 位数字,但现在 sass + compass 正在将我的小数四舍五入为 3 位数字。我发现如果
希望如此,我可以第一次发帖,告诉我我想问的问题。 我有cpp代码,可记录从fpga向下到纳秒级的时间戳。它将此值写入CSV。在同一个csv中,我正在计算连续时间戳之间的差异。 当我将其导出到pytho
我用JAVA编写了以下方法: public static float surface(float r) { return(4*Math.PI*Math.pow(r,2));
我试图找出为什么我的 Java 程序中会出现这种精度丢失错误。 这是错误: error: possible loss of precision int digit = num/Mat
关于 java-7 功能“精确重新抛出”和 final Exception ex 有很多问题,我找不到我的问题的明确答案。 “精确重新抛出”和final Exception之间有什么关系? publi
SciPy interpolation有 3 种支持的方法: Supported are “linear” and “nearest”, and “splinef2d”. “splinef2d” is
我是一名优秀的程序员,十分优秀!