/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2022 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xesl.xesli"

#include "amd_language.xesli"

#if XE_GUEST_OUTPUT_DITHER
  #include "dither_8bpc.xesli"
#endif  // XE_GUEST_OUTPUT_DITHER

push_const_begin_xe(b0, space0)
  // 16 used by the vertex shader (GLSL push constant offsets are across
  // stages).
  block_offset_member_xe(16, c0.x, int2_xe, xe_fsr_rcas_output_offset)
  block_offset_member_xe(24, c0.z, float, xe_fsr_rcas_sharpness_post_setup)
push_const_end_xe

// FIXME(Triang3l): This approach doesn't work for MSL - the texture must be
// passed explicitly from the entry point's arguments to FsrRcasLoadF.

// Forward declaration because FsrRcasLoadF needs xe_fsr_rcas_source from the
// entry point bindings.
void FsrRcasF(out_param_xe(float, pixel_r), out_param_xe(float, pixel_g),
              out_param_xe(float, pixel_b), uint2_xe pixel_position,
              uint4_xe constants);

entry_outputs_begin_xe
  entry_out_target_xe(float4_xe, xe_fsr_rcas_color, 0)
entry_outputs_end_stage_inputs_begin_xe
entry_stage_inputs_end_bindings_begin_pixel_xe
  push_const_binding_xe(buffer(0))
  entry_binding_next_xe
  texture_xe(texture_2d_xe, xe_fsr_rcas_source, set=0, binding=0, t0, space0,
             texture(0))
entry_bindings_end_inputs_begin_xe
  entry_in_pixel_coord_xe
entry_inputs_end_code_begin_xe
{
  uint2_xe pixel_coord = uint2_xe(int2_xe(in_pixel_coord_xe.xy) -
                                  push_const_xe(xe_fsr_rcas_output_offset));
  float sharpness = push_const_xe(xe_fsr_rcas_sharpness_post_setup);
  // FsrRcasCon with smaller push constant usage.
  uint4_xe rcas_const =
      uint4_xe(float_bits_to_uint_xe(sharpness),
               pack_half_2x16_xe(float2_xe(sharpness, sharpness)), 0u, 0u);
  float4_xe rcas_color;
  FsrRcasF(rcas_color.r, rcas_color.g, rcas_color.b, pixel_coord, rcas_const);
  #if XE_GUEST_OUTPUT_DITHER
    // Clamping because on Vulkan, the surface may specify any format, including
    // floating-point.
    rcas_color.rgb =
        saturate_xe(rcas_color.rgb + XeDitherOffset8bpc(pixel_coord));
  #endif  // XE_GUEST_OUTPUT_DITHER
  // Force alpha to 1 to make sure the surface won't be translucent.
  rcas_color.a = 1.0f;
  out_xe(xe_fsr_rcas_color) = rcas_color;
}
entry_code_end_xe

#define A_GPU 1
#include "../../../../third_party/FidelityFX-FSR/ffx-fsr/ffx_a.h"
#define FSR_RCAS_F 1
float4_xe FsrRcasLoadF(int2_xe p) {
  return float4_xe(texel_fetch_2d_xe(xe_fsr_rcas_source, p, 0).rgb, 1.0f);
}
void FsrRcasInputF(inout_param_xe(float, r), inout_param_xe(float, g),
                   inout_param_xe(float, b)) {}
#include "../../../../third_party/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h"
