mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	VideoCore: Split rasterizer regs from Regs struct
This commit is contained in:
		
							parent
							
								
									97e06b0a0d
								
							
						
					
					
						commit
						000e78144c
					
				
					 14 changed files with 219 additions and 188 deletions
				
			
		|  | @ -359,7 +359,7 @@ void GraphicsVertexShaderWidget::DumpShader() { | ||||||
|     auto& config = Pica::g_state.regs.vs; |     auto& config = Pica::g_state.regs.vs; | ||||||
| 
 | 
 | ||||||
|     Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, |     Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, | ||||||
|                                  Pica::g_state.regs.vs_output_attributes); |                                  Pica::g_state.regs.rasterizer.vs_output_attributes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( | GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( | ||||||
|  |  | ||||||
|  | @ -32,6 +32,7 @@ set(HEADERS | ||||||
|             primitive_assembly.h |             primitive_assembly.h | ||||||
|             rasterizer.h |             rasterizer.h | ||||||
|             rasterizer_interface.h |             rasterizer_interface.h | ||||||
|  |             regs_rasterizer.h | ||||||
|             renderer_base.h |             renderer_base.h | ||||||
|             renderer_opengl/gl_rasterizer.h |             renderer_opengl/gl_rasterizer.h | ||||||
|             renderer_opengl/gl_rasterizer_cache.h |             renderer_opengl/gl_rasterizer_cache.h | ||||||
|  |  | ||||||
|  | @ -64,10 +64,10 @@ static void InitScreenCoordinates(Vertex& vtx) { | ||||||
|     } viewport; |     } viewport; | ||||||
| 
 | 
 | ||||||
|     const auto& regs = g_state.regs; |     const auto& regs = g_state.regs; | ||||||
|     viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x); |     viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x); | ||||||
|     viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y); |     viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y); | ||||||
|     viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x)); |     viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x)); | ||||||
|     viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y)); |     viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y)); | ||||||
| 
 | 
 | ||||||
|     float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; |     float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; | ||||||
|     vtx.color *= inv_w; |     vtx.color *= inv_w; | ||||||
|  |  | ||||||
|  | @ -165,7 +165,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|                     g_state.primitive_assembler.SubmitVertex( |                     g_state.primitive_assembler.SubmitVertex( | ||||||
|                         Shader::OutputVertex::FromAttributeBuffer(regs, output), AddTriangle); |                         Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output), | ||||||
|  |                         AddTriangle); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -295,7 +296,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | ||||||
|                 shader_unit.WriteOutput(regs.vs, output); |                 shader_unit.WriteOutput(regs.vs, output); | ||||||
| 
 | 
 | ||||||
|                 // Retrieve vertex from register data
 |                 // Retrieve vertex from register data
 | ||||||
|                 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs, output); |                 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output); | ||||||
| 
 | 
 | ||||||
