1 // Copyright 2015 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <cstddef>
9 #include <cstring>
10 #include <memory>
11 #include <vector>
12 #include <glad/glad.h>
13 #include "common/bit_field.h"
14 #include "common/common_types.h"
15 #include "common/vector_math.h"
16 #include "core/hw/gpu.h"
17 #include "video_core/pica_state.h"
18 #include "video_core/pica_types.h"
19 #include "video_core/rasterizer_interface.h"
20 #include "video_core/regs_framebuffer.h"
21 #include "video_core/regs_lighting.h"
22 #include "video_core/regs_rasterizer.h"
23 #include "video_core/regs_texturing.h"
24 #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
25 #include "video_core/renderer_opengl/gl_resource_manager.h"
26 #include "video_core/renderer_opengl/gl_shader_manager.h"
27 #include "video_core/renderer_opengl/gl_state.h"
28 #include "video_core/renderer_opengl/gl_stream_buffer.h"
29 #include "video_core/renderer_opengl/pica_to_gl.h"
30 #include "video_core/shader/shader.h"
31 
32 namespace Frontend {
33 class EmuWindow;
34 }
35 
36 namespace OpenGL {
37 class ShaderProgramManager;
38 
39 class RasterizerOpenGL : public VideoCore::RasterizerInterface {
40 public:
41     explicit RasterizerOpenGL();
42     ~RasterizerOpenGL() override;
43 
44     void LoadDiskResources(const std::atomic_bool& stop_loading,
45                            const VideoCore::DiskResourceLoadCallback& callback) override;
46 
47     void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
48                      const Pica::Shader::OutputVertex& v2) override;
49     void DrawTriangles() override;
50     void NotifyPicaRegisterChanged(u32 id) override;
51     void FlushAll() override;
52     void FlushRegion(PAddr addr, u32 size) override;
53     void InvalidateRegion(PAddr addr, u32 size) override;
54     void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
55     void ClearAll(bool flush) override;
56     bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
57     bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
58     bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
59     bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr,
60                            u32 pixel_stride, ScreenInfo& screen_info) override;
61     bool AccelerateDrawBatch(bool is_indexed) override;
62 
63     /// Syncs entire status to match PICA registers
64     void SyncEntireState() override;
65 
66 private:
67     struct SamplerInfo {
68         using TextureConfig = Pica::TexturingRegs::TextureConfig;
69 
70         OGLSampler sampler;
71 
72         /// Creates the sampler object, initializing its state so that it's in sync with the
73         /// SamplerInfo struct.
74         void Create();
75         /// Syncs the sampler object with the config, updating any necessary state.
76         void SyncWithConfig(const TextureConfig& config);
77 
78     private:
79         TextureConfig::TextureFilter mag_filter;
80         TextureConfig::TextureFilter min_filter;
81         TextureConfig::TextureFilter mip_filter;
82         TextureConfig::WrapMode wrap_s;
83         TextureConfig::WrapMode wrap_t;
84         u32 border_color;
85         u32 lod_min;
86         u32 lod_max;
87         s32 lod_bias;
88 
89         // TODO(wwylele): remove this once mipmap for cube is implemented
90         bool supress_mipmap_for_cube = false;
91     };
92 
93     /// Structure that the hardware rendered vertices are composed of
94     struct HardwareVertex {
95         HardwareVertex() = default;
HardwareVertexHardwareVertex96         HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion) {
97             position[0] = v.pos.x.ToFloat32();
98             position[1] = v.pos.y.ToFloat32();
99             position[2] = v.pos.z.ToFloat32();
100             position[3] = v.pos.w.ToFloat32();
101             color[0] = v.color.x.ToFloat32();
102             color[1] = v.color.y.ToFloat32();
103             color[2] = v.color.z.ToFloat32();
104             color[3] = v.color.w.ToFloat32();
105             tex_coord0[0] = v.tc0.x.ToFloat32();
106             tex_coord0[1] = v.tc0.y.ToFloat32();
107             tex_coord1[0] = v.tc1.x.ToFloat32();
108             tex_coord1[1] = v.tc1.y.ToFloat32();
109             tex_coord2[0] = v.tc2.x.ToFloat32();
110             tex_coord2[1] = v.tc2.y.ToFloat32();
111             tex_coord0_w = v.tc0_w.ToFloat32();
112             normquat[0] = v.quat.x.ToFloat32();
113             normquat[1] = v.quat.y.ToFloat32();
114             normquat[2] = v.quat.z.ToFloat32();
115             normquat[3] = v.quat.w.ToFloat32();
116             view[0] = v.view.x.ToFloat32();
117             view[1] = v.view.y.ToFloat32();
118             view[2] = v.view.z.ToFloat32();
119 
120             if (flip_quaternion) {
121                 for (float& x : normquat) {
122                     x = -x;
123                 }
124             }
125         }
126 
127         GLvec4 position;
128         GLvec4 color;
129         GLvec2 tex_coord0;
130         GLvec2 tex_coord1;
131         GLvec2 tex_coord2;
132         GLfloat tex_coord0_w;
133         GLvec4 normquat;
134         GLvec3 view;
135     };
136 
137     /// Syncs the clip enabled status to match the PICA register
138     void SyncClipEnabled();
139 
140     /// Syncs the clip coefficients to match the PICA register
141     void SyncClipCoef();
142 
143     /// Sets the OpenGL shader in accordance with the current PICA register state
144     void SetShader();
145 
146     /// Syncs the cull mode to match the PICA register
147     void SyncCullMode();
148 
149     /// Syncs the depth scale to match the PICA register
150     void SyncDepthScale();
151 
152     /// Syncs the depth offset to match the PICA register
153     void SyncDepthOffset();
154 
155     /// Syncs the blend enabled status to match the PICA register
156     void SyncBlendEnabled();
157 
158     /// Syncs the blend functions to match the PICA register
159     void SyncBlendFuncs();
160 
161     /// Syncs the blend color to match the PICA register
162     void SyncBlendColor();
163 
164     /// Syncs the fog states to match the PICA register
165     void SyncFogColor();
166 
167     /// Sync the procedural texture noise configuration to match the PICA register
168     void SyncProcTexNoise();
169 
170     /// Sync the procedural texture bias configuration to match the PICA register
171     void SyncProcTexBias();
172 
173     /// Syncs the alpha test states to match the PICA register
174     void SyncAlphaTest();
175 
176     /// Syncs the logic op states to match the PICA register
177     void SyncLogicOp();
178 
179     /// Syncs the color write mask to match the PICA register state
180     void SyncColorWriteMask();
181 
182     /// Syncs the stencil write mask to match the PICA register state
183     void SyncStencilWriteMask();
184 
185     /// Syncs the depth write mask to match the PICA register state
186     void SyncDepthWriteMask();
187 
188     /// Syncs the stencil test states to match the PICA register
189     void SyncStencilTest();
190 
191     /// Syncs the depth test states to match the PICA register
192     void SyncDepthTest();
193 
194     /// Syncs the TEV combiner color buffer to match the PICA register
195     void SyncCombinerColor();
196 
197     /// Syncs the TEV constant color to match the PICA register
198     void SyncTevConstColor(std::size_t tev_index,
199                            const Pica::TexturingRegs::TevStageConfig& tev_stage);
200 
201     /// Syncs the lighting global ambient color to match the PICA register
202     void SyncGlobalAmbient();
203 
204     /// Syncs the specified light's specular 0 color to match the PICA register
205     void SyncLightSpecular0(int light_index);
206 
207     /// Syncs the specified light's specular 1 color to match the PICA register
208     void SyncLightSpecular1(int light_index);
209 
210     /// Syncs the specified light's diffuse color to match the PICA register
211     void SyncLightDiffuse(int light_index);
212 
213     /// Syncs the specified light's ambient color to match the PICA register
214     void SyncLightAmbient(int light_index);
215 
216     /// Syncs the specified light's position to match the PICA register
217     void SyncLightPosition(int light_index);
218 
219     /// Syncs the specified spot light direcition to match the PICA register
220     void SyncLightSpotDirection(int light_index);
221 
222     /// Syncs the specified light's distance attenuation bias to match the PICA register
223     void SyncLightDistanceAttenuationBias(int light_index);
224 
225     /// Syncs the specified light's distance attenuation scale to match the PICA register
226     void SyncLightDistanceAttenuationScale(int light_index);
227 
228     /// Syncs the shadow rendering bias to match the PICA register
229     void SyncShadowBias();
230 
231     /// Syncs the shadow texture bias to match the PICA register
232     void SyncShadowTextureBias();
233 
234     /// Syncs and uploads the lighting, fog and proctex LUTs
235     void SyncAndUploadLUTs();
236     void SyncAndUploadLUTsLF();
237 
238     /// Upload the uniform blocks to the uniform buffer object
239     void UploadUniforms(bool accelerate_draw);
240 
241     /// Generic draw function for DrawTriangles and AccelerateDrawBatch
242     bool Draw(bool accelerate, bool is_indexed);
243 
244     /// Internal implementation for AccelerateDrawBatch
245     bool AccelerateDrawBatchInternal(bool is_indexed);
246 
247     struct VertexArrayInfo {
248         u32 vs_input_index_min;
249         u32 vs_input_index_max;
250         u32 vs_input_size;
251     };
252 
253     /// Retrieve the range and the size of the input vertex
254     VertexArrayInfo AnalyzeVertexArray(bool is_indexed);
255 
256     /// Setup vertex array for AccelerateDrawBatch
257     void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset, GLuint vs_input_index_min,
258                           GLuint vs_input_index_max);
259 
260     /// Setup vertex shader for AccelerateDrawBatch
261     bool SetupVertexShader();
262 
263     /// Setup geometry shader for AccelerateDrawBatch
264     bool SetupGeometryShader();
265 
266     bool is_amd;
267 
268     OpenGLState state;
269     GLuint default_texture;
270 
271     RasterizerCacheOpenGL res_cache;
272 
273     std::vector<HardwareVertex> vertex_batch;
274 
275     bool shader_dirty = true;
276 
277     struct {
278         UniformData data;
279         std::array<bool, Pica::LightingRegs::NumLightingSampler> lighting_lut_dirty;
280         bool lighting_lut_dirty_any;
281         bool fog_lut_dirty;
282         bool proctex_noise_lut_dirty;
283         bool proctex_color_map_dirty;
284         bool proctex_alpha_map_dirty;
285         bool proctex_lut_dirty;
286         bool proctex_diff_lut_dirty;
287         bool dirty;
288     } uniform_block_data = {};
289 
290     std::unique_ptr<ShaderProgramManager> shader_program_manager;
291 
292     // They shall be big enough for about one frame.
293     static constexpr std::size_t VERTEX_BUFFER_SIZE = 16 * 1024 * 1024;
294     static constexpr std::size_t INDEX_BUFFER_SIZE = 1 * 1024 * 1024;
295     static constexpr std::size_t UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
296     static constexpr std::size_t TEXTURE_BUFFER_SIZE = 1 * 1024 * 1024;
297 
298     OGLVertexArray sw_vao; // VAO for software shader draw
299     OGLVertexArray hw_vao; // VAO for hardware shader / accelerate draw
300     std::array<bool, 16> hw_vao_enabled_attributes{};
301 
302     std::array<SamplerInfo, 3> texture_samplers;
303     OGLStreamBuffer vertex_buffer;
304     OGLStreamBuffer uniform_buffer;
305     OGLStreamBuffer index_buffer;
306     OGLStreamBuffer texture_buffer;
307     OGLStreamBuffer texture_lf_buffer;
308     OGLFramebuffer framebuffer;
309     GLint uniform_buffer_alignment;
310     std::size_t uniform_size_aligned_vs;
311     std::size_t uniform_size_aligned_fs;
312 
313     SamplerInfo texture_cube_sampler;
314 
315     OGLTexture texture_buffer_lut_lf;
316     OGLTexture texture_buffer_lut_rg;
317     OGLTexture texture_buffer_lut_rgba;
318 
319     std::array<std::array<GLvec2, 256>, Pica::LightingRegs::NumLightingSampler> lighting_lut_data{};
320     std::array<GLvec2, 128> fog_lut_data{};
321     std::array<GLvec2, 128> proctex_noise_lut_data{};
322     std::array<GLvec2, 128> proctex_color_map_data{};
323     std::array<GLvec2, 128> proctex_alpha_map_data{};
324     std::array<GLvec4, 256> proctex_lut_data{};
325     std::array<GLvec4, 256> proctex_diff_lut_data{};
326 
327     bool allow_shadow;
328 };
329 
330 } // namespace OpenGL
331