C++ DX11 Blur for your adapter

Пользователь
Пользователь
Статус
Оффлайн
Регистрация
3 Янв 2020
Сообщения
148
Реакции
158
hay guys just been working on my blur for my project decided share this is not fully completed / finalized for my needs but everything you guys need
here a example image you can get the blur work with your menu stuff to but comes down to timing and such when you do the blur atm tho i have no lock with that haha

blur.png


Код:
Expand Collapse Copy
        fullscreen_vs = static_cast<ID3D11VertexShader*>(create_vertex_shader(hls::fullscreen_vs_code));
        if (!fullscreen_vs) {
            REN_DBG("Failed to create fullscreen vertex shader");
        }

        downsample_ps = static_cast<ID3D11PixelShader*>(create_fragment_shader(hls::downsample_blur_ps_code));
        if (!downsample_ps) {
            REN_DBG("Failed to create enhanced downsample shader");
        }


        // Create blur shaders
        blur_horizontal_ps = static_cast<ID3D11PixelShader*>(create_fragment_shader(hls::blur_horizontal_ps_code));
        if (!blur_horizontal_ps) {
            REN_DBG("Failed to create horizontal blur shader");
        }

        blur_vertical_ps = static_cast<ID3D11PixelShader*>(create_fragment_shader(hls::blur_vertical_ps_code));
        if (!blur_vertical_ps) {
            REN_DBG("Failed to create vertical blur shader");
        }

        // Create blur parameters constant buffer
        {
            D3D11_BUFFER_DESC desc = {};
            desc.ByteWidth = sizeof(float) * 4; // texel_size.xy, blur_strength, pad
            desc.Usage = D3D11_USAGE_DYNAMIC;
            desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
            desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
            if (FAILED(device->CreateBuffer(&desc, nullptr, &blur_params_cb))) {
                REN_DBG("Failed to create blur params constant buffer");
            }
        }




 void adapter_dx11::create_blur_buffers(UINT width, UINT height) {
        // If already created and matching, nothing to do
        if (blur_temp_tex && blur_final_tex && blur_width == width && blur_height == height)
            return;

        // Release only blur-specific resources (not downsample buffers)
        cleanup_blur_resources();

        blur_width = width;
        blur_height = height;

        if (!device) {
            REN_DBG("create_blur_buffers: device is null");
            return;
        }

        D3D11_TEXTURE2D_DESC texDesc = {};
        texDesc.Width = width;
        texDesc.Height = height;
        texDesc.MipLevels = 1;
        texDesc.ArraySize = 1;
        texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        texDesc.SampleDesc.Count = 1;
        texDesc.Usage = D3D11_USAGE_DEFAULT;
        texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;

        HRESULT hr = S_OK;

        hr = device->CreateTexture2D(&texDesc, nullptr, &blur_temp_tex);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateTexture2D(blur_temp) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        hr = device->CreateRenderTargetView(blur_temp_tex, nullptr, &blur_temp_rtv);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateRenderTargetView(blur_temp) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        hr = device->CreateShaderResourceView(blur_temp_tex, nullptr, &blur_temp_srv);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateShaderResourceView(blur_temp) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        hr = device->CreateTexture2D(&texDesc, nullptr, &blur_final_tex);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateTexture2D(blur_final) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        hr = device->CreateRenderTargetView(blur_final_tex, nullptr, &blur_final_rtv);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateRenderTargetView(blur_final) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        hr = device->CreateShaderResourceView(blur_final_tex, nullptr, &blur_final_srv);
        if (FAILED(hr)) {
            REN_DBG("create_blur_buffers: CreateShaderResourceView(blur_final) failed hr=0x%08X");
            cleanup_blur_resources();
            return;
        }

        REN_DBG("create_blur_buffers: success %ux%u");
    }

    void adapter_dx11::cleanup_blur_resources() {
        safe_release(blur_temp_tex);
        safe_release(blur_temp_rtv);
        safe_release(blur_temp_srv);
        safe_release(blur_final_tex);
        safe_release(blur_final_rtv);
        safe_release(blur_final_srv);
    }

    // Return AddRef'd SRV; caller must Release()
    void* adapter_dx11::get_blurred_back_buffer() {
        if (!blur_final_srv) {
            REN_DBG("get_blurred_back_buffer: blur_final_srv is NULL");
            return nullptr;
        }
        blur_final_srv->AddRef();
        return static_cast<void*>(blur_final_srv);
    }

    void adapter_dx11::apply_blur_effect(ID3D11ShaderResourceView* input_srv, float blur_strength) {
        // Ensure we have resources
        if (!input_srv || !blur_temp_rtv || !blur_final_rtv || !blur_params_cb || !blur_temp_srv || !blur_final_srv) {
            return;
        }

        // Use cached downsample size for viewport/texel size if available; fall back to blur_width/height
        UINT vw = ds_width_cached ? ds_width_cached : blur_width;
        UINT vh = ds_height_cached ? ds_height_cached : blur_height;
        if (!vw || !vh) return;

        // Set viewport for blur operations
        D3D11_VIEWPORT vp = {};
        vp.TopLeftX = 0;
        vp.TopLeftY = 0;
        vp.Width = static_cast<float>(vw);
        vp.Height = static_cast<float>(vh);
        vp.MinDepth = 0.0f;
        vp.MaxDepth = 1.0f;
        ctx->RSSetViewports(1, &vp);

        // We'll do a single horizontal pass then vertical pass per iteration.
        // Update constant buffer for texel size and strength
        auto set_blur_cb = [&](float texel_x, float texel_y, float strength, bool flip) {
            D3D11_MAPPED_SUBRESOURCE mapped;
            if (SUCCEEDED(ctx->Map(blur_params_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) {
                float* params = reinterpret_cast<float*>(mapped.pData);
                params[0] = texel_x;
                params[1] = texel_y;
                params[2] = strength;
                *(bool*)(&params[3]) = flip;
                ctx->Unmap(blur_params_cb, 0);
            }
        };

        ctx->VSSetShader(fullscreen_vs, nullptr, 0);
        ctx->PSSetSamplers(0, 1, &linear_sampler);
        ctx->PSSetConstantBuffers(2, 1, &blur_params_cb);

        // PASS A: Horizontal (input_srv -> blur_temp)
        // Ensure input_srv is not the same resource bound as the RTV target (it isn't because blur_temp_rtv writes to blur_temp_tex).
        set_blur_cb(1.0f / static_cast<float>(vw), 0.0f, blur_strength, false);
        // Unbind any SRV that might be bound to the same texture as the RTV we will write to
        ID3D11ShaderResourceView* null_srvs[1] = { nullptr };
        ctx->PSSetShaderResources(0, 1, null_srvs);

        ctx->OMSetRenderTargets(1, &blur_temp_rtv, nullptr);
        ctx->PSSetShader(blur_horizontal_ps, nullptr, 0);
        ctx->PSSetShaderResources(0, 1, &input_srv);
        ctx->Draw(3, 0);

        // Unbind input before next pass
        ctx->PSSetShaderResources(0, 1, null_srvs);

        // PASS B: Vertical (blur_temp -> blur_final)
        set_blur_cb(0.0f, 1.0f / static_cast<float>(vh), blur_strength, false);
        ctx->OMSetRenderTargets(1, &blur_final_rtv, nullptr);
        ctx->PSSetShader(blur_vertical_ps, nullptr, 0);
        ctx->PSSetShaderResources(0, 1, &blur_temp_srv);
        ctx->Draw(3, 0);

        // Unbind temp srv
        ctx->PSSetShaderResources(0, 1, null_srvs);
    }

    void adapter_dx11::update_back_buffer(bool only_downsampled) {
        REN_DBG("dx11: updating back buffer with blur");

        if (!this->swap_chain) {
            REN_DBG("ERROR: No swap chain");
            return;
        }

        // Declare variables at the beginning to avoid goto issues
        ID3D11RenderTargetView* original_rtv = nullptr;
        ID3D11DepthStencilView* original_dsv = nullptr;
        ID3D11Texture2D* back_buffer = nullptr;
        ID3D11ShaderResourceView* back_buffer_srv = nullptr;
        UINT original_width = 0, original_height = 0;
        UINT ds_width = 0, ds_height = 0;
        UINT num_viewports = 1;
        D3D11_TEXTURE2D_DESC desc = {};
        D3D11_VIEWPORT vp = {};
        D3D11_VIEWPORT original_vp = {};

        // Store current render target state (IMPORTANT!)
        ctx->OMGetRenderTargets(1, &original_rtv, &original_dsv);
        // Store the original viewport
        ctx->RSGetViewports(&num_viewports, &original_vp);

        // Get the current back buffer from the swap chain
        if (FAILED(this->swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer))) {
            REN_DBG("Failed to get back buffer from swap chain");
            goto cleanup;
        }

        // Get back buffer dimensions
        back_buffer->GetDesc(&desc);
        original_width = desc.Width;
        original_height = desc.Height;
        ds_width = desc.Width / 4;
        ds_height = desc.Height / 4;

        REN_DBG("Processing blur");

        // Create/recreate blur buffers if they don't match the downsampled size
        if (blur_width != ds_width || blur_height != ds_height) {
            create_blur_buffers(ds_width, ds_height);
        }

        // Check if blur_final_srv was created
        if (!blur_final_srv) {
            REN_DBG("ERROR: blur_final_srv is NULL after create_blur_buffers!");
            goto cleanup;
        }

        // Create SRV from original back buffer
        if (FAILED(device->CreateShaderResourceView(back_buffer, nullptr, &back_buffer_srv))) {
            REN_DBG("Failed to create SRV for back buffer");
            goto cleanup;
        }

        // Create/recreate downsample buffer
        create_downsample_buffer(ds_width, ds_height);

        // STEP 1: Downsample with built-in blur
        ctx->OMSetRenderTargets(1, &back_buffer_ds_rtv, nullptr);

        vp.TopLeftX = 0;
        vp.TopLeftY = 0;
        vp.Width = static_cast<float>(ds_width);
        vp.Height = static_cast<float>(ds_height);
        vp.MinDepth = 0.0f;
        vp.MaxDepth = 1.0f;
        ctx->RSSetViewports(1, &vp);

        // Update blur parameters for downsampling
        D3D11_MAPPED_SUBRESOURCE mapped_resource;
        if (SUCCEEDED(ctx->Map(blur_params_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource))) {
            float* params = reinterpret_cast<float*>(mapped_resource.pData);
            params[0] = 1.0f / static_cast<float>(original_width);
            params[1] = 1.0f / static_cast<float>(original_height);
            params[2] = 1.0f;
            *(bool*)(&params[3]) = false;
            ctx->Unmap(blur_params_cb, 0);
        }

        ctx->VSSetShader(fullscreen_vs, nullptr, 0);
        ctx->PSSetShader(downsample_ps, nullptr, 0);
        ctx->PSSetConstantBuffers(2, 1, &blur_params_cb);
        ctx->PSSetShaderResources(0, 1, &back_buffer_srv);
        ctx->PSSetSamplers(0, 1, &linear_sampler);
        ctx->Draw(3, 0);

        // STEP 2: Apply multi-pass Gaussian blur
        apply_blur_effect(back_buffer_ds_srv, 1.5f);

        // Flush to ensure completion
        ctx->Flush();

        //REN_DBG("Blur generation complete");

    cleanup:
        // Unbind resources
        ID3D11ShaderResourceView* null_srv[1] = { nullptr };
        ctx->PSSetShaderResources(0, 1, null_srv);

        // Restore original render target
        ctx->OMSetRenderTargets(1, &original_rtv, original_dsv);
        if (original_rtv) original_rtv->Release();
        // Restore the original viewport
        ctx->RSSetViewports(1, &original_vp);

        if (original_dsv)
            original_dsv->Release();

        // Cleanup temporary resources
        if (back_buffer_srv)
            back_buffer_srv->Release();
        
        if (back_buffer)
            back_buffer->Release();
    }


HLS
c++:
Expand Collapse Copy
    const char* fullscreen_vs_code = R"(
struct VS_OUT {
    float4 pos : SV_POSITION;
    float2 uv  : TEXCOORD0;
};

VS_OUT main(uint id : SV_VertexID) {
    float2 uv = float2((id << 1) & 2, id & 2);
    float2 pos = uv * 2.0 - 1.0;

    VS_OUT o;
    o.pos = float4(pos, 0, 1);
    o.uv  = uv;
    return o;
}
)";

    const char* blur_horizontal_ps_code = R"(