|                 if (is_indexed) { |                 if (is_indexed) { | ||||||
|                     vertex_cache[vertex_cache_pos] = output_vertex; |                     vertex_cache[vertex_cache_pos] = output_vertex; | ||||||
|  |  | ||||||
|  | @ -90,7 +90,7 @@ namespace DebugUtils { | ||||||
| 
 | 
 | ||||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||||
|                 const Shader::ShaderSetup& setup, |                 const Shader::ShaderSetup& setup, | ||||||
|                 const Regs::VSOutputAttributes* output_attributes) { |                 const RasterizerRegs::VSOutputAttributes* output_attributes) { | ||||||
|     struct StuffToWrite { |     struct StuffToWrite { | ||||||
|         const u8* pointer; |         const u8* pointer; | ||||||
|         u32 size; |         u32 size; | ||||||
|  | @ -129,7 +129,7 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||||
|     // This is put into a try-catch block to make sure we notice unknown configurations.
 |     // This is put into a try-catch block to make sure we notice unknown configurations.
 | ||||||
|     std::vector<OutputRegisterInfo> output_info_table; |     std::vector<OutputRegisterInfo> output_info_table; | ||||||
|     for (unsigned i = 0; i < 7; ++i) { |     for (unsigned i = 0; i < 7; ++i) { | ||||||
|         using OutputAttributes = Pica::Regs::VSOutputAttributes; |         using OutputAttributes = Pica::RasterizerRegs::VSOutputAttributes; | ||||||
| 
 | 
 | ||||||
|         // TODO: It's still unclear how the attribute components map to the register!
 |         // TODO: It's still unclear how the attribute components map to the register!
 | ||||||
|         //       Once we know that, this code probably will not make much sense anymore.
 |         //       Once we know that, this code probably will not make much sense anymore.
 | ||||||
|  |  | ||||||
|  | @ -184,7 +184,7 @@ namespace DebugUtils { | ||||||
| 
 | 
 | ||||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||||
|                 const Shader::ShaderSetup& setup, |                 const Shader::ShaderSetup& setup, | ||||||
|                 const Regs::VSOutputAttributes* output_attributes); |                 const RasterizerRegs::VSOutputAttributes* output_attributes); | ||||||
| 
 | 
 | ||||||
| // Utility class to log Pica commands.
 | // Utility class to log Pica commands.
 | ||||||
| struct PicaTrace { | struct PicaTrace { | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/vector_math.h" | #include "common/vector_math.h" | ||||||
|  | #include "video_core/regs_rasterizer.h" | ||||||
| 
 | 
 | ||||||
| namespace Pica { | namespace Pica { | ||||||
| 
 | 
 | ||||||
|  | @ -44,121 +45,10 @@ namespace Pica { | ||||||
| #endif // _MSC_VER
 | #endif // _MSC_VER
 | ||||||
| 
 | 
 | ||||||
| struct Regs { | struct Regs { | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x10); |     INSERT_PADDING_WORDS(0x10); | ||||||
| 
 |  | ||||||
|     u32 trigger_irq; |     u32 trigger_irq; | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x2f); |     INSERT_PADDING_WORDS(0x2f); | ||||||
| 
 |     RasterizerRegs rasterizer; | ||||||
|     enum class CullMode : u32 { |  | ||||||
|         // Select which polygons are considered to be "frontfacing".
 |  | ||||||
|         KeepAll = 0, |  | ||||||
|         KeepClockWise = 1, |  | ||||||
|         KeepCounterClockWise = 2, |  | ||||||
|         // TODO: What does the third value imply?
 |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     union { |  | ||||||
|         BitField<0, 2, CullMode> cull_mode; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     BitField<0, 24, u32> viewport_size_x; |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x1); |  | ||||||
| 
 |  | ||||||
|     BitField<0, 24, u32> viewport_size_y; |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x9); |  | ||||||
| 
 |  | ||||||
|     BitField<0, 24, u32> viewport_depth_range;      // float24
 |  | ||||||
|     BitField<0, 24, u32> viewport_depth_near_plane; // float24
 |  | ||||||
| 
 |  | ||||||
|     BitField<0, 3, u32> vs_output_total; |  | ||||||
| 
 |  | ||||||
|     union VSOutputAttributes { |  | ||||||
|         // Maps components of output vertex attributes to semantics
 |  | ||||||
|         enum Semantic : u32 { |  | ||||||
|             POSITION_X = 0, |  | ||||||
|             POSITION_Y = 1, |  | ||||||
|             POSITION_Z = 2, |  | ||||||
|             POSITION_W = 3, |  | ||||||
| 
 |  | ||||||
|             QUATERNION_X = 4, |  | ||||||
|             QUATERNION_Y = 5, |  | ||||||
|             QUATERNION_Z = 6, |  | ||||||
|             QUATERNION_W = 7, |  | ||||||
| 
 |  | ||||||
|             COLOR_R = 8, |  | ||||||
|             COLOR_G = 9, |  | ||||||
|             COLOR_B = 10, |  | ||||||
|             COLOR_A = 11, |  | ||||||
| 
 |  | ||||||
|             TEXCOORD0_U = 12, |  | ||||||
|             TEXCOORD0_V = 13, |  | ||||||
|             TEXCOORD1_U = 14, |  | ||||||
|             TEXCOORD1_V = 15, |  | ||||||
| 
 |  | ||||||
|             TEXCOORD0_W = 16, |  | ||||||
| 
 |  | ||||||
|             VIEW_X = 18, |  | ||||||
|             VIEW_Y = 19, |  | ||||||
|             VIEW_Z = 20, |  | ||||||
| 
 |  | ||||||
|             TEXCOORD2_U = 22, |  | ||||||
|             TEXCOORD2_V = 23, |  | ||||||
| 
 |  | ||||||
|             INVALID = 31, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         BitField<0, 5, Semantic> map_x; |  | ||||||
|         BitField<8, 5, Semantic> map_y; |  | ||||||
|         BitField<16, 5, Semantic> map_z; |  | ||||||
|         BitField<24, 5, Semantic> map_w; |  | ||||||
|     } vs_output_attributes[7]; |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0xe); |  | ||||||
| 
 |  | ||||||
|     enum class ScissorMode : u32 { |  | ||||||
|         Disabled = 0, |  | ||||||
|         Exclude = 1, // Exclude pixels inside the scissor box
 |  | ||||||
| 
 |  | ||||||
|         Include = 3 // Exclude pixels outside the scissor box
 |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct { |  | ||||||
|         BitField<0, 2, ScissorMode> mode; |  | ||||||
| 
 |  | ||||||
|         union { |  | ||||||
|             BitField<0, 16, u32> x1; |  | ||||||
|             BitField<16, 16, u32> y1; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         union { |  | ||||||
|             BitField<0, 16, u32> x2; |  | ||||||
|             BitField<16, 16, u32> y2; |  | ||||||
|         }; |  | ||||||
|     } scissor_test; |  | ||||||
| 
 |  | ||||||
|     union { |  | ||||||
|         BitField<0, 10, s32> x; |  | ||||||
|         BitField<16, 10, s32> y; |  | ||||||
|     } viewport_corner; |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x1); |  | ||||||
| 
 |  | ||||||
|     // TODO: early depth
 |  | ||||||
|     INSERT_PADDING_WORDS(0x1); |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x2); |  | ||||||
| 
 |  | ||||||
|     enum DepthBuffering : u32 { |  | ||||||
|         WBuffering = 0, |  | ||||||
|         ZBuffering = 1, |  | ||||||
|     }; |  | ||||||
|     BitField<0, 1, DepthBuffering> depthmap_enable; |  | ||||||
| 
 |  | ||||||
|     INSERT_PADDING_WORDS(0x12); |  | ||||||
| 
 | 
 | ||||||
|     struct TextureConfig { |     struct TextureConfig { | ||||||
|         enum TextureType : u32 { |         enum TextureType : u32 { | ||||||
|  | @ -1338,16 +1228,19 @@ private: | ||||||
|                   "Field " #field_name " has invalid position") |                   "Field " #field_name " has invalid position") | ||||||
| 
 | 
 | ||||||
| ASSERT_REG_POSITION(trigger_irq, 0x10); | ASSERT_REG_POSITION(trigger_irq, 0x10); | ||||||
| ASSERT_REG_POSITION(cull_mode, 0x40); | 
 | ||||||
| ASSERT_REG_POSITION(viewport_size_x, 0x41); | ASSERT_REG_POSITION(rasterizer, 0x40); | ||||||
| ASSERT_REG_POSITION(viewport_size_y, 0x43); | ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40); | ||||||
| ASSERT_REG_POSITION(viewport_depth_range, 0x4d); | ASSERT_REG_POSITION(rasterizer.viewport_size_x, 0x41); | ||||||
| ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e); | ASSERT_REG_POSITION(rasterizer.viewport_size_y, 0x43); | ||||||
| ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); | ASSERT_REG_POSITION(rasterizer.viewport_depth_range, 0x4d); | ||||||
| ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); | ASSERT_REG_POSITION(rasterizer.viewport_depth_near_plane, 0x4e); | ||||||
| ASSERT_REG_POSITION(scissor_test, 0x65); | ASSERT_REG_POSITION(rasterizer.vs_output_attributes[0], 0x50); | ||||||
| ASSERT_REG_POSITION(viewport_corner, 0x68); | ASSERT_REG_POSITION(rasterizer.vs_output_attributes[1], 0x51); | ||||||
| ASSERT_REG_POSITION(depthmap_enable, 0x6D); | ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65); | ||||||
|  | ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68); | ||||||
|  | ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D); | ||||||
|  | 
 | ||||||
| ASSERT_REG_POSITION(texture0_enable, 0x80); | ASSERT_REG_POSITION(texture0_enable, 0x80); | ||||||
| ASSERT_REG_POSITION(texture0, 0x81); | ASSERT_REG_POSITION(texture0, 0x81); | ||||||
| ASSERT_REG_POSITION(texture0_format, 0x8e); | ASSERT_REG_POSITION(texture0_format, 0x8e); | ||||||
|  |  | ||||||
|  | @ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | ||||||
|                                   ScreenToRasterizerCoordinates(v1.screenpos), |                                   ScreenToRasterizerCoordinates(v1.screenpos), | ||||||
|                                   ScreenToRasterizerCoordinates(v2.screenpos)}; |                                   ScreenToRasterizerCoordinates(v2.screenpos)}; | ||||||
| 
 | 
 | ||||||
|     if (regs.cull_mode == Regs::CullMode::KeepAll) { |     if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) { | ||||||
|         // Make sure we always end up with a triangle wound counter-clockwise
 |         // Make sure we always end up with a triangle wound counter-clockwise
 | ||||||
|         if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { |         if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { | ||||||
|             ProcessTriangleInternal(v0, v2, v1, true); |             ProcessTriangleInternal(v0, v2, v1, true); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         if (!reversed && regs.cull_mode == Regs::CullMode::KeepClockWise) { |         if (!reversed && regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepClockWise) { | ||||||
|             // Reverse vertex order and use the CCW code path.
 |             // Reverse vertex order and use the CCW code path.
 | ||||||
|             ProcessTriangleInternal(v0, v2, v1, true); |             ProcessTriangleInternal(v0, v2, v1, true); | ||||||
|             return; |             return; | ||||||
|  | @ -351,13 +351,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | ||||||
|     u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); |     u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); | ||||||
| 
 | 
 | ||||||
|     // Convert the scissor box coordinates to 12.4 fixed point
 |     // Convert the scissor box coordinates to 12.4 fixed point
 | ||||||
|     u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4); |     u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4); | ||||||
|     u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4); |     u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4); | ||||||
|     // x2,y2 have +1 added to cover the entire sub-pixel area
 |     // x2,y2 have +1 added to cover the entire sub-pixel area
 | ||||||
|     u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); |     u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4); | ||||||
|     u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); |     u16 scissor_y2 = (u16)((regs.rasterizer.scissor_test.y2 + 1) << 4); | ||||||
| 
 | 
 | ||||||
|     if (regs.scissor_test.mode == Regs::ScissorMode::Include) { |     if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Include) { | ||||||
|         // Calculate the new bounds
 |         // Calculate the new bounds
 | ||||||
|         min_x = std::max(min_x, scissor_x1); |         min_x = std::max(min_x, scissor_x1); | ||||||
|         min_y = std::max(min_y, scissor_y1); |         min_y = std::max(min_y, scissor_y1); | ||||||
|  | @ -411,7 +411,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | ||||||
| 
 | 
 | ||||||
|             // Do not process the pixel if it's inside the scissor box and the scissor mode is set
 |             // Do not process the pixel if it's inside the scissor box and the scissor mode is set
 | ||||||
|             // to Exclude
 |             // to Exclude
 | ||||||
|             if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { |             if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Exclude) { | ||||||
|                 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2) |                 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2) | ||||||
|                     continue; |                     continue; | ||||||
|             } |             } | ||||||
|  | @ -441,12 +441,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | ||||||
| 
 | 
 | ||||||
