저는 이 프레젠테이션 의 예를 가지고 놀았습니다 (슬라이드 41).
내가 아는 한 알파 블렌딩을 수행합니다.
MOVQ mm0, alpha//4 16-b zero-padding α
MOVD mm1, A //move 4 pixels of image A
MOVD mm2, B //move 4 pixels of image B
PXOR mm3 mm3 //clear mm3 to all zeroes
//unpack 4 pixels to 4 words
PUNPCKLBW mm1, mm3 // Because B -A could be
PUNPCKLBW mm2, mm3 // negative, need 16 bits
PSUBW mm1, mm2 //(B-A)
PMULHW mm1, mm0 //(B-A)*fade/256
PADDW mm1, mm2 //(B-A)*fade + B
//pack four words back to four bytes
PACKUSWB mm1, mm3
어셈블러를 사용하여 c로 다시 작성하고 싶습니다.
지금은 다음과 같습니다.
void fade_mmx(SDL_Surface* im1,SDL_Surface* im2,Uint8 alpha, SDL_Surface* imOut)
{
int pixelsCount = imOut->w * im1->h;
Uint32 *A = (Uint32*) im1->pixels;
Uint32 *B = (Uint32*) im2->pixels;
Uint32 *out = (Uint32*) imOut->pixels;
Uint32 *end = out + pixelsCount;
__asm__ __volatile__ (
"\n\t movd (%0), %%mm0"
"\n\t movd (%1), %%mm1"
"\n\t movd (%2), %%mm2"
"\n\t pxor %%mm3, %%mm3"
"\n\t punpcklbw %%mm3, %%mm1"
"\n\t punpcklbw %%mm3, %%mm2"
"\n\t psubw %%mm2, %%mm1"
"\n\t pmulhw %%mm0, %%mm1"
"\n\t paddw %%mm2, %%mm1"
"\n\t packuswb %%mm3, %%mm1"
: : "r" (alpha), "r" (A), "r" (B), "r" (out), "r" (end)
);
__asm__("emms" : : );
}
컴파일 할 때 Error: (%dl) is not a valid base/index expression
어셈블러의 첫 번째 줄에 관한 메시지가 표시 됩니다. 나는 때문에 용의자 alpha
입니다 Uint8
, 내가 캐스팅 시도하지만 내가 세그먼트 오류를 얻을. 예에서 그들은 4 16-b zero-padding α
나에게 명확하지 않은 것에 대해 이야기하고 있습니다.
MM reg에 복사하기 전에 alpha
스칼라 곱하기를 사용하여 64 비트로 브로드 캐스트 할 수 있습니다 0x0001000100010001ULL
. 또 다른 옵션은에서 8 비트 정수를 32 비트로 0 확장 movd
한 다음 pshufw
복제하는 것입니다.
당신의 asm에도 다양한 안전 문제가있었습니다.
#include <SDL/SDL.h>
#include <stdint.h>
void fade_mmx(SDL_Surface* im1,SDL_Surface* im2,Uint8 alpha, SDL_Surface* imOut)
{
int pixelsCount = imOut->w * im1->h;
Uint32 *A = (Uint32*) im1->pixels;
Uint32 *B = (Uint32*) im2->pixels;
Uint32 *out = (Uint32*) imOut->pixels;
Uint32 *end = out + pixelsCount;
Uint64 alphas = (Uint64)alpha * 0x0001000100010001ULL;
__asm__ __volatile__ (
"\n\t movd %0, %%mm0"
"\n\t movd %1, %%mm1"
"\n\t movd %2, %%mm2"
"\n\t pxor %%mm3, %%mm3"
"\n\t punpcklbw %%mm3, %%mm1"
"\n\t punpcklbw %%mm3, %%mm2"
"\n\t psubw %%mm2, %%mm1"
"\n\t pmulhw %%mm0, %%mm1"
"\n\t paddw %%mm2, %%mm1"
"\n\t packuswb %%mm3, %%mm1"
: // you're probably going to want an "=m"(*something) memory output here
: "r" (alphas), "m" (*A), "m" (*B), "r" (out), "r" (end)
: "mm0", "mm1", "mm2", "mm3");
__asm__("emms" : : );
}
volatile
컴파일러가 "memory"
클로버에 의존하는 대신 모든 입력과 출력에 대해 알고 있는 경우 asm 문이 필요하지 않습니다 . (여기처럼 출력이없고 입력 피연산자 인 레지스터와 메모리 만 읽습니다.)
32 비트 코드의 경우, 교체 "r"(alphas)
와 함께 "m"(alphas)
. 또는 "rm"(alphas)
컴파일러가 선택하도록 사용 하십시오. (그러나 32 비트의 경우 컴파일러가 64 비트 곱셈 결과를 2 개의 32 비트 반으로 저장하도록 만드는 대신 pshufw를 사용하는 것이 더 낫습니다. 그런 다음 movq로 다시로드 할 때 저장 전달 지연이 발생합니다. Intrinsics는 결정을 내릴 수 있습니다. _mm_set1_epi8(alpha)
루프 밖에서 한 번 수행 하는 컴파일러 ).
또한 필요한 clobber 목록을 추가하고 역 참조하는 포인터를 포함하는 레지스터 피연산자를 역 참조하는 메모리를 참조하는 메모리 피연산자로 대체하여 gcc가 액세스하는 메모리에 대해 추론 할 수 있도록했습니다.
이러한 문제를 해결하지 않으면 gcc가 불행해질 것이며 코드의 동작이 정의되지 않고 신비스럽고 디버깅하기 어려운 방식으로 실패 할 수 있습니다. 수행중인 작업을 정확히 이해하지 않는 한 인라인 어셈블리를 사용하지 마십시오. 더 안전하고 잠재적으로 더 효율적인 대안으로 내장 함수를 사용하는 것을 고려하십시오. ( https://gcc.gnu.org/wiki/DontUseInlineAsm ).
__m128i
벡터가있는 SSE2를 사용하면 pack
0으로 패킹 하여 처리량의 절반을 낭비하는 2 개 또는 1 개가 아니라 한 번에 4 픽셀을 쉽게 처리 할 수 있습니다. (이에 대한 설정 punpckhbw
을 보완하는 punpcklbw
데 사용 ). MMX는 너무 구식이어서 최신 CPU는 동일한 128 비트 SSE2 XMM 명령어보다 일부 명령어의 MMX 버전에 대한 처리량이 낮습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다