Changeset 856

Show
Ignore:
Timestamp:
01/17/08 13:55:20 (16 years ago)
Author:
ppalmers
Message:

revert to old structure and implement SSE routines in there. This avoids memory accesses hence speeding things up

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp

    r849 r856  
    2525#include "AmdtpTransmitStreamProcessor.h" 
    2626#include "AmdtpPort.h" 
    27 #include "AmdtpBufferOps.h" 
    2827#include "../StreamProcessorManager.h" 
    2928#include "devicemanager.h" 
     
    3837#include <assert.h> 
    3938 
    40 #include "libutil/ByteSwap.h" 
     39#define AMDTP_FLOAT_MULTIPLIER 2147483392.0 
    4140 
    4241namespace Streaming 
     
    412411 
    413412    // encode audio data 
    414     // the data is stored in the original format (float, int). later on 
    415     // the complete buffer is converted to the correct type and labeled at once 
    416     muxAudioPorts((quadlet_t *)data, offset, nevents); 
    417  
    418     // label everything as MBLA audio since those are by far the most 
    419     // occurring. If we treat all as audio we can use efficient block 
    420     // processing. Afterwards we can correct wrong labels of other 
    421     // types. 
    422413    switch(m_StreamProcessorManager.getAudioDataType()) { 
    423414        case StreamProcessorManager::eADT_Int24: 
    424             convertFromInt24AndLabelAsMBLA(((quadlet_t *)data), nevents * m_dimension); 
     415            encodeAudioPortsInt24((quadlet_t *)data, offset, nevents); 
    425416            break; 
    426417        case StreamProcessorManager::eADT_Float: 
    427             convertFromFloatAndLabelAsMBLA(((quadlet_t *)data), nevents * m_dimension); 
     418            encodeAudioPortsFloat((quadlet_t *)data, offset, nevents); 
    428419            break; 
    429420    } 
     
    431422    // do midi ports 
    432423    encodeMidiPorts((quadlet_t *)data, offset, nevents); 
    433     // do endian conversion 
    434     byteSwapToBus(((quadlet_t *)data), nevents * m_dimension); 
    435424    return true; 
    436425} 
     
    442431    // no need to update the port cache when transmitting silence since 
    443432    // no dynamic values are used to do so. 
    444  
    445433    encodeAudioPortsSilence((quadlet_t *)data, offset, nevents); 
    446     convertFromInt24AndLabelAsMBLA(((quadlet_t *)data), nevents * m_dimension); 
    447434    encodeMidiPortsSilence((quadlet_t *)data, offset, nevents); 
    448     byteSwapToBus(((quadlet_t *)data), nevents * m_dimension); 
    449435    return true; 
    450436} 
     
    467453    for (i = 0; i < m_nb_audio_ports; i++) { 
    468454        target_event = (quadlet_t *)(data + i); 
    469         __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality 
    470455 
    471456        for (j = 0;j < nevents; j += 1) 
    472457        { 
    473             *target_event = 0
     458            *target_event = 0x00000040
    474459            target_event += m_dimension; 
    475             __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality 
    476460        } 
    477461    } 
     
    490474 */ 
    491475void 
    492 AmdtpTransmitStreamProcessor::muxAudioPorts(quadlet_t *data, 
    493                                             unsigned int offset, 
    494                                             unsigned int nevents) 
     476AmdtpTransmitStreamProcessor::encodeAudioPortsFloat(quadlet_t *data, 
     477                                                    unsigned int offset, 
     478                                                    unsigned int nevents) 
    495479{ 
    496480    unsigned int j; 
     
    498482    unsigned int i; 
    499483 
    500     quadlet_t * client_buffers[4]; 
    501     quadlet_t tmp_values[4] __attribute__ ((aligned (16))); 
     484    float * client_buffers[4]; 
     485    float tmp_values[4] __attribute__ ((aligned (16))); 
     486    uint32_t tmp_values_int[4] __attribute__ ((aligned (16))); 
    502487 
    503488    // prepare the scratch buffer 
    504489    assert(m_scratch_buffer_size_bytes > nevents * 4); 
    505490    memset(m_scratch_buffer, 0, nevents * 4); 
    506      
     491 
     492    const __m128i label = _mm_set_epi32 (0x40000000, 0x40000000, 0x40000000, 0x40000000); 
     493    const __m128 mult = _mm_set_ps(AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER); 
     494 
    507495    // this assumes that audio ports are sorted by position, 
    508496    // and that there are no gaps 
     
    514502            p = &(m_audio_ports.at(i+j)); 
    515503            if(p->buffer && p->enabled) { 
    516                 client_buffers[j] = (quadlet_t *) p->buffer; 
     504                client_buffers[j] = (float *) p->buffer; 
    517505                client_buffers[j] += offset; 
    518506            } else { 
    519507                // if a port is disabled or has no valid 
    520508                // buffer, use the scratch buffer (all zero's) 
    521                 client_buffers[j] = (quadlet_t *) m_scratch_buffer; 
     509                client_buffers[j] = (float *) m_scratch_buffer; 
    522510            } 
    523511        } 
     
    535523            tmp_values[3] = *(client_buffers[3]); 
    536524 
    537             // convert to packed int 
    538             __m128i v_vals = *((__m128i*)tmp_values); 
     525            // now do the SSE based conversion/labeling 
     526            __m128 v_float = *((__m128*)tmp_values); 
    539527            __m128i *target = (__m128i*)target_event; 
     528            __m128i v_int; 
     529 
     530            // multiply 
     531            v_float = _mm_mul_ps(v_float, mult); 
     532            // convert to signed integer 
     533            v_int = _mm_cvttps_epi32( v_float ); 
     534            // shift right 8 bits 
     535            v_int = _mm_srli_epi32( v_int, 8 ); 
     536            // label it 
     537            v_int = _mm_or_si128( v_int, label ); 
     538 
     539            // do endian conversion (SSE is always little endian) 
     540            // do first swap 
     541            v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); 
     542            // do second swap 
     543            v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); 
    540544 
    541545            // store the packed int 
    542546            // (target misalignment is assumed since we don't know the m_dimension) 
    543             _mm_storeu_si128 (target, v_vals); 
     547            _mm_storeu_si128 (target, v_int); 
    544548 
    545549            // increment the buffer pointers 
     
    555559 
    556560    // do remaining ports 
     561    // NOTE: these can be time-SSE'd 
    557562    for (; i < m_nb_audio_ports; i++) { 
    558563        struct _MBLA_port_cache &p = m_audio_ports.at(i); 
     
    561566 
    562567        if(p.buffer && p.enabled) { 
    563             quadlet_t *buffer = (quadlet_t *)(p.buffer); 
     568            float *buffer = (float *)(p.buffer); 
    564569            buffer += offset; 
    565570     
    566             for (j = 0;j < nevents; j += 1
     571            for (j = 0;j < nevents; j += 4
    567572            { 
    568                 *target_event = *buffer; 
    569                 buffer++; 
    570                 target_event += m_dimension; 
    571             } 
     573                // read the values 
     574                tmp_values[0] = *buffer; 
     575                buffer++; 
     576                tmp_values[1] = *buffer; 
     577                buffer++; 
     578                tmp_values[2] = *buffer; 
     579                buffer++; 
     580                tmp_values[3] = *buffer; 
     581                buffer++; 
     582     
     583                // now do the SSE based conversion/labeling 
     584                __m128 v_float = *((__m128*)tmp_values); 
     585                __m128i v_int; 
     586     
     587                // multiply 
     588                v_float = _mm_mul_ps(v_float, mult); 
     589                // convert to signed integer 
     590                v_int = _mm_cvttps_epi32( v_float ); 
     591                // shift right 8 bits 
     592                v_int = _mm_srli_epi32( v_int, 8 ); 
     593                // label it 
     594                v_int = _mm_or_si128( v_int, label ); 
     595     
     596                // do endian conversion (SSE is always little endian) 
     597                // do first swap 
     598                v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); 
     599                // do second swap 
     600                v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); 
     601 
     602                // store the packed int 
     603                _mm_store_si128 ((__m128i *)(&tmp_values_int), v_int); 
     604 
     605                // increment the buffer pointers 
     606                *target_event = tmp_values_int[0]; 
     607                target_event += m_dimension; 
     608                *target_event = tmp_values_int[1]; 
     609                target_event += m_dimension; 
     610                *target_event = tmp_values_int[2]; 
     611                target_event += m_dimension; 
     612                *target_event = tmp_values_int[3]; 
     613                target_event += m_dimension; 
     614            } 
     615 
     616            // do the remainder of the events 
     617            for(;j < nevents; j += 1) { 
     618                float *in = (float *)buffer; 
     619                float v = (*in) * AMDTP_FLOAT_MULTIPLIER; 
     620                unsigned int tmp = ((int) v); 
     621                tmp = ( tmp >> 8 ) | 0x40000000; 
     622                *target_event = htonl((quadlet_t)tmp); 
     623                buffer++; 
     624                target_event += m_dimension; 
     625            } 
     626 
    572627        } else { 
    573628            for (j = 0;j < nevents; j += 1) 
    574629            { 
    575                 *target_event = 0x0; 
    576                 target_event += m_dimension
    577             } 
    578        
    579    
    580 
    581  
    582 #else 
     630                // hardcoded byte swapped 
     631                *target_event = 0x00000040
     632                target_event += m_dimension; 
     633           
     634       
     635   
     636
     637 
    583638 
    584639/** 
     
    589644 */ 
    590645void 
    591 AmdtpTransmitStreamProcessor::muxAudioPorts(quadlet_t *data, 
    592                                             unsigned int offset, 
    593                                             unsigned int nevents) 
     646AmdtpTransmitStreamProcessor::encodeAudioPortsInt24(quadlet_t *data, 
     647                                                    unsigned int offset, 
     648                                                    unsigned int nevents) 
     649
     650    unsigned int j; 
     651    quadlet_t *target_event; 
     652    unsigned int i; 
     653 
     654    uint32_t *client_buffers[4]; 
     655    uint32_t tmp_values[4] __attribute__ ((aligned (16))); 
     656 
     657    // prepare the scratch buffer 
     658    assert(m_scratch_buffer_size_bytes > nevents * 4); 
     659    memset(m_scratch_buffer, 0, nevents * 4); 
     660 
     661    const __m128i label = _mm_set_epi32 (0x40000000, 0x40000000, 0x40000000, 0x40000000); 
     662    const __m128i mask  = _mm_set_epi32 (0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF); 
     663 
     664    // this assumes that audio ports are sorted by position, 
     665    // and that there are no gaps 
     666    for (i = 0; i < m_nb_audio_ports-4; i += 4) { 
     667        struct _MBLA_port_cache *p; 
     668 
     669        // get the port buffers 
     670        for (j=0; j<4; j++) { 
     671            p = &(m_audio_ports.at(i+j)); 
     672            if(p->buffer && p->enabled) { 
     673                client_buffers[j] = (uint32_t *) p->buffer; 
     674                client_buffers[j] += offset; 
     675            } else { 
     676                // if a port is disabled or has no valid 
     677                // buffer, use the scratch buffer (all zero's) 
     678                client_buffers[j] = (uint32_t *) m_scratch_buffer; 
     679            } 
     680        } 
     681 
     682        // the base event for this position 
     683        target_event = (quadlet_t *)(data + i); 
     684 
     685        // process the events 
     686        for (j=0;j < nevents; j += 1) 
     687        { 
     688            // read the values 
     689            tmp_values[0] = *(client_buffers[0]); 
     690            tmp_values[1] = *(client_buffers[1]); 
     691            tmp_values[2] = *(client_buffers[2]); 
     692            tmp_values[3] = *(client_buffers[3]); 
     693 
     694            // now do the SSE based conversion/labeling 
     695            __m128i *target = (__m128i*)target_event; 
     696            __m128i v_int = *((__m128i*)tmp_values);; 
     697 
     698            // mask 
     699            v_int = _mm_and_si128( v_int, mask ); 
     700            // label it 
     701            v_int = _mm_or_si128( v_int, label ); 
     702 
     703            // do endian conversion (SSE is always little endian) 
     704            // do first swap 
     705            v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); 
     706            // do second swap 
     707            v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); 
     708 
     709            // store the packed int 
     710            // (target misalignment is assumed since we don't know the m_dimension) 
     711            _mm_storeu_si128 (target, v_int); 
     712 
     713            // increment the buffer pointers 
     714            client_buffers[0]++; 
     715            client_buffers[1]++; 
     716            client_buffers[2]++;  
     717            client_buffers[3]++; 
     718 
     719            // go to next target event position 
     720            target_event += m_dimension; 
     721        } 
     722    } 
     723 
     724    // do remaining ports 
     725    // NOTE: these can be time-SSE'd 
     726    for (; i < m_nb_audio_ports; i++) { 
     727        struct _MBLA_port_cache &p = m_audio_ports.at(i); 
     728        target_event = (quadlet_t *)(data + i); 
     729        assert(nevents + offset <= p.buffer_size ); 
     730 
     731        if(p.buffer && p.enabled) { 
     732            uint32_t *buffer = (uint32_t *)(p.buffer); 
     733            buffer += offset; 
     734     
     735            for (j = 0;j < nevents; j += 4) 
     736            { 
     737                // read the values 
     738                tmp_values[0] = *buffer; 
     739                buffer++; 
     740                tmp_values[1] = *buffer; 
     741                buffer++; 
     742                tmp_values[2] = *buffer; 
     743                buffer++; 
     744                tmp_values[3] = *buffer; 
     745                buffer++; 
     746 
     747                // now do the SSE based conversion/labeling 
     748                __m128i v_int = *((__m128i*)tmp_values);; 
     749 
     750                // mask 
     751                v_int = _mm_and_si128( v_int, mask ); 
     752                // label it 
     753                v_int = _mm_or_si128( v_int, label ); 
     754 
     755                // do endian conversion (SSE is always little endian) 
     756                // do first swap 
     757                v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); 
     758                // do second swap 
     759                v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); 
     760 
     761                // store the packed int 
     762                _mm_store_si128 ((__m128i *)(&tmp_values), v_int); 
     763 
     764                // increment the buffer pointers 
     765                *target_event = tmp_values[0]; 
     766                target_event += m_dimension; 
     767                *target_event = tmp_values[1]; 
     768                target_event += m_dimension; 
     769                *target_event = tmp_values[2]; 
     770                target_event += m_dimension; 
     771                *target_event = tmp_values[3]; 
     772                target_event += m_dimension; 
     773            } 
     774 
     775            // do the remainder of the events 
     776            for(;j < nevents; j += 1) { 
     777                uint32_t in = (uint32_t)(*buffer); 
     778                *target_event = htonl((quadlet_t)((in & 0x00FFFFFF) | 0x40000000)); 
     779                buffer++; 
     780                target_event += m_dimension; 
     781            } 
     782 
     783        } else { 
     784            for (j = 0;j < nevents; j += 1) 
     785            { 
     786                // hardcoded byte swapped 
     787                *target_event = 0x00000040; 
     788                target_event += m_dimension; 
     789            } 
     790        } 
     791    } 
     792
     793 
     794#else 
     795 
     796/** 
     797 * @brief mux all audio ports to events 
     798 * @param data  
     799 * @param offset  
     800 * @param nevents  
     801 */ 
     802void 
     803AmdtpTransmitStreamProcessor::encodeAudioPortsInt24(quadlet_t *data, 
     804                                                    unsigned int offset, 
     805                                                    unsigned int nevents) 
    594806{ 
    595807    unsigned int j; 
     
    608820            for (j = 0;j < nevents; j += 1) 
    609821            { 
    610                 *target_event = *buffer; 
     822                uint32_t in = (uint32_t)(*buffer); 
     823                *target_event = htonl((quadlet_t)((in & 0x00FFFFFF) | 0x40000000)); 
    611824                buffer++; 
    612825                target_event += m_dimension; 
     
    615828            for (j = 0;j < nevents; j += 1) 
    616829            { 
    617                 *target_event = 0x0; 
     830                *target_event = 0x00000040; 
     831                target_event += m_dimension; 
     832            } 
     833        } 
     834    } 
     835
     836 
     837/** 
     838 * @brief mux all audio ports to events 
     839 * @param data  
     840 * @param offset  
     841 * @param nevents  
     842 */ 
     843void 
     844AmdtpTransmitStreamProcessor::encodeAudioPortsFloat(quadlet_t *data, 
     845                                                    unsigned int offset, 
     846                                                    unsigned int nevents) 
     847
     848    unsigned int j; 
     849    quadlet_t *target_event; 
     850    unsigned int i; 
     851 
     852    for (i = 0; i < m_nb_audio_ports; i++) { 
     853        struct _MBLA_port_cache &p = m_audio_ports.at(i); 
     854        target_event = (quadlet_t *)(data + i); 
     855        assert(nevents + offset <= p.buffer_size ); 
     856 
     857        if(p.buffer && p.enabled) { 
     858            quadlet_t *buffer = (quadlet_t *)(p.buffer); 
     859            buffer += offset; 
     860     
     861            for (j = 0;j < nevents; j += 1) 
     862            { 
     863                float *in = (float *)buffer; 
     864                float v = (*in) * AMDTP_FLOAT_MULTIPLIER; 
     865                unsigned int tmp = ((int) v); 
     866                tmp = ( tmp >> 8 ) | 0x40000000; 
     867                *target_event = htonl((quadlet_t)tmp); 
     868                buffer++; 
     869                target_event += m_dimension; 
     870            } 
     871        } else { 
     872            for (j = 0;j < nevents; j += 1) 
     873            { 
     874                // hardcoded little endian 
     875                *target_event = 0x00000040; 
    618876                target_event += m_dimension; 
    619877            } 
     
    642900        for (j = p.location;j < nevents; j += 8) { 
    643901            target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); 
    644             __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality 
    645             *target_event = IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA); 
     902            *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); 
    646903        } 
    647904    } 
     
    667924            uint32_t *buffer = (quadlet_t *)(p.buffer); 
    668925            buffer += offset; 
    669             __builtin_prefetch(buffer, 0, 0); // prefetch events for read, no temporal locality 
    670      
     926 
    671927            for (j = p.location;j < nevents; j += 8) { 
    672928                target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); 
    673                 __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality 
    674      
     929 
    675930                if ( *buffer & 0xFF000000 )   // we can send a byte 
    676931                { 
     
    678933                    tmpval = ((*buffer)<<16) & 0x00FF0000; 
    679934                    tmpval = IEC61883_AM824_SET_LABEL(tmpval, IEC61883_AM824_LABEL_MIDI_1X); 
    680                     *target_event = tmpval
     935                    *target_event = htonl(tmpval)
    681936 
    682937//                     debugOutput ( DEBUG_LEVEL_VERBOSE, "MIDI port %s, pos=%u, loc=%u, nevents=%u, dim=%d\n", 
     
    688943                    // or because this would exceed the maximum rate 
    689944                    // FIXME: this can be ifdef optimized since it's a constant 
    690                     *target_event = IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA); 
     945                    *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); 
    691946                } 
    692947                buffer+=8; 
     
    694949        } else { 
    695950            for (j = p.location;j < nevents; j += 8) { 
    696                 target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); 
     951                target_event = (quadlet_t *)(data + ((j * m_dimension) + p.position)); 
    697952                __builtin_prefetch(target_event, 1, 0); // prefetch events for write, no temporal locality 
    698                 *target_event = IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA); 
     953                *target_event = htonl(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); 
    699954            } 
    700955        } 
  • trunk/libffado/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.h

    r849 r856  
    120120    void encodeMidiPortsSilence(quadlet_t *data, unsigned int offset, unsigned int nevents); 
    121121    void encodeMidiPorts(quadlet_t *data, unsigned int offset, unsigned int nevents); 
    122     void muxAudioPorts(quadlet_t *data, unsigned int offset, unsigned int nevents); 
    123122 
    124123    unsigned int getFDF();