|             // Not fully accurate. About 3 bits in precision are missing.
 |             // Not fully accurate. About 3 bits in precision are missing.
 | ||||||
|             // Z-Buffer (z / w * scale + offset)
 |             // Z-Buffer (z / w * scale + offset)
 | ||||||
|             float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); |             float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32(); | ||||||
|             float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); |             float depth_offset = | ||||||
|  |                 float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32(); | ||||||
|             float depth = interpolated_z_over_w * depth_scale + depth_offset; |             float depth = interpolated_z_over_w * depth_scale + depth_offset; | ||||||
| 
 | 
 | ||||||
|             // Potentially switch to W-Buffer
 |             // Potentially switch to W-Buffer
 | ||||||
|             if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { |             if (regs.rasterizer.depthmap_enable == | ||||||
|  |                 Pica::RasterizerRegs::DepthBuffering::WBuffering) { | ||||||
|                 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
 |                 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
 | ||||||
|                 depth *= interpolated_w_inverse.ToFloat32() * wsum; |                 depth *= interpolated_w_inverse.ToFloat32() * wsum; | ||||||
|             } |             } | ||||||
|  |  | ||||||
							
								
								
									
										129
									
								
								src/video_core/regs_rasterizer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/video_core/regs_rasterizer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <array> | ||||||
