/*
 * Copyright © 2016 Red Hat.
 * Copyright © 2016 Bas Nieuwenhuizen
 *
 * based in part on anv driver which is:
 * Copyright © 2015 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 */
#ifndef RADV_ACO_SHADER_INFO_H
#define RADV_ACO_SHADER_INFO_H

/* this will convert from radv shader info to the ACO one. */

#include "ac_hw_stage.h"
#include "aco_shader_info.h"

#define ASSIGN_FIELD(x)    aco_info->x = radv->x
#define ASSIGN_FIELD_CP(x) memcpy(&aco_info->x, &radv->x, sizeof(radv->x))

static inline void radv_aco_convert_ps_epilog_key(struct aco_ps_epilog_info *aco_info,
                                                  const struct radv_ps_epilog_key *radv,
                                                  const struct radv_shader_args *radv_args);

static inline unsigned
radv_calculate_lds_size(const struct radv_shader_info *radv, const enum amd_gfx_level gfx_level)
{
   unsigned lds_size = 0;

   if (radv->is_ngg)
      lds_size = radv->nir_shared_size;
   else if (gfx_level >= GFX9 && radv->stage == MESA_SHADER_GEOMETRY)
      lds_size = radv->legacy_gs_info.lds_size;
   else if (radv->stage == MESA_SHADER_TESS_CTRL)
      lds_size = radv->tcs.lds_size; /* only used by stats */
   else
      lds_size = radv->nir_shared_size;

   return lds_size;
}

static inline void
radv_aco_convert_shader_info(struct aco_shader_info *aco_info, const struct radv_shader_info *radv,
                             const struct radv_shader_args *radv_args, const struct radv_device_cache_key *radv_key,
                             const enum amd_gfx_level gfx_level)
{
   bool ngg_wave_id_en = radv->ngg_wave_id_en;
   /* Separately compiled shader, where the next stage might use NGG streamout. */
   ngg_wave_id_en |= radv->is_ngg && radv->merged_shader_compiled_separately &&
                     radv->next_stage == MESA_SHADER_GEOMETRY && gfx_level >= GFX11;

   ASSIGN_FIELD(wave_size);
   ASSIGN_FIELD(workgroup_size);
   ASSIGN_FIELD(ps.has_epilog);
   ASSIGN_FIELD(merged_shader_compiled_separately);
   ASSIGN_FIELD(vs.tcs_in_out_eq);
   ASSIGN_FIELD(vs.has_prolog);
   ASSIGN_FIELD(ps.num_inputs);
   ASSIGN_FIELD(cs.uses_full_subgroups);
   ASSIGN_FIELD(descriptor_heap);
   aco_info->vs.any_tcs_inputs_via_lds = radv->vs.tcs_inputs_via_lds != 0;
   /* S2 must not be modified for correct hang recovery when NGG_WAVE_ID_EN=1. */
   aco_info->vs.preserve_s2 = ngg_wave_id_en && gfx_level < GFX12;
   aco_info->ps.spi_ps_input_ena = radv->ps.spi_ps_input_ena;
   aco_info->ps.spi_ps_input_addr = radv->ps.spi_ps_input_addr;
   aco_info->ps.has_prolog = false;
   aco_info->image_2d_view_of_3d = radv_key->image_2d_view_of_3d;
   aco_info->epilog_pc = radv_args->epilog_pc;
   aco_info->hw_stage = radv_select_hw_stage(radv, gfx_level);
   aco_info->next_stage_pc = radv_args->next_stage_pc;
   aco_info->schedule_ngg_pos_exports = gfx_level < GFX11 && radv->has_ngg_culling && radv->has_ngg_early_prim_export;
   aco_info->lds_size = radv_calculate_lds_size(radv, gfx_level);
}

static inline void
radv_aco_convert_vs_prolog_key(struct aco_vs_prolog_info *aco_info, const struct radv_vs_prolog_key *radv,
                               const struct radv_shader_args *radv_args)
{
   ASSIGN_FIELD(instance_rate_inputs);
   ASSIGN_FIELD(nontrivial_divisors);
   ASSIGN_FIELD(zero_divisors);
   ASSIGN_FIELD(post_shuffle);
   ASSIGN_FIELD(alpha_adjust_lo);
   ASSIGN_FIELD(alpha_adjust_hi);
   ASSIGN_FIELD_CP(formats);
   ASSIGN_FIELD(num_attributes);
   ASSIGN_FIELD(misaligned_mask);
   ASSIGN_FIELD(unaligned_mask);
   ASSIGN_FIELD(is_ngg);
   ASSIGN_FIELD(next_stage);

   aco_info->inputs = radv_args->prolog_inputs;
}

static inline void
radv_aco_convert_ps_epilog_key(struct aco_ps_epilog_info *aco_info, const struct radv_ps_epilog_key *radv,
                               const struct radv_shader_args *radv_args)
{
   ASSIGN_FIELD(spi_shader_col_format);
   ASSIGN_FIELD(color_is_int8);
   ASSIGN_FIELD(color_is_int10);
   ASSIGN_FIELD(mrt0_is_dual_src);
   ASSIGN_FIELD(alpha_to_coverage_via_mrtz);
   ASSIGN_FIELD(alpha_to_one);

   memcpy(aco_info->colors, radv_args->colors, sizeof(aco_info->colors));
   memcpy(aco_info->color_map, radv->color_map, sizeof(aco_info->color_map));
   aco_info->depth = radv_args->depth;
   aco_info->stencil = radv_args->stencil;
   aco_info->samplemask = radv_args->sample_mask;

   aco_info->alpha_func = COMPARE_FUNC_ALWAYS;
}

static inline void
radv_aco_convert_opts(struct aco_compiler_options *aco_info, const struct radv_nir_compiler_options *radv,
                      const struct radv_shader_args *radv_args, const struct radv_shader_stage_key *stage_key)
{
   ASSIGN_FIELD(dump_ir);
   ASSIGN_FIELD(dump_preoptir);
   ASSIGN_FIELD(record_asm);
   ASSIGN_FIELD(record_ir);
   ASSIGN_FIELD(record_stats);
   ASSIGN_FIELD(enable_mrt_output_nan_fixup);
   ASSIGN_FIELD(wgp_mode);
   aco_info->compiler_info = radv->compiler_info;
   aco_info->is_opengl = false;
   aco_info->optimisations_disabled = stage_key->optimisations_disabled;
   aco_info->gfx_level = radv->gfx_level;
   aco_info->family = radv->family;
   aco_info->address32_hi = radv->address32_hi;
}
#undef ASSIGN_VS_STATE_FIELD
#undef ASSIGN_VS_STATE_FIELD_CP
#undef ASSIGN_FIELD
#undef ASSIGN_FIELD_CP

#endif /* RADV_ACO_SHADER_INFO_H */