Texture2D input_tex : register(t0);
SamplerState linear_sampler : register(s0);

cbuffer BlurParams : register(b2)
{
    float2 texel_size;
    float blur_strength;
    bool flip;
    float _pad;
}

static const float weights[9] = {
    0.13298, 0.23227, 0.1353, 0.0511, 0.01253, 0.00198, 0.00020, 0.00001, 0.0
};

float4 main(float4 pos : SV_POSITION, float2 uv : TEXCOORD0) : SV_Target
{
    float3 result = input_tex.Sample(linear_sampler, uv).rgb * weights[0];
    
    // Sample horizontally with variable blur strength
    for(int i = 1; i < 9; ++i)
    {
        float offset = (float)i * texel_size.x * blur_strength;
        if (flip)
            uv.y = 1.0 - uv.y;

        result += input_tex.Sample(linear_sampler, uv + float2(offset, 0.0)).rgb * weights[i];
        result += input_tex.Sample(linear_sampler, uv - float2(offset, 0.0)).rgb * weights[i];
    }
    
    return float4(result, 1.0);
}
)";

    const char* blur_vertical_ps_code = R"(
Texture2D input_tex : register(t0);
SamplerState linear_sampler : register(s0);

cbuffer BlurParams : register(b2)
{
    float2 texel_size;
    float blur_strength;
    bool flip;
    float _pad;
}

