/**
 ******************************************************************************
 * 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"

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

xesl_pushConstants_begin(b0, space0)
  // 16 used by the vertex shader (GLSL push constant offsets are across
  // stages).
  xesl_block_offset_member(16, c0.x, xesl_int2, xe_bilinear_output_offset)
  xesl_block_offset_member(24, c0.z, xesl_float2, xe_bilinear_output_size_inv)
xesl_pushConstants_end

xesl_entry_outputs_begin
  xesl_entry_output_target(xesl_float4, xe_bilinear_color, 0)
xesl_entry_outputs_end_stageInputs_begin
xesl_entry_stageInputs_end_bindings_begin_pixel
  xesl_pushConstants_binding(buffer(0))
  xesl_entry_binding_next
  xesl_texture(xesl_texture2D, xe_bilinear_source, set=0, binding=0, t0, space0,
               texture(0))
  xesl_entry_binding_next
  xesl_samplerState(xe_bilinear_sampler, set=0, binding=1, s0, space0,
                    sampler(0))
xesl_entry_bindings_end_inputs_begin
  xesl_entry_input_fragCoord
xesl_entry_inputs_end_code_begin
  xesl_uint2 pixel_coord =
      xesl_uint2(xesl_int2(xesl_FragCoord.xy) -
                 xesl_pushConstant(xe_bilinear_output_offset));
  xesl_float4 bilinear_color;
  // + 0.5 so the origin is at the pixel center, and at 1:1 the original pixel
  // is taken.
  // Interpolating the four colors in the perceptual space because doing it in
  // linear space causes, in particular, bright text on a dark background to
  // become too thick, and aliasing of bright parts on top of dark areas to be
  // too apparent (4D5307E6 HUD, for example, mainly the edges of the
  // multiplayer score bars).
  bilinear_color.rgb =
      xesl_textureSampleLod2D_sep(
          xe_bilinear_source, xe_bilinear_sampler,
          (xesl_float2(pixel_coord) + 0.5) *
              xesl_pushConstant(xe_bilinear_output_size_inv),
          0.0).rgb;
  #if XE_GUEST_OUTPUT_DITHER
    // Clamping because on Vulkan, the surface may specify any format, including
    // floating-point.
    bilinear_color.rgb =
        xesl_saturate(bilinear_color.rgb + XeDitherOffset8bpc(pixel_coord));
  #endif  // XE_GUEST_OUTPUT_DITHER
  bilinear_color.a = 1.0;
  xesl_Output(xe_bilinear_color) = bilinear_color;
xesl_entry_code_end
