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 ®isters, 126 unsigned scaling_factor) const; 127 Vulkan::ImageHandle aa_fetch_stage(Vulkan::CommandBuffer &cmd, 128 Vulkan::Image &vram_image, 129 const Registers ®isters, 130 unsigned scaling_factor) const; 131 Vulkan::ImageHandle divot_stage(Vulkan::CommandBuffer &cmd, 132 Vulkan::Image &aa_image, 133 const Registers ®isters, 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 ®, unsigned scaling_factor); 149 }; 150 } 151