1 /* Copyright (c) 2020 Themaister
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #pragma once
24 
25 #include <stdint.h>
26 #include "device.hpp"
27 #include "rdp_common.hpp"
28 
29 namespace RDP
30 {
31 struct ScanoutOptions
32 {
33 	unsigned crop_overscan_pixels = 0;
34 	unsigned downscale_steps = 0;
35 
36 	// Works around certain game bugs. Considered a hack if enabled.
37 	bool persist_frame_on_invalid_input = false;
38 
39 	// To be equivalent to reference behavior where
40 	// pixels persist for an extra frame.
41 	// Not hardware accurate, but needed for weave interlace mode.
42 	bool blend_previous_frame = false;
43 
44 	// Upscale deinterlacing deinterlaces by upscaling in Y, with an Y coordinate offset matching the field.
45 	// If disabled, weave interlacing is used.
46 	// Weave deinterlacing should *not* be used, except to run test suite!
47 	bool upscale_deinterlacing = true;
48 
49 	struct
50 	{
51 		bool aa = true;
52 		bool scale = true;
53 		bool serrate = true;
54 		bool dither_filter = true;
55 		bool divot_filter = true;
56 		bool gamma_dither = true;
57 	} vi;
58 };
59 
60 class Renderer;
61 
62 class VideoInterface : public Vulkan::DebugChannelInterface
63 {
64 public:
65 	void set_device(Vulkan::Device *device);
66 	void set_renderer(Renderer *renderer);
67 	void set_vi_register(VIRegister reg, uint32_t value);
68 
69 	void set_rdram(const Vulkan::Buffer *rdram, size_t offset, size_t size);
70 	void set_hidden_rdram(const Vulkan::Buffer *hidden_rdram);
71 
72 	int resolve_shader_define(const char *name, const char *define) const;
73 
74 	Vulkan::ImageHandle scanout(VkImageLayout target_layout, const ScanoutOptions &options = {}, unsigned scale_factor = 1);
75 	void scanout_memory_range(unsigned &offset, unsigned &length) const;
76 	void set_shader_bank(const ShaderBank *bank);
77 
78 private:
79 	Vulkan::Device *device = nullptr;
80 	Renderer *renderer = nullptr;
81 	uint32_t vi_registers[unsigned(VIRegister::Count)] = {};
82 	const Vulkan::Buffer *rdram = nullptr;
83 	const Vulkan::Buffer *hidden_rdram = nullptr;
84 	Vulkan::BufferHandle gamma_lut;
85 	Vulkan::BufferViewHandle gamma_lut_view;
86 	const ShaderBank *shader_bank = nullptr;
87 
88 	void init_gamma_table();
89 	bool previous_frame_blank = false;
90 	bool debug_channel = false;
91 	int filter_debug_channel_x = -1;
92 	int filter_debug_channel_y = -1;
93 
94 	void message(const std::string &tag, uint32_t code,
95 	             uint32_t x, uint32_t y, uint32_t z,
96 	             uint32_t num_words, const Vulkan::DebugChannelInterface::Word *words) override;
97 
98 	// Frame state.
99 	uint32_t frame_count = 0;
100 	uint32_t last_valid_frame_count = 0;
101 	Vulkan::ImageHandle prev_scanout_image;
102 	VkImageLayout prev_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
103 
104 	size_t rdram_offset = 0;
105 	size_t rdram_size = 0;
106 	bool timestamp = false;
107 
108 	struct Registers
109 	{
110 		int x_start, y_start;
111 		int h_start, v_start;
112 		int h_end, v_end;
113 		int h_res, v_res;
114 		int x_add, y_add;
115 		int v_sync;
116 		int vi_width;
117 		int vi_offset;
118 		int max_x, max_y;
119 		int v_current_line;
120 		bool left_clamp, right_clamp;
121 		bool is_pal;
122 		uint32_t status;
123 	};
124 	Registers decode_vi_registers() const;
125 	Vulkan::ImageHandle vram_fetch_stage(const Registers &registers,
126 	                                     unsigned scaling_factor) const;
127 	Vulkan::ImageHandle aa_fetch_stage(Vulkan::CommandBuffer &cmd,
128 	                                   Vulkan::Image &vram_image,
129 	                                   const Registers &registers,
130 	                                   unsigned scaling_factor) const;
131 	Vulkan::ImageHandle divot_stage(Vulkan::CommandBuffer &cmd,
132 	                                Vulkan::Image &aa_image,
133 	                                const Registers &registers,
134 	                                unsigned scaling_factor) const;
135 	Vulkan::ImageHandle scale_stage(Vulkan::CommandBuffer &cmd,
136 	                                Vulkan::Image &divot_image,
137 	                                Registers registers,
138 	                                unsigned scaling_factor,
139 	                                bool degenerate,
140 	                                const ScanoutOptions &options) const;
141 	Vulkan::ImageHandle downscale_stage(Vulkan::CommandBuffer &cmd,
142 	                                    Vulkan::Image &scale_image,
143 	                                    unsigned scaling_factor,
144 	                                    unsigned downscale_factor) const;
145 	Vulkan::ImageHandle upscale_deinterlace(Vulkan::CommandBuffer &cmd,
146 	                                        Vulkan::Image &scale_image,
147 	                                        unsigned scaling_factor, bool field_select) const;
148 	static bool need_fetch_bug_emulation(const Registers &reg, unsigned scaling_factor);
149 };
150 }
151