- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在尝试找出使用 AMD64 SIMD 指令来实现与大量 u8 值一起使用的 lerp 的最佳方法,但我似乎无法在不需要所有 SIMD 扩展的情况下找出正确的指令。
我现在使用的公式是
u8* a;
u8* b;
u8* result;
size_t count;
u16 total;
u16 progress;
u32 invertedProgress = total - progress;
for(size_t i = 0; i < count; i++){
result[i] = (u8)((b[i] * progress + a[i] * invertedProgress) / total);
}
我认为它看起来像这样:
u8* a;
u8* b;
u8* result;
size_t count;
u16 total;
u16 progress;
__m128i mmxZero;
__m128i mmxProgress;
__m128i mmxInvertedProgress;
__m128i mmxProductA;
__m128i mmxProductB;
mmxZero = _mm_xor_ps(zero, zero); // Is there a clear?
mmxProgress = Fill with progress;
mmxTotal = Fill with total;
mmxInvertedProgress = mmxTotal;
mmxInvertedProgress = _mm_unpacklo_epi8(mmxInvertedProgres, mmxZero);
mmxInvertedProgress = _mm_sub_epi8(mmxTotal, progress);
for(size_t i = 0; i < count; i += 8){
mmxProductA = load A;
// u8 -> u16
mmxProductA = _mm_unpacklo_epi8(mmxProductA, mmxZero);
mmxProductB = load B;
// u8 -> u16
mmxProductB = _mm_unpacklo_epi8(mmxProductB, mmxZero);
// a * (total - progress)
mmxProductA = _mm_mullo_epi16(mmxProductA, mmxInvertedProgress);
// b * progress
mmxProductB = _mm_mullo_epi16(mmxProductB, mmxProgress);
// a * (total - progress) + b * progress
mmxProductA = _mm_add_epi16(mmxProductA, mmxProductB);
// (a * (total - progress) + b * progress) / total
mmxProductA = _mm_div_epi16(mmxProductA, mmxTotal);
mmxProductA = saturated u16 -> u8;
store result = maxProductA;
}
这里有一些我似乎无法挖掘的东西 in the guide ,主要与加载和存储值有关。
我知道有一些更新的指令可以同时执行更多的操作,这个初始实现应该适用于旧芯片。
对于这个例子,我也忽略了对齐和缓冲区溢出的可能性,我认为这有点超出了问题的范围。
最佳答案
好问题。正如您所发现的,SSE 没有整数除法指令,并且(与 ARM NEON 不同)它没有字节乘法或 FMA。
这是我通常做的。下面的代码将向量拆分为偶数/奇数字节,使用 16 位乘法指令分别缩放,然后将它们合并回字节。
// Linear interpolation is based on the following formula: x*(1-s) + y*s which can equivalently be written as x + s(y-x).
class LerpBytes
{
// Multipliers are fixed point numbers in 16-bit lanes of these vectors, in 1.8 format
__m128i mulX, mulY;
public:
LerpBytes( uint16_t progress, uint16_t total )
{
// The source and result are bytes.
// Multipliers only need 1.8 fixed point format, anything above that is wasteful.
assert( total > 0 );
assert( progress >= 0 );
assert( progress <= total );
const uint32_t fp = (uint32_t)progress * 0x100 / total;
mulY = _mm_set1_epi16( (short)fp );
mulX = _mm_set1_epi16( (short)( 0x100 - fp ) );
}
__m128i lerp( __m128i x, __m128i y ) const
{
const __m128i lowMask = _mm_set1_epi16( 0xFF );
// Split both vectors into even/odd bytes in 16-bit lanes
__m128i lowX = _mm_and_si128( x, lowMask );
__m128i highX = _mm_srli_epi16( x, 8 );
__m128i lowY = _mm_and_si128( y, lowMask );
__m128i highY = _mm_srli_epi16( y, 8 );
// That multiply instruction has relatively high latency, 3-5 cycles.
// We're lucky to have 4 vectors to handle.
lowX = _mm_mullo_epi16( lowX, mulX );
lowY = _mm_mullo_epi16( lowY, mulY );
highX = _mm_mullo_epi16( highX, mulX );
highY = _mm_mullo_epi16( highY, mulY );
// Add the products
__m128i low = _mm_adds_epu16( lowX, lowY );
__m128i high = _mm_adds_epu16( highX, highY );
// Pack them back into bytes.
// The multiplier was 1.8 fixed point, trimming the lowest byte off both vectors.
low = _mm_srli_epi16( low, 8 );
high = _mm_andnot_si128( lowMask, high );
return _mm_or_si128( low, high );
}
};
static void print( const char* what, __m128i v )
{
printf( "%s:\t", what );
alignas( 16 ) std::array<uint8_t, 16> arr;
_mm_store_si128( ( __m128i * )arr.data(), v );
for( uint8_t b : arr )
printf( " %02X", (int)b );
printf( "\n" );
}
int main()
{
const __m128i x = _mm_setr_epi32( 0x33221100, 0x77665544, 0xBBAA9988, 0xFFEEDDCC );
const __m128i y = _mm_setr_epi32( 0xCCDDEEFF, 0x8899AABB, 0x44556677, 0x00112233 );
LerpBytes test( 0, 1 );
print( "zero", test.lerp( x, y ) );
test = LerpBytes( 1, 1 );
print( "one", test.lerp( x, y ) );
test = LerpBytes( 1, 2 );
print( "half", test.lerp( x, y ) );
test = LerpBytes( 1, 3 );
print( "1/3", test.lerp( x, y ) );
test = LerpBytes( 1, 4 );
print( "1/4", test.lerp( x, y ) );
return 0;
}
关于x86-64 - 带有 SSE 的 8 位 LERP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64165250/
函数 lerp() 是编程语言中的常用函数: lerp(a, b, t) = a + t * (b - a). 现在对于很多情况,我有一个反函数: fraction(x, a, b) = (x - a
我需要在三个不同的范围之间进行插值, (1,1.3),(.72,1) , (1.4,1.9)->(1,1.05) 和 (2,3)->(1.05,1.1) 其中前两项是 x 值,后两项是 y 值,但函数
有没有一种优雅的方法可以使用整数进行线性插值? (为了平均微 Controller 中的 ADC 测量值,ADC 测量值是 12 位,微 Controller 可以很好地处理 32 位整数)。系数f在
有没有一种优雅的方法可以使用整数进行线性插值? (为了平均微 Controller 中的 ADC 测量值,ADC 测量值是 12 位,微 Controller 可以很好地处理 32 位整数)。系数f在
我正在尝试通过时间值减少浮点数,我正在使用 Unity 并停止时间 Time.timeScale = 0f;,因此无法使用 Time.deltaTime,因此在 while 循环中使用“Time.re
我必须使用 lerp 函数来插入两个图像。帖子 How to perform a linear interpolation between to images推荐此方法 dst[x][y].r = l
当我在我的游戏引擎中运行对象时,我一直遇到与计时器相关的问题。渐变几乎是正确的,当我将渐变应用于移动或旋转的物体时,它很好,除了每隔几秒钟它看起来好像物体在继续平稳移动之前快速闪烁到它之前的位置。 在
所以我决定在 pygame 中为我的矩形角色添加线性插值。几天前我看到了 lerp,我不确定我是否遗漏了什么。 问题是: 例如,当我向右移动时。速度插值以达到所需的最大速度 - (7) 或 (-7 为
我只想通过 lerp 实现 x 轴上的移动对象以获得平滑移动。 这是我需要的图片 我不知道如何对这段代码实现 lerp 以获得这些值之间的平滑移动,它现在可以工作但是它传送玩家并且这不是我想要实现的平
我想 lerp 旋转到 new Quaternion(0,0,0,0);但它似乎根本没有动画到所需的旋转......它只是停在它所在的地方...... 我试的是下面那三个 RectTransform
我想在一系列输入值(例如,A 和 B 之间)之间进行一般插值,并获得一系列输出值(例如,C 和 D 之间)。有时我想限制值(以便 B+10000 仍然输出 D),有时我不想。我该怎么做? 例如,给定输
我有一个带有 2d 对撞机的立方体游戏对象,当有人击中相机时应该向上 10 个单位,但很顺利,相机转到正确的位置但没有阻尼。 public Transform target; public float
目前这是我的脚本,用于将玩家移动到场景周围。我怎样才能让它顺利移动? void FixedUpdate() { bool running = Input.GetKey(KeyCode.Left
在学习了 std::lerp 之后,我尝试将它与强类型一起使用,但它失败了,因为它只适用于内置类型...... #include #include struct MyFloat{ float
我的逻辑在这里一定很不对劲。本质上,我有一个加载栏,当通过鼠标悬停激活时,它会增加覆盖 UI 面板的左侧位置以提供加载效果。这工作正常。 问题在于当 UI 面板在第二个 while 循环中未激活时,将
我想来回更改颜色的 alpha 值(透明度): private void Awake() { material = gameObject.GetComponent().material;
我正在使用 LibGDX 并尝试在两个 Vector3 之间穿插……但是,当我这样做时,它不是线性的,而是以指数方式缓和它。我不想要这个,我想要它是纯线性的! 这样我的模型就可以遵循一组 Vector
我正在尝试在协程中使用两个不同的 lerp 来扩大然后缩小一系列游戏对象。尽管这两个 while 循环在功能上是相同的,但对象会增长但不会缩小,而是保持增加的大小。 我已将初始和最终尺寸替换为硬编码值
我想知道如何根据 2 个对象之间的距离制作平滑的颜色插值。颜色应该从绿色到红色到绿色再到红色......远立方体 = 红色,近立方体 = 绿色。 我已经让一切正常,但唯一认为无效的是颜色不平滑。这就是
我是一个刚刚接触 pyCUDA 的休闲 Python 爱好者。我试图弄清楚如何使用 pyCUDA 实现线性插值(lerp)。 CUDA CG函数为:http://http.developer.nvid
我是一名优秀的程序员,十分优秀!