Производительность Pixel Shader на xbox

У меня есть пиксельный шейдер (ниже), который я использую с XNA. На моем ноутбуке (дрянная видеокарта) он работает немного вяло, но хорошо. Я только что попробовал запустить его на Xbox, и это ужасно!

В игре нет ничего (это просто фрактальный рендерер), поэтому он должен быть пиксельным шейдером, вызывающим проблемы. Я также думаю, что это код PS, потому что я снизил количество итераций, и это нормально. Я также проверил, и дельта GC равна нулю.

Есть ли какие-либо функции HLSL, которые нет-нет на Xbox?? Должно быть, я что-то делаю не так, производительность не может быть такой плохой!

#include "FractalBase.fxh"

float ZPower;

float3 Colour;
float3 ColourScale;

float ComAbs(float2 Arg)
{
    return sqrt(Arg.x * Arg.x + Arg.y * Arg.y);
}

float2 ComPow(float2 Arg, float Power)
{
    float Mod = pow(Arg.x * Arg.x + Arg.y * Arg.y, Power / 2);
    float Ang = atan2(Arg.y, Arg.x) * Power;

    return float2(Mod * cos(Ang), Mod * sin(Ang));
}

float4 FractalPixelShader(float2 texCoord : TEXCOORD0, uniform float Iterations) : COLOR0
{
    float2 c = texCoord.xy;
    float2 z = 0;

    float i;

    float oldBailoutTest = 0;
    float bailoutTest = 0;

    for(i = 0; i < Iterations; i++)
    {
        z = ComPow(z, ZPower) + c;

        bailoutTest = z.x * z.x + z.y * z.y;

        if(bailoutTest >= ZPower * ZPower)
        {
            break;
        }

        oldBailoutTest = bailoutTest;
    }

    float normalisedIterations = i / Iterations;
    float factor = (bailoutTest - oldBailoutTest) / (ZPower * ZPower - oldBailoutTest);

    float4 Result = normalisedIterations + (1 / factor / Iterations);

    Result = (i >= Iterations - 1) ? float4(0.0, 0.0, 0.0, 1.0) : float4(Result.x * Colour.r * ColourScale.x, Result.y * Colour.g * ColourScale.y, Result.z * Colour.b * ColourScale.z, 1);

    return Result;
}

technique Technique1
{
    pass
    {
        VertexShader = compile vs_3_0 SpriteVertexShader();
        PixelShader = compile ps_3_0 FractalPixelShader(128);
    }
}

Ниже FractalBase.fxh:

float4x4 MatrixTransform : register(vs, c0);

float2 Pan;
float Zoom;
float Aspect;

void SpriteVertexShader(inout float4 Colour    : COLOR0,
                        inout float2 texCoord : TEXCOORD0,
                        inout float4 position : SV_Position)
{
    position = mul(position, MatrixTransform);

    // Convert the position into from screen space into complex coordinates
    texCoord = (position) * Zoom * float2(1, Aspect) - float2(Pan.x, -Pan.y);
}

РЕДАКТИРОВАТЬ Я попытался удалить условное выражение с помощью большого количества lerps, однако когда я это сделал, я получил множество артефактов (а не тот, который " принадлежит музею"!). Я изменил ситуацию и исправил несколько логических ошибок, однако ключом было умножить результат GreaterThan на 1 + epsilon, чтобы учесть ошибки округления, составляющие 0,9999 = 0 (целое число). Смотрите фиксированный код ниже:

#include "FractalBase.fxh"

float ZPower;

float3 Colour;
float3 ColourScale;

float ComAbs(float2 Arg)
{
    return sqrt(Arg.x * Arg.x + Arg.y * Arg.y);
}

float2 ComPow(float2 Arg, float Power)
{
    float Mod = pow(Arg.x * Arg.x + Arg.y * Arg.y, Power / 2);
    float Ang = atan2(Arg.y, Arg.x) * Power;

    return float2(Mod * cos(Ang), Mod * sin(Ang));
}

float GreaterThan(float x, float y)
{
    return ((x - y) / (2 * abs(x - y)) + 0.5) * 1.001;
}

float4 FractalPixelShader(float2 texCoord : TEXCOORD0, uniform float Iterations) : COLOR0
{
    float2 c = texCoord.xy;
    float2 z = 0;

    int i;

    float oldBailoutTest = 0;
    float bailoutTest = 0;

    int KeepGoing = 1;

    int DoneIterations = Iterations;

    int Bailout = 0;

    for(i = 0; i < Iterations; i++)
    {
        z = lerp(z, ComPow(z, ZPower) + c, KeepGoing);

        bailoutTest = lerp(bailoutTest, z.x * z.x + z.y * z.y, KeepGoing);

        Bailout = lerp(Bailout, GreaterThan(bailoutTest, ZPower * ZPower), -abs(Bailout) + 1);

        KeepGoing = lerp(KeepGoing, 0.0, Bailout);
        DoneIterations = lerp(DoneIterations, min(i, DoneIterations), Bailout);

        oldBailoutTest = lerp(oldBailoutTest, bailoutTest, KeepGoing);
    }

    float normalisedIterations = DoneIterations / Iterations;
    float factor = (bailoutTest - oldBailoutTest) / (ZPower * ZPower - oldBailoutTest);

    float4 Result = normalisedIterations + (1 / factor / Iterations);

    Result = (DoneIterations >= Iterations - 1) ? float4(0.0, 0.0, 0.0, 1.0) : float4(Result.x * Colour.r * ColourScale.x, Result.y * Colour.g * ColourScale.y, Result.z * Colour.b * ColourScale.z, 1);

    return Result;
}

technique Technique1
{
    pass
    {
        VertexShader = compile vs_3_0 SpriteVertexShader();
        PixelShader = compile ps_3_0 FractalPixelShader(128);
    }
}

1 ответ

Решение

У xbox довольно большой размер блока, поэтому ветвление на xbox не всегда так велико. Кроме того, компилятор не всегда наиболее эффективен для создания динамических веток, которые, похоже, использует ваш код.

Посмотрите на атрибут ветви: http://msdn.microsoft.com/en-us/library/bb313972%28v=xnagamestudio.31%29.aspx

Кроме того, если вы перенесете раннюю помощь, станет ли компьютер более похожим на Xbox?

Имейте в виду, что современные графические карты на самом деле сейчас немного быстрее, чем ксеноновые.

Другие вопросы по тегам