// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
 * @file
 * @brief  Settings struct for compositor.
 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
 * @ingroup comp_main
 */

#include "util/u_debug.h"
#include "comp_settings.h"

#define USE_COMPUTE_DEFAULT false

// clang-format off
DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO)
DEBUG_GET_ONCE_BOOL_OPTION(print_modes, "XRT_COMPOSITOR_PRINT_MODES", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_randr, "XRT_COMPOSITOR_FORCE_RANDR", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_wayland_direct, "XRT_COMPOSITOR_FORCE_WAYLAND_DIRECT", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_nvidia, "XRT_COMPOSITOR_FORCE_NVIDIA", false)
DEBUG_GET_ONCE_OPTION(nvidia_display, "XRT_COMPOSITOR_FORCE_NVIDIA_DISPLAY", NULL)
DEBUG_GET_ONCE_NUM_OPTION(vk_display, "XRT_COMPOSITOR_FORCE_VK_DISPLAY", -1)
DEBUG_GET_ONCE_BOOL_OPTION(force_xcb, "XRT_COMPOSITOR_FORCE_XCB", false)
DEBUG_GET_ONCE_BOOL_OPTION(force_wayland, "XRT_COMPOSITOR_FORCE_WAYLAND", false)
DEBUG_GET_ONCE_NUM_OPTION(force_gpu_index, "XRT_COMPOSITOR_FORCE_GPU_INDEX", -1)
DEBUG_GET_ONCE_NUM_OPTION(force_client_gpu_index, "XRT_COMPOSITOR_FORCE_CLIENT_GPU_INDEX", -1)
DEBUG_GET_ONCE_NUM_OPTION(desired_mode, "XRT_COMPOSITOR_DESIRED_MODE", -1)
DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "XRT_COMPOSITOR_SCALE_PERCENTAGE", 140)
DEBUG_GET_ONCE_BOOL_OPTION(xcb_fullscreen, "XRT_COMPOSITOR_XCB_FULLSCREEN", false)
DEBUG_GET_ONCE_NUM_OPTION(xcb_display, "XRT_COMPOSITOR_XCB_DISPLAY", -1)
DEBUG_GET_ONCE_NUM_OPTION(default_framerate, "XRT_COMPOSITOR_DEFAULT_FRAMERATE", 60)
DEBUG_GET_ONCE_BOOL_OPTION(compute, "XRT_COMPOSITOR_COMPUTE", USE_COMPUTE_DEFAULT)
// clang-format on

static inline void
add_format(struct comp_settings *s, VkFormat format)
{
	uint32_t count = s->format_count;

	// Just in case, but should never happen.
	if (count >= ARRAY_SIZE(s->formats)) {
		U_LOG_E("Too many formats!");
		return;
	}

	s->formats[count++] = format;
	s->format_count = count;
}


/*
 *
 * 'Exported' functions.
 *
 */

void
comp_settings_init(struct comp_settings *s, struct xrt_device *xdev)
{
	int default_framerate = debug_get_num_option_default_framerate();

	uint64_t interval_ns = xdev->hmd->screens[0].nominal_frame_interval_ns;
	if (interval_ns == 0) {
		interval_ns = (1000 * 1000 * 1000) / default_framerate;
	}

	s->use_compute = debug_get_bool_option_compute();

	if (s->use_compute) {
		// This was the default before, keep it first.
		add_format(s, VK_FORMAT_B8G8R8A8_UNORM);

		// This is according to GPU info more supported.
		add_format(s, VK_FORMAT_B8G8R8A8_UNORM);

		// Seen on some NVIDIA cards.
		add_format(s, VK_FORMAT_A8B8G8R8_UNORM_PACK32);

		// Untested: 30 bit format, should we move this higher up?
		add_format(s, VK_FORMAT_A2B10G10R10_UNORM_PACK32);

		// Untested: Super constrained platforms.
		add_format(s, VK_FORMAT_A1R5G5B5_UNORM_PACK16);
	} else {
#if defined(XRT_OS_ANDROID)
		/*
		 * On Android the most ubiquitous sRGB format is R8G8B8A8_SRGB.
		 * https://vulkan.gpuinfo.org/listsurfaceformats.php?platform=android
		 */
		add_format(s, VK_FORMAT_R8G8B8A8_SRGB);

		// Fallback
		add_format(s, VK_FORMAT_B8G8R8A8_SRGB);
#elif defined(XRT_OS_LINUX) || defined(XRT_OS_WINDOWS)
		/*
		 * On Linux the most ubiquitous sRGB format is B8G8R8A8_SRGB.
		 * https://vulkan.gpuinfo.org/listsurfaceformats.php?platform=linux
		 *
		 * On Windows the most ubiquitous sRGB format is B8G8R8A8_SRGB.
		 * https://vulkan.gpuinfo.org/listsurfaceformats.php?platform=windows
		 */
		add_format(s, VK_FORMAT_B8G8R8A8_SRGB);

		// Fallback
		add_format(s, VK_FORMAT_R8G8B8A8_SRGB);
#else
#error "Need to pick default swapchain format for this platform!"
#endif

		// Seen as the only sRGB format on some NVIDIA cards.
		add_format(s, VK_FORMAT_A8B8G8R8_SRGB_PACK32);
	}

	s->display = debug_get_num_option_xcb_display();
	s->color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
	s->present_mode = VK_PRESENT_MODE_FIFO_KHR;
	s->fullscreen = debug_get_bool_option_xcb_fullscreen();
	s->preferred.width = xdev->hmd->screens[0].w_pixels;
	s->preferred.height = xdev->hmd->screens[0].h_pixels;
	s->nominal_frame_interval_ns = interval_ns;
	s->log_level = debug_get_log_option_log();
	s->print_modes = debug_get_bool_option_print_modes();
	s->selected_gpu_index = debug_get_num_option_force_gpu_index();
	s->client_gpu_index = debug_get_num_option_force_client_gpu_index();
	s->desired_mode = debug_get_num_option_desired_mode();
	s->viewport_scale = debug_get_num_option_scale_percentage() / 100.0;


	s->nvidia_display = debug_get_option_nvidia_display();
	if (debug_get_bool_option_force_nvidia()) {
		s->target_identifier = "x11_direct_nvidia";
	}

	s->vk_display = debug_get_num_option_vk_display();
	if (s->vk_display >= 0) {
		s->target_identifier = "vk_display";
	}

	if (debug_get_bool_option_force_randr()) {
		s->target_identifier = "x11_direct";
	}

	if (debug_get_bool_option_force_wayland_direct()) {
		s->target_identifier = "direct_wayland";
	}

	if (debug_get_bool_option_force_xcb()) {
		s->target_identifier = "x11";

		// HMD screen tends to be much larger then monitors.
		s->preferred.width /= 2;
		s->preferred.height /= 2;
	}
	if (debug_get_bool_option_force_wayland()) {
		s->target_identifier = "wayland";

		// HMD screen tends to be much larger then monitors.
		s->preferred.width /= 2;
		s->preferred.height /= 2;
	}
}
