BradLarson / GPUImage

An open source iOS framework for GPU-based image and video processing
http://www.sunsetlakesoftware.com/2012/02/12/introducing-gpuimage-framework
BSD 3-Clause "New" or "Revised" License
20.23k stars 4.62k forks source link

Custom filter 32-bit architecture problem #1707

Open pegurov opened 10 years ago

pegurov commented 10 years ago

Hey Brad! I have a very weird issue, that I'm unable to fix on my own, I've been trying for days to figure out what is wrong.

The situation is following: One of our developers wrote a custom filter, as an extension of GPUImageFiler. The purpose of the filter is to change Hue Saturation and Luminance for different tones of an image. He is not an iOS developer.

So he wrote it, and I tried to use it. The problem is this: it works on 64-bit architecture (iPhone 5S and all of the simulators), but doesn't work on 32 bit. On 32-bit architecture it just returns a clear image. But the weirdest part of it all is that even if i just initialise the filter but don't use it (don't add any targets to it), but just change some of its parameters, other filters that I'm using start returning a clear image too.

Here is the link to the repository: https://bitbucket.org/pashagurov/filtersapp When you launch the app you can actually choose the filters swiping left and right at the bottom part of the app. So when you change parameters of tone curve filter, it works as expected, but when you swipe to custom filter and change something there, the image disappears, but that filter is not even added as a target anywhere.

Could you please help me to solve the issue? If you don't want to clone the repository, then i can just paste the code here, i just thought that giving a link to the repository would be cleaner.

pegurov commented 10 years ago

SaturationHueLuminanceFilter.h

#import <GPUImage.h>

@interface SaturationHueLuminanceFilter : GPUImageFilter
{
    GLfloat referenceTones[8]; // Blue and Aqua are included twice to manage edge cases
}

// Accept an array on 6 floats from -1.0 to 1.0 for Red, Yellow, Green, Aqua, Blue and Magenta respectively
@property(nonatomic) GLfloat* saturation;
@property(nonatomic) GLfloat* hue;
@property(nonatomic) GLfloat* luminance;

@end

SaturationHueLuminanceFilter.m

#import "SaturationHueLuminanceFilter.h"

NSString *const kSatuationHueLuminanceFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;

 const highp  vec3  kRGBToYPrime = vec3 (0.299, 0.587, 0.114);
 const highp  vec3  kRGBToI     = vec3 (0.595716, -0.274453, -0.321263);
 const highp  vec3  kRGBToQ     = vec3 (0.211456, -0.522591, 0.31135);
 const highp  vec3  kYIQToR   = vec3 (1.0, 0.9563, 0.6210);
 const highp  vec3  kYIQToG   = vec3 (1.0, -0.2721, -0.6474);
 const highp  vec3  kYIQToB   = vec3 (1.0, -1.1070, 1.7046);
 const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
 uniform mediump float referenceTones[8]; // it's actually const, but GLES 2.0 dosen't do const arrays

 const mediump float relevanceRange = 0.7;

 uniform lowp float saturationTones[8];
 uniform lowp float hueTones[8];
 uniform lowp float luminanceTones[8];

 void main()
 {
     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     lowp vec3 color = textureColor.rgb;

     highp float   YPrime  = dot (color, kRGBToYPrime); // convert to YIQ
     highp float   I      = dot (color, kRGBToI);
     highp float   Q      = dot (color, kRGBToQ);

     highp float   hue     = atan (Q, I); // calculate the hue and chroma
     highp float   chroma  = sqrt (I * I + Q * Q);

     mediump float luminanceAmount = 0.0;
     mediump float hueAmount = 0.0;
     mediump float saturationAmount = 0.0;

     lowp int toneNumber;
     mediump float normalizedRelevance;
     for (toneNumber=0;toneNumber<8;toneNumber++)
     {
         normalizedRelevance = clamp(1.0 - (abs(referenceTones[toneNumber] - hue)-0.2)/relevanceRange,0.0,1.0);
         luminanceAmount += normalizedRelevance*luminanceTones[toneNumber];
         saturationAmount += normalizedRelevance*saturationTones[toneNumber];
         hueAmount += normalizedRelevance*hueTones[toneNumber];
     }

     hue = hue + (-hueAmount*3.14); // apply hue adjustment

     Q = chroma * sin (hue); // back to YIQ
     I = chroma * cos (hue);

     highp vec3 yIQ = vec3 (YPrime, I, Q); // back to RGB
     color.r = dot (yIQ, kYIQToR);
     color.g = dot (yIQ, kYIQToG);
     color.b = dot (yIQ, kYIQToB);

     color = color + luminanceAmount*0.2; // apply luminance adjustment

     lowp float luminance = dot(color.rgb, luminanceWeighting); // apply saturation adjustment
     lowp vec3 greyscaleColor = vec3(luminance);
     color = mix(greyscaleColor, color, saturationAmount + 1.0);

     gl_FragColor = vec4(color.rgb, textureColor.a);
 }
);

@implementation SaturationHueLuminanceFilter

- (id) init;
{
    if (!(self = [super initWithFragmentShaderFromString:kSatuationHueLuminanceFragmentShaderString])) {
        return nil;
    }

    referenceTones[0] = 0.3326; // red
    referenceTones[1] = -0.7761; // yellow
    referenceTones[2] = -2.0574; // green
    referenceTones[3] = -2.8212; // aqua
    referenceTones[4] = 2.3777; // blue
    referenceTones[5] = 1.0964; // magenda
    referenceTones[6] = 3.5; // aqua again
    referenceTones[7] = -3.9; // blue again
    [self setFloatArray:referenceTones length:8 forUniform:@"referenceTones"];

    return self;
}

- (void) setFloat:(GLfloat*)array forUniform:(NSString*)uniformName
{
    array = (GLfloat*)realloc((void*)array, sizeof(GLfloat)*8);
    array[6] = array[3];
    array[7] = array[4];

    [self setFloatArray:array length:8 forUniform:uniformName];
}

- (void) setSaturation:(GLfloat *)saturationValues;
{
    _saturation = saturationValues;

    [self setFloat:saturationValues forUniform:@"saturationTones"];
}

- (void) setHue:(GLfloat *)hueValues;
{
    _hue = hueValues;

    [self setFloat:hueValues forUniform:@"hueTones"];
}

- (void) setLuminance:(GLfloat *)luminanceValues;
{
    _luminance = luminanceValues;

    [self setFloat:luminanceValues forUniform:@"luminanceTones"];
}

@end