2012-06-29 9 views
1

argb로 rgba 버퍼를 변환하려고합니다. 다음 알고리즘을 개선 할 수있는 방법이 있습니까? 아니면 다른 빠른 방법으로 그러한 연산을 수행 할 수 있습니까? 알파 값은 argb 버퍼에서 한 번 중요하지 않으며 항상 0xFF로 끝나야 함을 고려하십시오. 나는 당신이 원하는 모든 스왑은 매 초마다 (짝수) 바이트 추측 할 수있는 코드가 버그 (단지 비효율적) 아니라고 가정Fast RGBA를 ARGB로 변환

int y, x, pixel; 

for (y = 0; y < height; y++) 
{ 
    for (x = 0; x < width; x++) 
    { 
    pixel = rgbaBuffer[y * width + x]; 
    argbBuffer[(height - y - 1) * width + x] = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff); 
    } 
} 

답변

4

나는 단지 스왑 기능에 초점을 맞출 것이다 :

typedef unsigned int Color32; 

inline Color32 Color32Reverse(Color32 x) 
{ 

    return 
    // Source is in format: 0xAARRGGBB 
     ((x & 0xFF000000) >> 24) | //______AA 
     ((x & 0x00FF0000) >> 8) | //____RR__ 
     ((x & 0x0000FF00) << 8) | //__GG____ 
     ((x & 0x000000FF) << 24); //BB______ 
    // Return value is in format: 0xBBGGRRAA 
} 
+0

질문은 ARGB에서 ARGB가 아니라 BGRA에서 RGBA에 관한 질문이었습니다. – Blaisorblade

+0

ARGB와 RGBA는 의미없는 단어이므로 철회해야 할 수도 있습니다. 이것은 여전히 ​​질문과 일치하지 않는 것 같습니다 (알파는 0xff로 설정되지 않습니다). https://en.wikipedia.org/wiki/RGBA_color_space#Representation – Blaisorblade

1

(물론 버퍼를 반전),하지 그것? 다음과 같이 내가 코드를 다시 작성 것이다

  • 인덱스 계산

에 경제적으로 예를 들어, 루프를 최적화 시프트를 방지하고 작업을

  • 마스킹 :

    그래서 당신은에 의해 약간의 최적화를 달성 할 수 :

    int y, x; 
    
    for (y = 0; y < height; y++) 
    { 
        unsigned char *pRGBA= (unsigned char *)(rgbaBuffer+y*width); 
        unsigned char *pARGB= (unsigned char *)(argbBuffer+(height-y-1)*width); 
        for (x = 4*(width-1); x>=0; x-=4) 
        { 
         pARGB[x ] = pRGBA[x+2]; 
         pARGB[x+1] = pRGBA[x+1]; 
         pARGB[x+2] = pRGBA[x ]; 
         pARGB[x+3] = 0xFF; 
        } 
    } 
    

    더 복잡한 것은 오지 계산은 외부 루프에서만 수행됩니다. 각각의 픽셀에 대해 rgbaBuffer와 argbBuffer에 4 가지 접근이 있지만 비트 연산과 indixes 계산을 피함으로써 오프셋보다 많은 것이라고 생각합니다. 한 번에 하나의 픽셀 (int)을 가져 오거나 저장하고 로컬 처리 (메모리 액세스에서 절약)를 수행하는 대신 코드에서와 같이 두 바이트를 스왑하고 알파를 로컬로 (예를 들어 인라인 어셈블리로 구성하여 모든 것이 레지스터 레벨에서 수행되는지 확인하십시오.) 정말 도움이되지 않습니다.

  • 1

    제공하신 코드는 rgba-> argb가 아니라 rgba-> rabg가 아닌 색상 요소를 뒤섞어서 매우 이상합니다.

    나는이 루틴을 정확하고 최적화 된 버전으로 만들었습니다.

    int pixel; 
    int size = width * height; 
    
    for (unsigned int * rgba_ptr = rgbaBuffer, * argb_ptr = argbBuffer + size - 1; argb_ptr >= argbBuffer; rgba_ptr++, argb_ptr--) 
    { 
        // *argb_ptr = *rgba_ptr >> 8 | 0xff000000; // - this version doesn't change endianess 
        *argb_ptr = __builtin_bswap32(*rgba_ptr) >> 8 | 0xff000000; // This does 
    } 
    

    가장 먼저 작성한 것은 셔플 표현식을 단순화하는 것입니다. XRGB가 RGBA >> 8인지 확실합니다. 또한 각 반복마다 배열 인덱스 계산을 제거하고 포인터를 루프 변수로 사용했습니다. 이 버전은 내 컴퓨터의 원본보다 약 2 배 빠릅니다.

    이 코드가 x86 CPU 용인 경우 SSE를 사용하여 셔플 링할 수도 있습니다.

    +0

    가장 빠른 구현 인 것처럼 보이지만 실제 이미지에는 빨간색 톤이 표시되므로 작업 중에 문제가 발생합니다. 나는 이것이 안드로이드 폰을위한 것이라고 언급 할 필요가있다. – PerracoLabs

    +2

    에헴, 당신은 abgr -> argb ie로 변환하려는 것 같습니다. rgba-> argb를 변환하고 한 번에 endianess를 변경하려고합니다. 나 맞아? –

    +0

    또한 이미지를 거꾸로 뒤집을 필요가 있습니까? –

    0

    사용 어셈블리, 인텔위한 다음과 같습니다.

    이 예에서는 Red와 Blue를 서로 바꿉니다.

    void* b = pixels; 
    UINT len = textureWidth*textureHeight; 
    
    __asm              
    { 
        mov ecx, len    // Set loop counter to pixels memory block size 
        mov ebx, b     // Set ebx to pixels pointer 
        label:      
         mov al,[ebx+0]   // Load Red to al 
         mov ah,[ebx+2]   // Load Blue to ah 
         mov [ebx+0],ah   // Swap Red 
         mov [ebx+2],al   // Swap Blue 
         add ebx,4    // Move by 4 bytes to next pixel 
         dec ecx     // Decrease loop counter 
         jnz label    // If not zero jump to label 
    } 
    
    +1

    낮은 수준의 최적화가 작동하지 않는 경우입니다. 나는 바이트 쉬프트를 가진 사소한 C++ 코드를 컴파일하려고 노력했으며 컴파일러는 모든 것을 'bswap edi'로 최적화했다. https://godbolt.org/g/hk2QiR을 참조하십시오. – Lordalcol