|  | 
 | ||||||
|  | #include "common/bit_field.h" | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "common/common_types.h" | ||||||
|  | 
 | ||||||
|  | namespace Pica { | ||||||
|  | 
 | ||||||
|  | struct RasterizerRegs { | ||||||
|  |     enum class CullMode : u32 { | ||||||
|  |         // Select which polygons are considered to be "frontfacing".
 | ||||||
|  |         KeepAll = 0, | ||||||
|  |         KeepClockWise = 1, | ||||||
|  |         KeepCounterClockWise = 2, | ||||||
|  |         // TODO: What does the third value imply?
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     union { | ||||||
|  |         BitField<0, 2, CullMode> cull_mode; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     BitField<0, 24, u32> viewport_size_x; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x1); | ||||||
|  | 
 | ||||||
|  |     BitField<0, 24, u32> viewport_size_y; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x9); | ||||||
|  | 
 | ||||||
|  |     BitField<0, 24, u32> viewport_depth_range;      // float24
 | ||||||
|  |     BitField<0, 24, u32> viewport_depth_near_plane; // float24
 | ||||||
|  | 
 | ||||||
|  |     BitField<0, 3, u32> vs_output_total; | ||||||
|  | 
 | ||||||
|  |     union VSOutputAttributes { | ||||||
|  |         // Maps components of output vertex attributes to semantics
 | ||||||
|  |         enum Semantic : u32 { | ||||||
|  |             POSITION_X = 0, | ||||||
|  |             POSITION_Y = 1, | ||||||
|  |             POSITION_Z = 2, | ||||||
|  |             POSITION_W = 3, | ||||||
|  | 
 | ||||||
|  |             QUATERNION_X = 4, | ||||||
|  |             QUATERNION_Y = 5, | ||||||
|  |             QUATERNION_Z = 6, | ||||||
|  |             QUATERNION_W = 7, | ||||||
|  | 
 | ||||||
|  |             COLOR_R = 8, | ||||||
|  |             COLOR_G = 9, | ||||||
|  |             COLOR_B = 10, | ||||||
|  |             COLOR_A = 11, | ||||||
|  | 
 | ||||||
|  |             TEXCOORD0_U = 12, | ||||||
|  |             TEXCOORD0_V = 13, | ||||||
|  |             TEXCOORD1_U = 14, | ||||||
|  |             TEXCOORD1_V = 15, | ||||||
|  | 
 | ||||||
|  |             TEXCOORD0_W = 16, | ||||||
|  | 
 | ||||||
|  |             VIEW_X = 18, | ||||||
|  |             VIEW_Y = 19, | ||||||
|  |             VIEW_Z = 20, | ||||||
|  | 
 | ||||||
|  |             TEXCOORD2_U = 22, | ||||||
|  |             TEXCOORD2_V = 23, | ||||||
|  | 
 | ||||||
|  |             INVALID = 31, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         BitField<0, 5, Semantic> map_x; | ||||||
|  |         BitField<8, 5, Semantic> map_y; | ||||||
|  |         BitField<16, 5, Semantic> map_z; | ||||||
|  |         BitField<24, 5, Semantic> map_w; | ||||||
|  |     } vs_output_attributes[7]; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0xe); | ||||||
|  | 
 | ||||||
|  |     enum class ScissorMode : u32 { | ||||||
|  |         Disabled = 0, | ||||||
|  |         Exclude = 1, // Exclude pixels inside the scissor box
 | ||||||
|  | 
 | ||||||
|  |         Include = 3 // Exclude pixels outside the scissor box
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct { | ||||||
|  |         BitField<0, 2, ScissorMode> mode; | ||||||
|  | 
 | ||||||
|  |         union { | ||||||
|  |             BitField<0, 16, u32> x1; | ||||||
|  |             BitField<16, 16, u32> y1; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         union { | ||||||
|  |             BitField<0, 16, u32> x2; | ||||||
|  |             BitField<16, 16, u32> y2; | ||||||
|  |         }; | ||||||
|  |     } scissor_test; | ||||||
|  | 
 | ||||||
|  |     union { | ||||||
|  |         BitField<0, 10, s32> x; | ||||||
|  |         BitField<16, 10, s32> y; | ||||||
|  |     } viewport_corner; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x1); | ||||||
|  | 
 | ||||||
|  |     // TODO: early depth
 | ||||||
|  |     INSERT_PADDING_WORDS(0x1); | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x2); | ||||||
|  | 
 | ||||||
|  |     enum DepthBuffering : u32 { | ||||||
|  |         WBuffering = 0, | ||||||
|  |         ZBuffering = 1, | ||||||
|  |     }; | ||||||
|  |     BitField<0, 1, DepthBuffering> depthmap_enable; | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x12); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static_assert(sizeof(RasterizerRegs) == 0x40 * sizeof(u32), | ||||||
|  |               "RasterizerRegs struct has incorrect size"); | ||||||
|  | 
 | ||||||
|  | } // namespace Pica
 | ||||||
