Đó là một sai lầm khi cho rằng nhánh trong GPU và phân nhánh trong mã là những điều tương tự.
Đối với các điều kiện đơn giản, không bao giờ có phân nhánh nào cả. GPU có hướng dẫn di chuyển có điều kiện trực tiếp dịch sang các biểu thức bậc ba và các câu lệnh if-else đơn giản.
Trường hợp mọi thứ gặp sự cố là khi bạn có điều kiện lồng nhau hoặc nhiều thao tác phụ thuộc vào điều kiện. Sau đó, bạn phải xem xét liệu trình biên dịch GLSL là đủ thông minh để dịch tất cả thành các cmoves. Bất cứ khi nào có thể trình biên dịch sẽ phát ra mã thực hiện tất cả các nhánh và kết hợp lại kết quả với các chuyển động có điều kiện, nhưng nó không thể luôn làm điều đó.
Bạn phải biết khi nào cần trợ giúp. Không bao giờ đoán khi bạn có thể đo lường - sử dụng GPU Shader Analyzer của AMD hoặc GCG của Nvidia để xem đầu ra lắp ráp. Bộ hướng dẫn của GPU rất hạn chế và đơn giản nên đừng sợ cụm từ 'lắp ráp'.
Đây là một cặp chức năng chuyển đổi RGB/HSL mà tôi đã thay đổi xung quanh để chúng phát độc đáo với trình biên dịch GLSL của AMD, cùng với đầu ra lắp ráp. Tín dụng chuyển đến Paul Bourke cho mã chuyển đổi C ban đầu.
// HSL range 0:1
vec4 convertRGBtoHSL(vec4 col)
{
float red = col.r;
float green = col.g;
float blue = col.b;
float minc = min3(col.r, col.g, col.b);
float maxc = max3(col.r, col.g, col.b);
float delta = maxc - minc;
float lum = (minc + maxc) * 0.5;
float sat = 0.0;
float hue = 0.0;
if (lum > 0.0 && lum < 1.0) {
float mul = (lum < 0.5) ? (lum) : (1.0-lum);
sat = delta/(mul * 2.0);
}
vec3 masks = vec3(
(maxc == red && maxc != green) ? 1.0 : 0.0,
(maxc == green && maxc != blue) ? 1.0 : 0.0,
(maxc == blue && maxc != red) ? 1.0 : 0.0
);
vec3 adds = vec3(
((green - blue)/delta),
2.0 + ((blue - red )/delta),
4.0 + ((red - green)/delta)
);
float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
hue += dot(adds, masks);
hue *= deltaGtz;
hue /= 6.0;
if (hue < 0.0)
hue += 1.0;
return vec4(hue, sat, lum, col.a);
}
đầu ra hội cho chức năng này:
1 x: MIN ____, R0.y, R0.z
y: ADD R127.y, -R0.x, R0.z
z: MAX ____, R0.y, R0.z
w: ADD R127.w, R0.x, -R0.y
t: ADD R127.x, R0.y, -R0.z
2 y: MAX R126.y, R0.x, PV1.z
w: MIN R126.w, R0.x, PV1.x
t: MOV R1.w, R0.w
3 x: ADD R125.x, -PV2.w, PV2.y
y: SETE_DX10 ____, R0.x, PV2.y
z: SETNE_DX10 ____, R0.y, PV2.y
w: SETE_DX10 ____, R0.y, PV2.y
t: SETNE_DX10 ____, R0.z, PV2.y
4 x: CNDE_INT R123.x, PV3.y, 0.0f, PV3.z
y: CNDE_INT R125.y, PV3.w, 0.0f, PS3
z: SETNE_DX10 ____, R0.x, R126.y
w: SETE_DX10 ____, R0.z, R126.y
t: RCP_e R125.w, PV3.x
5 x: MUL_e ____, PS4, R127.y
y: CNDE_INT R123.y, PV4.w, 0.0f, PV4.z
z: ADD/2 R127.z, R126.w, R126.y VEC_021
w: MUL_e ____, PS4, R127.w
t: CNDE_INT R126.x, PV4.x, 0.0f, 1065353216
6 x: MUL_e ____, R127.x, R125.w
y: CNDE_INT R123.y, R125.y, 0.0f, 1065353216
z: CNDE_INT R123.z, PV5.y, 0.0f, 1065353216
w: ADD ____, PV5.x, (0x40000000, 2.0f).y
t: ADD ____, PV5.w, (0x40800000, 4.0f).z
7 x: DOT4 ____, R126.x, PV6.x
y: DOT4 ____, PV6.y, PV6.w
z: DOT4 ____, PV6.z, PS6
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f
t: SETGT_DX10 R125.w, 0.5, R127.z
8 x: ADD R126.x, PV7.x, 0.0f
y: SETGT_DX10 ____, R127.z, 0.0f
z: ADD ____, -R127.z, 1.0f
w: SETGT_DX10 ____, R125.x, 0.0f
t: SETGT_DX10 ____, 1.0f, R127.z
9 x: CNDE_INT R127.x, PV8.y, 0.0f, PS8
y: CNDE_INT R123.y, R125.w, PV8.z, R127.z
z: CNDE_INT R123.z, PV8.w, 0.0f, 1065353216
t: MOV R1.z, R127.z
10 x: MOV*2 ____, PV9.y
w: MUL ____, PV9.z, R126.x
11 z: MUL_e R127.z, PV10.w, (0x3E2AAAAB, 0.1666666716f).x
t: RCP_e ____, PV10.x
12 x: ADD ____, PV11.z, 1.0f
y: SETGT_DX10 ____, 0.0f, PV11.z
z: MUL_e ____, R125.x, PS11
13 x: CNDE_INT R1.x, PV12.y, R127.z, PV12.x
y: CNDE_INT R1.y, R127.x, 0.0f, PV12.z
Chú ý rằng không có hướng dẫn phân nhánh. Đó là di chuyển có điều kiện tất cả các cách, khá nhiều chính xác như tôi đã viết chúng.
Phần cứng cần thiết cho di chuyển có điều kiện chỉ là một bộ so sánh nhị phân (5 cửa mỗi bit) và một loạt các dấu vết. Rất nhanh.
Một điều thú vị khác cần lưu ý là không có dải phân cách. Thay vào đó trình biên dịch sử dụng một đối ứng gần đúng và một lệnh nhân. Nó làm điều này cho các hoạt động sqrt cũng như rất nhiều thời gian. Bạn có thể kéo các thủ thuật tương tự trên một CPU với (ví dụ) các lệnh rcpps SSE và rsqrtps.
Bây giờ hoạt động ngược lại:
// HSL [0:1] to RGB [0:1]
vec4 convertHSLtoRGB(vec4 col)
{
const float onethird = 1.0/3.0;
const float twothird = 2.0/3.0;
const float rcpsixth = 6.0;
float hue = col.x;
float sat = col.y;
float lum = col.z;
vec3 xt = vec3(
rcpsixth * (hue - twothird),
0.0,
rcpsixth * (1.0 - hue)
);
if (hue < twothird) {
xt.r = 0.0;
xt.g = rcpsixth * (twothird - hue);
xt.b = rcpsixth * (hue - onethird);
}
if (hue < onethird) {
xt.r = rcpsixth * (onethird - hue);
xt.g = rcpsixth * hue;
xt.b = 0.0;
}
xt = min(xt, 1.0);
float sat2 = 2.0 * sat;
float satinv = 1.0 - sat;
float luminv = 1.0 - lum;
float lum2m1 = (2.0 * lum) - 1.0;
vec3 ct = (sat2 * xt) + satinv;
vec3 rgb;
if (lum >= 0.5)
rgb = (luminv * ct) + lum2m1;
else rgb = lum * ct;
return vec4(rgb, col.a);
}
(sửa 05/July/2013:. Tôi đã phạm sai lầm khi dịch chức năng này orignally Việc lắp ráp cũng đã được cập nhật).
đầu ra hội:
1 x: ADD ____, -R2.x, 1.0f
y: ADD ____, R2.x, (0xBF2AAAAB, -0.6666666865f).x
z: ADD R0.z, -R2.x, (0x3F2AAAAB, 0.6666666865f).y
w: ADD R0.w, R2.x, (0xBEAAAAAB, -0.3333333433f).z
2 x: SETGT_DX10 R0.x, (0x3F2AAAAB, 0.6666666865f).x, R2.x
y: MUL R0.y, PV2.x, (0x40C00000, 6.0f).y
z: MOV R1.z, 0.0f
w: MUL R1.w, PV2.y, (0x40C00000, 6.0f).y
3 x: MUL ____, R0.w, (0x40C00000, 6.0f).x
y: MUL ____, R0.z, (0x40C00000, 6.0f).x
z: ADD R0.z, -R2.x, (0x3EAAAAAB, 0.3333333433f).y
w: MOV ____, 0.0f
4 x: CNDE_INT R0.x, R0.x, R0.y, PV4.x
y: CNDE_INT R0.y, R0.x, R1.z, PV4.y
z: CNDE_INT R1.z, R0.x, R1.w, PV4.w
w: SETGT_DX10 R1.w, (0x3EAAAAAB, 0.3333333433f).x, R2.x
5 x: MUL ____, R2.x, (0x40C00000, 6.0f).x
y: MUL ____, R0.z, (0x40C00000, 6.0f).x
z: ADD R0.z, -R2.y, 1.0f
w: MOV ____, 0.0f
6 x: CNDE_INT R127.x, R1.w, R0.x, PV6.w
y: CNDE_INT R127.y, R1.w, R0.y, PV6.x
z: CNDE_INT R127.z, R1.w, R1.z, PV6.y
w: ADD R1.w, -R2.z, 1.0f
7 x: MULADD R0.x, R2.z, (0x40000000, 2.0f).x, -1.0f
y: MIN*2 ____, PV7.x, 1.0f
z: MIN*2 ____, PV7.y, 1.0f
w: MIN*2 ____, PV7.z, 1.0f
8 x: MULADD R1.x, PV8.z, R2.y, R0.z
y: MULADD R127.y, PV8.w, R2.y, R0.z
z: SETGE_DX10 R1.z, R2.z, 0.5
w: MULADD R0.w, PV8.y, R2.y, R0.z
9 x: MULADD R0.x, R1.w, PV9.x, R0.x
y: MULADD R0.y, R1.w, PV9.y, R0.x
z: MUL R0.z, R2.z, PV9.y
w: MULADD R1.w, R1.w, PV9.w, R0.x
10 x: MUL ____, R2.z, R0.w
y: MUL ____, R2.z, R1.x
w: MOV R2.w, R2.w
11 x: CNDE_INT R2.x, R1.z, R0.z, R0.y
y: CNDE_INT R2.y, R1.z, PV11.y, R0.x
z: CNDE_INT R2.z, R1.z, PV11.x, R1.w
Một lần nữa không có chi nhánh. Yum!
Câu trả lời hay, tuy nhiên tôi vẫn không chắc cách tương tự "tương tự" liên quan đến sửa đổi màu sắc. – ronag
Tôi đã thêm làm rõ cho vấn đề màu sắc. – Virne