static const float weights[9] = {
    0.13298, 0.23227, 0.1353, 0.0511, 0.01253, 0.00198, 0.00020, 0.00001, 0.0
};

float4 main(float4 pos : SV_POSITION, float2 uv : TEXCOORD0) : SV_Target
{
    float3 result = input_tex.Sample(linear_sampler, uv).rgb * weights[0];
    
    // Sample vertically with variable blur strength
    for(int i = 1; i < 9; ++i)
    {
        float offset = (float)i * texel_size.y * blur_strength;
        if (flip)
            uv.y = 1.0 - uv.y;

        result += input_tex.Sample(linear_sampler, uv + float2(0.0, offset)).rgb * weights[i];
        result += input_tex.Sample(linear_sampler, uv - float2(0.0, offset)).rgb * weights[i];
    }
    
    return float4(result, 1.0);
}
)";

    const char* downsample_blur_ps_code = R"(
Texture2D input_tex : register(t0);
SamplerState linear_sampler : register(s0);

cbuffer BlurParams : register(b2)
{
    float2 texel_size;
    float blur_strength;
    bool flip;
    float _pad;
}

float4 main(float4 pos : SV_POSITION, float2 uv : TEXCOORD0) : SV_Target
{
    // 13-tap downsample with built-in blur
    float4 result = 0.0;

    if (flip)
        uv.y = 1.0 - uv.y;
    
    // Center sample
    result += input_tex.Sample(linear_sampler, uv) * 0.125;
    
    // 4-tap box filter
    float2 offset = texel_size;
    result += input_tex.Sample(linear_sampler, uv + float2(-offset.x, -offset.y)) * 0.125;
    result += input_tex.Sample(linear_sampler, uv + float2(offset.x, -offset.y)) * 0.125;
    result += input_tex.Sample(linear_sampler, uv + float2(-offset.x, offset.y)) * 0.125;
    result += input_tex.Sample(linear_sampler, uv + float2(offset.x, offset.y)) * 0.125;
    
    // Additional samples for smoother blur
    offset *= 0.5;
    result += input_tex.Sample(linear_sampler, uv + float2(-offset.x * 2, 0)) * 0.0625;
    result += input_tex.Sample(linear_sampler, uv + float2(offset.x * 2, 0)) * 0.0625;
    result += input_tex.Sample(linear_sampler, uv + float2(0, -offset.y * 2)) * 0.0625;
    result += input_tex.Sample(linear_sampler, uv + float2(0, offset.y * 2)) * 0.0625;
    
    return result;
}
)";
 
нууууууууууууу особо не кому не надо но ладно +rep
 
Назад
Сверху Снизу