|  | @ -197,13 +197,16 @@ void RasterizerOpenGL::DrawTriangles() { | ||||||
| 
 | 
 | ||||||
|     // Sync the viewport
 |     // Sync the viewport
 | ||||||
|     // These registers hold half-width and half-height, so must be multiplied by 2
 |     // These registers hold half-width and half-height, so must be multiplied by 2
 | ||||||
|     GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2; |     GLsizei viewport_width = | ||||||
|     GLsizei viewport_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2; |         (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_x).ToFloat32() * 2; | ||||||
|  |     GLsizei viewport_height = | ||||||
|  |         (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_y).ToFloat32() * 2; | ||||||
| 
 | 
 | ||||||
|     glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), |     glViewport( | ||||||
|                (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), |         (GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width), | ||||||
|                (GLsizei)(viewport_width * color_surface->res_scale_width), |         (GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * color_surface->res_scale_height), | ||||||
|                (GLsizei)(viewport_height * color_surface->res_scale_height)); |         (GLsizei)(viewport_width * color_surface->res_scale_width), | ||||||
|  |         (GLsizei)(viewport_height * color_surface->res_scale_height)); | ||||||
| 
 | 
 | ||||||
|     if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || |     if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || | ||||||
|         uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { |         uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { | ||||||
|  | @ -215,16 +218,16 @@ void RasterizerOpenGL::DrawTriangles() { | ||||||
| 
 | 
 | ||||||
|     // Scissor checks are window-, not viewport-relative, which means that if the cached texture
 |     // Scissor checks are window-, not viewport-relative, which means that if the cached texture
 | ||||||
|     // sub-rect changes, the scissor bounds also need to be updated.
 |     // sub-rect changes, the scissor bounds also need to be updated.
 | ||||||
|     GLint scissor_x1 = |     GLint scissor_x1 = static_cast<GLint>( | ||||||
|         static_cast<GLint>(rect.left + regs.scissor_test.x1 * color_surface->res_scale_width); |         rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width); | ||||||
|     GLint scissor_y1 = |     GLint scissor_y1 = static_cast<GLint>( | ||||||
|         static_cast<GLint>(rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height); |         rect.bottom + regs.rasterizer.scissor_test.y1 * color_surface->res_scale_height); | ||||||
|     // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
 |     // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
 | ||||||
|     // scaling or doing multisampling.
 |     // scaling or doing multisampling.
 | ||||||
|     GLint scissor_x2 = |     GLint scissor_x2 = static_cast<GLint>( | ||||||
|         static_cast<GLint>(rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width); |         rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width); | ||||||
|     GLint scissor_y2 = static_cast<GLint>( |     GLint scissor_y2 = static_cast<GLint>( | ||||||
|         rect.bottom + (regs.scissor_test.y2 + 1) * color_surface->res_scale_height); |         rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * color_surface->res_scale_height); | ||||||
| 
 | 
 | ||||||
|     if (uniform_block_data.data.scissor_x1 != scissor_x1 || |     if (uniform_block_data.data.scissor_x1 != scissor_x1 || | ||||||
|         uniform_block_data.data.scissor_x2 != scissor_x2 || |         uniform_block_data.data.scissor_x2 != scissor_x2 || | ||||||
|  | @ -316,20 +319,20 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | ||||||
| 
 | 
 | ||||||
|     switch (id) { |     switch (id) { | ||||||
|     // Culling
 |     // Culling
 | ||||||
|     case PICA_REG_INDEX(cull_mode): |     case PICA_REG_INDEX(rasterizer.cull_mode): | ||||||
|         SyncCullMode(); |         SyncCullMode(); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Depth modifiers
 |     // Depth modifiers
 | ||||||
|     case PICA_REG_INDEX(viewport_depth_range): |     case PICA_REG_INDEX(rasterizer.viewport_depth_range): | ||||||
|         SyncDepthScale(); |         SyncDepthScale(); | ||||||
|         break; |         break; | ||||||
|     case PICA_REG_INDEX(viewport_depth_near_plane): |     case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane): | ||||||
|         SyncDepthOffset(); |         SyncDepthOffset(); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Depth buffering
 |     // Depth buffering
 | ||||||
|     case PICA_REG_INDEX(depthmap_enable): |     case PICA_REG_INDEX(rasterizer.depthmap_enable): | ||||||
|         shader_dirty = true; |         shader_dirty = true; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|  | @ -398,7 +401,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     // Scissor test
 |     // Scissor test
 | ||||||
|     case PICA_REG_INDEX(scissor_test.mode): |     case PICA_REG_INDEX(rasterizer.scissor_test.mode): | ||||||
|         shader_dirty = true; |         shader_dirty = true; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|  | @ -1110,30 +1113,31 @@ void RasterizerOpenGL::SetShader() { | ||||||
| void RasterizerOpenGL::SyncCullMode() { | void RasterizerOpenGL::SyncCullMode() { | ||||||
|     const auto& regs = Pica::g_state.regs; |     const auto& regs = Pica::g_state.regs; | ||||||
| 
 | 
 | ||||||
|     switch (regs.cull_mode) { |     switch (regs.rasterizer.cull_mode) { | ||||||
|     case Pica::Regs::CullMode::KeepAll: |     case Pica::RasterizerRegs::CullMode::KeepAll: | ||||||
|         state.cull.enabled = false; |         state.cull.enabled = false; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case Pica::Regs::CullMode::KeepClockWise: |     case Pica::RasterizerRegs::CullMode::KeepClockWise: | ||||||
|         state.cull.enabled = true; |         state.cull.enabled = true; | ||||||
|         state.cull.front_face = GL_CW; |         state.cull.front_face = GL_CW; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case Pica::Regs::CullMode::KeepCounterClockWise: |     case Pica::RasterizerRegs::CullMode::KeepCounterClockWise: | ||||||
|         state.cull.enabled = true; |         state.cull.enabled = true; | ||||||
|         state.cull.front_face = GL_CCW; |         state.cull.front_face = GL_CCW; | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.cull_mode.Value()); |         LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.rasterizer.cull_mode.Value()); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RasterizerOpenGL::SyncDepthScale() { | void RasterizerOpenGL::SyncDepthScale() { | ||||||
|     float depth_scale = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32(); |     float depth_scale = | ||||||
|  |         Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32(); | ||||||
|     if (depth_scale != uniform_block_data.data.depth_scale) { |     if (depth_scale != uniform_block_data.data.depth_scale) { | ||||||
|         uniform_block_data.data.depth_scale = depth_scale; |         uniform_block_data.data.depth_scale = depth_scale; | ||||||
|         uniform_block_data.dirty = true; |         uniform_block_data.dirty = true; | ||||||
|  | @ -1142,7 +1146,7 @@ void RasterizerOpenGL::SyncDepthScale() { | ||||||
| 
 | 
 | ||||||
| void RasterizerOpenGL::SyncDepthOffset() { | void RasterizerOpenGL::SyncDepthOffset() { | ||||||
|     float depth_offset = |     float depth_offset = | ||||||
|         Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); |         Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32(); | ||||||
|     if (depth_offset != uniform_block_data.data.depth_offset) { |     if (depth_offset != uniform_block_data.data.depth_offset) { | ||||||
|         uniform_block_data.data.depth_offset = depth_offset; |         uniform_block_data.data.depth_offset = depth_offset; | ||||||
|         uniform_block_data.dirty = true; |         uniform_block_data.dirty = true; | ||||||
|  |  | ||||||
|  | @ -52,9 +52,9 @@ union PicaShaderConfig { | ||||||
| 
 | 
 | ||||||
|         const auto& regs = Pica::g_state.regs; |         const auto& regs = Pica::g_state.regs; | ||||||
| 
 | 
 | ||||||
|         state.scissor_test_mode = regs.scissor_test.mode; |         state.scissor_test_mode = regs.rasterizer.scissor_test.mode; | ||||||
| 
 | 
 | ||||||
|         state.depthmap_enable = regs.depthmap_enable; |         state.depthmap_enable = regs.rasterizer.depthmap_enable; | ||||||
| 
 | 
 | ||||||
|         state.alpha_test_func = regs.output_merger.alpha_test.enable |         state.alpha_test_func = regs.output_merger.alpha_test.enable | ||||||
|                                     ? regs.output_merger.alpha_test.func.Value() |                                     ? regs.output_merger.alpha_test.func.Value() | ||||||
|  | @ -172,12 +172,12 @@ union PicaShaderConfig { | ||||||
| 
 | 
 | ||||||
|     struct State { |     struct State { | ||||||
|         Pica::Regs::CompareFunc alpha_test_func; |         Pica::Regs::CompareFunc alpha_test_func; | ||||||
|         Pica::Regs::ScissorMode scissor_test_mode; |         Pica::RasterizerRegs::ScissorMode scissor_test_mode; | ||||||
|         Pica::Regs::TextureConfig::TextureType texture0_type; |         Pica::Regs::TextureConfig::TextureType texture0_type; | ||||||
|         std::array<TevStageConfigRaw, 6> tev_stages; |         std::array<TevStageConfigRaw, 6> tev_stages; | ||||||
|         u8 combiner_buffer_input; |         u8 combiner_buffer_input; | ||||||
| 
 | 
 | ||||||
|         Pica::Regs::DepthBuffering depthmap_enable; |         Pica::RasterizerRegs::DepthBuffering depthmap_enable; | ||||||
|         Pica::Regs::FogMode fog_mode; |         Pica::Regs::FogMode fog_mode; | ||||||
|         bool fog_flip; |         bool fog_flip; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | #include "video_core/renderer_opengl/gl_shader_util.h" | ||||||
| 
 | 
 | ||||||
| using Pica::Regs; | using Pica::Regs; | ||||||
|  | using Pica::RasterizerRegs; | ||||||
| using TevStageConfig = Regs::TevStageConfig; | using TevStageConfig = Regs::TevStageConfig; | ||||||
| 
 | 
 | ||||||
| namespace GLShader { | namespace GLShader { | ||||||
|  | @ -639,10 +640,10 @@ vec4 secondary_fragment_color = vec4(0.0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Append the scissor test
 |     // Append the scissor test
 | ||||||
|     if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { |     if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) { | ||||||
|         out += "if ("; |         out += "if ("; | ||||||
|         // Negate the condition if we have to keep only the pixels outside the scissor box
 |         // Negate the condition if we have to keep only the pixels outside the scissor box
 | ||||||
|         if (state.scissor_test_mode == Regs::ScissorMode::Include) |         if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include) | ||||||
|             out += "!"; |             out += "!"; | ||||||
|         out += "(gl_FragCoord.x >= scissor_x1 && " |         out += "(gl_FragCoord.x >= scissor_x1 && " | ||||||
|                "gl_FragCoord.y >= scissor_y1 && " |                "gl_FragCoord.y >= scissor_y1 && " | ||||||
|  | @ -652,7 +653,7 @@ vec4 secondary_fragment_color = vec4(0.0); | ||||||
| 
 | 
 | ||||||
|     out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; |     out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; | ||||||
|     out += "float depth = z_over_w * depth_scale + depth_offset;\n"; |     out += "float depth = z_over_w * depth_scale + depth_offset;\n"; | ||||||
|     if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { |     if (state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) { | ||||||
|         out += "depth /= gl_FragCoord.w;\n"; |         out += "depth /= gl_FragCoord.w;\n"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ namespace Pica { | ||||||
| 
 | 
 | ||||||
| namespace Shader { | namespace Shader { | ||||||
| 
 | 
 | ||||||
| OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) { | OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) { | ||||||
|     // Setup output data
 |     // Setup output data
 | ||||||
|     union { |     union { | ||||||
|         OutputVertex ret{}; |         OutputVertex ret{}; | ||||||
|  | @ -33,16 +33,16 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer | ||||||
|     for (unsigned int i = 0; i < num_attributes; ++i) { |     for (unsigned int i = 0; i < num_attributes; ++i) { | ||||||
|         const auto& output_register_map = regs.vs_output_attributes[i]; |         const auto& output_register_map = regs.vs_output_attributes[i]; | ||||||
| 
 | 
 | ||||||
|         Regs::VSOutputAttributes::Semantic semantics[4] = { |         RasterizerRegs::VSOutputAttributes::Semantic semantics[4] = { | ||||||
|             output_register_map.map_x, output_register_map.map_y, output_register_map.map_z, |             output_register_map.map_x, output_register_map.map_y, output_register_map.map_z, | ||||||
|             output_register_map.map_w}; |             output_register_map.map_w}; | ||||||
| 
 | 
 | ||||||
|         for (unsigned comp = 0; comp < 4; ++comp) { |         for (unsigned comp = 0; comp < 4; ++comp) { | ||||||
|             Regs::VSOutputAttributes::Semantic semantic = semantics[comp]; |             RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp]; | ||||||
|             float24* out = &vertex_slots[semantic]; |             float24* out = &vertex_slots[semantic]; | ||||||
|             if (semantic < vertex_slots.size()) { |             if (semantic < vertex_slots.size()) { | ||||||
|                 *out = input.attr[i][comp]; |                 *out = input.attr[i][comp]; | ||||||
|             } else if (semantic != Regs::VSOutputAttributes::INVALID) { |             } else if (semantic != RasterizerRegs::VSOutputAttributes::INVALID) { | ||||||
|                 LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic); |                 LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -39,19 +39,19 @@ struct OutputVertex { | ||||||
|     INSERT_PADDING_WORDS(1); |     INSERT_PADDING_WORDS(1); | ||||||
|     Math::Vec2<float24> tc2; |     Math::Vec2<float24> tc2; | ||||||
| 
 | 
 | ||||||
|     static OutputVertex FromAttributeBuffer(const Regs& regs, AttributeBuffer& output); |     static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& output); | ||||||
| }; | }; | ||||||
| #define ASSERT_POS(var, pos)                                                                       \ | #define ASSERT_POS(var, pos)                                                                       \ | ||||||
|     static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong "       \ |     static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong "       \ | ||||||
|                                                                         "offset.") |                                                                         "offset.") | ||||||
| ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X); | ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X); | ||||||
| ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X); | ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X); | ||||||
| ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R); | ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R); | ||||||
| ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U); | ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U); | ||||||
| ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U); | ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U); | ||||||
| ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W); | ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W); | ||||||
| ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X); | ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X); | ||||||
| ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U); | ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U); | ||||||
| #undef ASSERT_POS | #undef ASSERT_POS | ||||||
| static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | ||||||
| static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); | static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue