/* SPDX-FileCopyrightText: 2022 Blender Authors
 *
 * SPDX-License-Identifier: GPL-2.0-or-later */

/** \file
 * \ingroup draw
 */

#pragma once

#include "GPU_shader_shared_utils.hh"

#ifndef GPU_SHADER
namespace blender::gpu {
class Batch;
}
namespace blender::draw::command {
#endif

/* -------------------------------------------------------------------- */
/** \name Multi Draw
 * \{ */

/**
 * A DrawGroup allow to split the command stream into batch-able chunks of commands with
 * the same render state.
 */
struct [[host_shared]] DrawGroup {
  /** Index of next #DrawGroup from the same header. */
  uint next;

  /**
   * IMPORTANT: All the following 3 members do not take multi-view into account.
   * They only count the number of input instances. The command generation shader must multiply
   * them by view_len to get the correct indices for resource ids.
   */

  /** Index of the first instances after sorting. */
  uint start;
  /** Total number of instances (including inverted facing). Needed to issue the draw call. */
  uint len;
  /** Number of non inverted scaling instances in this Group. */
  uint front_facing_len;

  /** #gpu::Batch values (or subrange of) copied to #DrawCommand after sorting. */
  int vertex_len;
  int vertex_first;
  /* Set to -1 if not an indexed draw. */
  int base_index;

  /** Atomic counters used during command sorting. GPU only. Reset on CPU. */

  /* Counts visible and invisible instances. Create draw-calls when it reaches `DrawGroup::len`. */
  uint total_counter;
  /* Counts only visible instance (counting multi-view). Used to issue the draw-calls. */
  uint front_facing_counter;
  uint back_facing_counter;

  /* CPU specific region of the struct. Should be kept constant after recording.
   * Can be used by GPU but needs to be initialized by GPU before usage. */
#ifndef GPU_SHADER
  struct {
    /* Specific range of vertex to draw from the #gpu::Batch. */
    uint32_t vertex_first;
    /* Ugly packing to support expanded draws without inflating the struct.
     * Makes vertex range restricted to smaller range for expanded draw. */
    uint32_t expand_prim_type : 4;
    uint32_t expand_prim_len : 3;
    uint32_t vertex_len : 25;

    /** Needed to create the correct draw call. */
    gpu::Batch *gpu_batch;
    uint64_t _cpu_pad0;
  } desc;
#else
  uint _cpu_reserved_1;
  uint _cpu_reserved_2;

  uint _cpu_reserved_3;
  uint _cpu_reserved_4;
  uint _cpu_reserved_5;
  uint _cpu_reserved_6;
#endif
};
BLI_STATIC_ASSERT_ALIGN(DrawGroup, 16)

/**
 * Representation of a future draw call inside a DrawGroup. This #DrawPrototype is then
 * converted into #DrawCommand on GPU after visibility and compaction. Multiple
 * #DrawPrototype might get merged into the same final #DrawCommand.
 */
struct [[host_shared]] DrawPrototype {
  /* Reference to parent DrawGroup to get the gpu::Batch vertex / instance count. */
  uint group_id;
  /* Resource handle associated with this call. Also reference visibility. */
  uint res_id;
  /* Custom extra value to be used by the engines. */
  uint custom_id;
  /* Number of instances. */
  uint instance_len;
};

/** \} */

#ifndef GPU_SHADER
};  // namespace blender::draw::command
#endif
