mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #2482 from yuriks/pica-refactor
Split up monolithic Regs struct
This commit is contained in:
		
						commit
						2889372e47
					
				
					 37 changed files with 2635 additions and 2427 deletions
				
			
		|  | @ -5,6 +5,7 @@ set(SRCS | |||
|             pica.cpp | ||||
|             primitive_assembly.cpp | ||||
|             rasterizer.cpp | ||||
|             regs.cpp | ||||
|             renderer_base.cpp | ||||
|             renderer_opengl/gl_rasterizer.cpp | ||||
|             renderer_opengl/gl_rasterizer_cache.cpp | ||||
|  | @ -32,6 +33,13 @@ set(HEADERS | |||
|             primitive_assembly.h | ||||
|             rasterizer.h | ||||
|             rasterizer_interface.h | ||||
|             regs.h | ||||
|             regs_framebuffer.h | ||||
|             regs_lighting.h | ||||
|             regs_pipeline.h | ||||
|             regs_rasterizer.h | ||||
|             regs_shader.h | ||||
|             regs_texturing.h | ||||
|             renderer_base.h | ||||
|             renderer_opengl/gl_rasterizer.h | ||||
|             renderer_opengl/gl_rasterizer_cache.h | ||||
|  |  | |||
|  | @ -12,10 +12,10 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/clipper.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/rasterizer.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| using Pica::Rasterizer::Vertex; | ||||
|  | @ -64,10 +64,10 @@ static void InitScreenCoordinates(Vertex& vtx) { | |||
|     } viewport; | ||||
| 
 | ||||
|     const auto& regs = g_state.regs; | ||||
|     viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x); | ||||
|     viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y); | ||||
|     viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x)); | ||||
|     viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y)); | ||||
|     viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x); | ||||
|     viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y); | ||||
|     viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x)); | ||||
|     viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y)); | ||||
| 
 | ||||
|     float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; | ||||
|     vtx.color *= inv_w; | ||||
|  |  | |||
|  | @ -16,11 +16,11 @@ | |||
| #include "core/tracer/recorder.h" | ||||
| #include "video_core/command_processor.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/vertex_loader.h" | ||||
|  | @ -74,23 +74,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|         Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); | ||||
|         break; | ||||
| 
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): | ||||
|         g_state.primitive_assembler.Reconfigure(regs.triangle_topology); | ||||
|     case PICA_REG_INDEX(pipeline.triangle_topology): | ||||
|         g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology); | ||||
|         break; | ||||
| 
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): | ||||
|     case PICA_REG_INDEX(pipeline.restart_primitive): | ||||
|         g_state.primitive_assembler.Reset(); | ||||
|         break; | ||||
| 
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): | ||||
|     case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index): | ||||
|         g_state.immediate.current_attribute = 0; | ||||
|         default_attr_counter = 0; | ||||
|         break; | ||||
| 
 | ||||
|     // Load default vertex input attributes
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): | ||||
|     case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): | ||||
|     case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): { | ||||
|     case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233): | ||||
|     case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234): | ||||
|     case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): { | ||||
|         // TODO: Does actual hardware indeed keep an intermediate buffer or does
 | ||||
|         //       it directly write the values?
 | ||||
|         default_attr_write_buffer[default_attr_counter++] = value; | ||||
|  | @ -102,7 +102,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|         if (default_attr_counter >= 3) { | ||||
|             default_attr_counter = 0; | ||||
| 
 | ||||
|             auto& setup = regs.vs_default_attributes_setup; | ||||
|             auto& setup = regs.pipeline.vs_default_attributes_setup; | ||||
| 
 | ||||
|             if (setup.index >= 16) { | ||||
|                 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); | ||||
|  | @ -137,7 +137,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 
 | ||||
|                 immediate_input.attr[immediate_attribute_id] = attribute; | ||||
| 
 | ||||
|                 if (immediate_attribute_id < regs.max_input_attrib_index) { | ||||
|                 if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) { | ||||
|                     immediate_attribute_id += 1; | ||||
|                 } else { | ||||
|                     MICROPROFILE_SCOPE(GPU_Drawing); | ||||
|  | @ -165,15 +165,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|                     }; | ||||
| 
 | ||||
|                     g_state.primitive_assembler.SubmitVertex( | ||||
|                         Shader::OutputVertex::FromAttributeBuffer(regs, output), AddTriangle); | ||||
|                         Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output), | ||||
|                         AddTriangle); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case PICA_REG_INDEX(gpu_mode): | ||||
|         if (regs.gpu_mode == Regs::GPUMode::Configuring) { | ||||
|     case PICA_REG_INDEX(pipeline.gpu_mode): | ||||
|         if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) { | ||||
|             MICROPROFILE_SCOPE(GPU_Drawing); | ||||
| 
 | ||||
|             // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
 | ||||
|  | @ -185,19 +186,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): | ||||
|     case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): { | ||||
|         unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); | ||||
|         u32* head_ptr = | ||||
|             (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); | ||||
|     case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c): | ||||
|     case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): { | ||||
|         unsigned index = | ||||
|             static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0])); | ||||
|         u32* head_ptr = (u32*)Memory::GetPhysicalPointer( | ||||
|             regs.pipeline.command_buffer.GetPhysicalAddress(index)); | ||||
|         g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; | ||||
|         g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); | ||||
|         g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     // It seems like these trigger vertex rendering
 | ||||
|     case PICA_REG_INDEX(trigger_draw): | ||||
|     case PICA_REG_INDEX(trigger_draw_indexed): { | ||||
|     case PICA_REG_INDEX(pipeline.trigger_draw): | ||||
|     case PICA_REG_INDEX(pipeline.trigger_draw_indexed): { | ||||
|         MICROPROFILE_SCOPE(GPU_Drawing); | ||||
| 
 | ||||
| #if PICA_LOG_TEV | ||||
|  | @ -209,13 +211,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|         // Processes information about internal vertex attributes to figure out how a vertex is
 | ||||
|         // loaded.
 | ||||
|         // Later, these can be compiled and cached.
 | ||||
|         const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress(); | ||||
|         VertexLoader loader(regs); | ||||
|         const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress(); | ||||
|         VertexLoader loader(regs.pipeline); | ||||
| 
 | ||||
|         // Load vertices
 | ||||
|         bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); | ||||
|         bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); | ||||
| 
 | ||||
|         const auto& index_info = regs.index_array; | ||||
|         const auto& index_info = regs.pipeline.index_array; | ||||
|         const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); | ||||
|         const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8); | ||||
|         bool index_u16 = index_info.format != 0; | ||||
|  | @ -224,13 +226,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 
 | ||||
|         if (g_debug_context && g_debug_context->recorder) { | ||||
|             for (int i = 0; i < 3; ++i) { | ||||
|                 const auto texture = regs.GetTextures()[i]; | ||||
|                 const auto texture = regs.texturing.GetTextures()[i]; | ||||
|                 if (!texture.enabled) | ||||
|                     continue; | ||||
| 
 | ||||
|                 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); | ||||
|                 g_debug_context->recorder->MemoryAccessed( | ||||
|                     texture_data, Pica::Regs::NibblesPerPixel(texture.format) * | ||||
|                     texture_data, Pica::TexturingRegs::NibblesPerPixel(texture.format) * | ||||
|                                       texture.config.width / 2 * texture.config.height, | ||||
|                     texture.config.GetPhysicalAddress()); | ||||
|             } | ||||
|  | @ -253,11 +255,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 
 | ||||
|         shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); | ||||
| 
 | ||||
|         for (unsigned int index = 0; index < regs.num_vertices; ++index) { | ||||
|         for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) { | ||||
|             // Indexed rendering doesn't use the start offset
 | ||||
|             unsigned int vertex = | ||||
|                 is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) | ||||
|                            : (index + regs.vertex_offset); | ||||
|                            : (index + regs.pipeline.vertex_offset); | ||||
| 
 | ||||
|             // -1 is a common special value used for primitive restart. Since it's unknown if
 | ||||
|             // the PICA supports it, and it would mess up the caching, guard against it here.
 | ||||
|  | @ -295,7 +297,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|                 shader_unit.WriteOutput(regs.vs, output); | ||||
| 
 | ||||
|                 // Retrieve vertex from register data
 | ||||
|                 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs, output); | ||||
|                 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output); | ||||
| 
 | ||||
|                 if (is_indexed) { | ||||
|                     vertex_cache[vertex_cache_pos] = output_vertex; | ||||
|  | @ -437,16 +439,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): { | ||||
|         g_state.fog.lut[regs.fog_lut_offset % 128].raw = value; | ||||
|         regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1); | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): { | ||||
|         g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value; | ||||
|         regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,10 +29,10 @@ | |||
| #include "common/math_util.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/texture/texture_decode.h" | ||||
|  | @ -88,9 +88,9 @@ std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global | |||
| 
 | ||||
| namespace DebugUtils { | ||||
| 
 | ||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||
| void DumpShader(const std::string& filename, const ShaderRegs& config, | ||||
|                 const Shader::ShaderSetup& setup, | ||||
|                 const Regs::VSOutputAttributes* output_attributes) { | ||||
|                 const RasterizerRegs::VSOutputAttributes* output_attributes) { | ||||
|     struct StuffToWrite { | ||||
|         const u8* pointer; | ||||
|         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.
 | ||||
|     std::vector<OutputRegisterInfo> output_info_table; | ||||
|     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!
 | ||||
|         //       Once we know that, this code probably will not make much sense anymore.
 | ||||
|  | @ -331,7 +331,7 @@ static void FlushIOFile(png_structp png_ptr) { | |||
| } | ||||
| #endif | ||||
| 
 | ||||
| void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | ||||
| void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data) { | ||||
| #ifndef HAVE_PNG | ||||
|     return; | ||||
| #else | ||||
|  | @ -396,7 +396,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
|             info.width = texture_config.width; | ||||
|             info.height = texture_config.height; | ||||
|             info.stride = row_stride; | ||||
|             info.format = g_state.regs.texture0_format; | ||||
|             info.format = g_state.regs.texturing.texture0_format; | ||||
|             Math::Vec4<u8> texture_color = Pica::Texture::LookupTexture(data, x, y, info); | ||||
|             buf[3 * x + y * row_stride] = texture_color.r(); | ||||
|             buf[3 * x + y * row_stride + 1] = texture_color.g(); | ||||
|  | @ -434,8 +434,10 @@ static std::string ReplacePattern(const std::string& input, const std::string& p | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) { | ||||
|     using Source = Pica::Regs::TevStageConfig::Source; | ||||
| static std::string GetTevStageConfigSourceString( | ||||
|     const TexturingRegs::TevStageConfig::Source& source) { | ||||
| 
 | ||||
|     using Source = TexturingRegs::TevStageConfig::Source; | ||||
|     static const std::map<Source, std::string> source_map = { | ||||
|         {Source::PrimaryColor, "PrimaryColor"}, | ||||
|         {Source::PrimaryFragmentColor, "PrimaryFragmentColor"}, | ||||
|  | @ -457,9 +459,10 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi | |||
| } | ||||
| 
 | ||||
| static std::string GetTevStageConfigColorSourceString( | ||||
|     const Pica::Regs::TevStageConfig::Source& source, | ||||
|     const Pica::Regs::TevStageConfig::ColorModifier modifier) { | ||||
|     using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier; | ||||
|     const TexturingRegs::TevStageConfig::Source& source, | ||||
|     const TexturingRegs::TevStageConfig::ColorModifier modifier) { | ||||
| 
 | ||||
|     using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier; | ||||
|     static const std::map<ColorModifier, std::string> color_modifier_map = { | ||||
|         {ColorModifier::SourceColor, "%source.rgb"}, | ||||
|         {ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"}, | ||||
|  | @ -483,9 +486,10 @@ static std::string GetTevStageConfigColorSourceString( | |||
| } | ||||
| 
 | ||||
| static std::string GetTevStageConfigAlphaSourceString( | ||||
|     const Pica::Regs::TevStageConfig::Source& source, | ||||
|     const Pica::Regs::TevStageConfig::AlphaModifier modifier) { | ||||
|     using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier; | ||||
|     const TexturingRegs::TevStageConfig::Source& source, | ||||
|     const TexturingRegs::TevStageConfig::AlphaModifier modifier) { | ||||
| 
 | ||||
|     using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier; | ||||
|     static const std::map<AlphaModifier, std::string> alpha_modifier_map = { | ||||
|         {AlphaModifier::SourceAlpha, "%source.a"}, | ||||
|         {AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"}, | ||||
|  | @ -507,8 +511,9 @@ static std::string GetTevStageConfigAlphaSourceString( | |||
| } | ||||
| 
 | ||||
| static std::string GetTevStageConfigOperationString( | ||||
|     const Pica::Regs::TevStageConfig::Operation& operation) { | ||||
|     using Operation = Pica::Regs::TevStageConfig::Operation; | ||||
|     const TexturingRegs::TevStageConfig::Operation& operation) { | ||||
| 
 | ||||
|     using Operation = TexturingRegs::TevStageConfig::Operation; | ||||
|     static const std::map<Operation, std::string> combiner_map = { | ||||
|         {Operation::Replace, "%source1"}, | ||||
|         {Operation::Modulate, "(%source1 * %source2)"}, | ||||
|  | @ -528,7 +533,7 @@ static std::string GetTevStageConfigOperationString( | |||
|     return op_it->second; | ||||
| } | ||||
| 
 | ||||
| std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { | ||||
| std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage) { | ||||
|     auto op_str = GetTevStageConfigOperationString(tev_stage.color_op); | ||||
|     op_str = ReplacePattern( | ||||
|         op_str, "%source1", | ||||
|  | @ -541,7 +546,7 @@ std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfi | |||
|         GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3)); | ||||
| } | ||||
| 
 | ||||
| std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { | ||||
| std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage) { | ||||
|     auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op); | ||||
|     op_str = ReplacePattern( | ||||
|         op_str, "%source1", | ||||
|  | @ -554,7 +559,7 @@ std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfi | |||
|         GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3)); | ||||
| } | ||||
| 
 | ||||
| void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages) { | ||||
| void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages) { | ||||
|     std::string stage_info = "Tev setup:\n"; | ||||
|     for (size_t index = 0; index < stages.size(); ++index) { | ||||
|         const auto& tev_stage = stages[index]; | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs.h" | ||||
| 
 | ||||
| namespace CiTrace { | ||||
| class Recorder; | ||||
|  | @ -182,9 +182,9 @@ namespace DebugUtils { | |||
| #define PICA_DUMP_TEXTURES 0 | ||||
| #define PICA_LOG_TEV 0 | ||||
| 
 | ||||
| void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, | ||||
| void DumpShader(const std::string& filename, const ShaderRegs& config, | ||||
|                 const Shader::ShaderSetup& setup, | ||||
|                 const Regs::VSOutputAttributes* output_attributes); | ||||
|                 const RasterizerRegs::VSOutputAttributes* output_attributes); | ||||
| 
 | ||||
| // Utility class to log Pica commands.
 | ||||
| struct PicaTrace { | ||||
|  | @ -205,13 +205,13 @@ inline bool IsPicaTracing() { | |||
| void OnPicaRegWrite(PicaTrace::Write write); | ||||
| std::unique_ptr<PicaTrace> FinishPicaTracing(); | ||||
| 
 | ||||
| void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); | ||||
| void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data); | ||||
| 
 | ||||
| std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage); | ||||
| std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage); | ||||
| std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage); | ||||
| std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage); | ||||
| 
 | ||||
| /// Dumps the Tev stage config to log at trace level
 | ||||
| void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages); | ||||
| void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages); | ||||
| 
 | ||||
| /**
 | ||||
|  * Used in the vertex loader to merge access records. TODO: Investigate if actually useful. | ||||
|  |  | |||
|  | @ -3,497 +3,14 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <iterator> | ||||
| #include <unordered_map> | ||||
| #include <utility> | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/regs.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| State g_state; | ||||
| 
 | ||||
| static const std::pair<u16, const char*> register_names[] = { | ||||
|     {0x010, "GPUREG_FINALIZE"}, | ||||
| 
 | ||||
|     {0x040, "GPUREG_FACECULLING_CONFIG"}, | ||||
|     {0x041, "GPUREG_VIEWPORT_WIDTH"}, | ||||
|     {0x042, "GPUREG_VIEWPORT_INVW"}, | ||||
|     {0x043, "GPUREG_VIEWPORT_HEIGHT"}, | ||||
|     {0x044, "GPUREG_VIEWPORT_INVH"}, | ||||
| 
 | ||||
|     {0x047, "GPUREG_FRAGOP_CLIP"}, | ||||
|     {0x048, "GPUREG_FRAGOP_CLIP_DATA0"}, | ||||
|     {0x049, "GPUREG_FRAGOP_CLIP_DATA1"}, | ||||
|     {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"}, | ||||
|     {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"}, | ||||
| 
 | ||||
|     {0x04D, "GPUREG_DEPTHMAP_SCALE"}, | ||||
|     {0x04E, "GPUREG_DEPTHMAP_OFFSET"}, | ||||
|     {0x04F, "GPUREG_SH_OUTMAP_TOTAL"}, | ||||
|     {0x050, "GPUREG_SH_OUTMAP_O0"}, | ||||
|     {0x051, "GPUREG_SH_OUTMAP_O1"}, | ||||
|     {0x052, "GPUREG_SH_OUTMAP_O2"}, | ||||
|     {0x053, "GPUREG_SH_OUTMAP_O3"}, | ||||
|     {0x054, "GPUREG_SH_OUTMAP_O4"}, | ||||
|     {0x055, "GPUREG_SH_OUTMAP_O5"}, | ||||
|     {0x056, "GPUREG_SH_OUTMAP_O6"}, | ||||
| 
 | ||||
|     {0x061, "GPUREG_EARLYDEPTH_FUNC"}, | ||||
|     {0x062, "GPUREG_EARLYDEPTH_TEST1"}, | ||||
|     {0x063, "GPUREG_EARLYDEPTH_CLEAR"}, | ||||
|     {0x064, "GPUREG_SH_OUTATTR_MODE"}, | ||||
|     {0x065, "GPUREG_SCISSORTEST_MODE"}, | ||||
|     {0x066, "GPUREG_SCISSORTEST_POS"}, | ||||
|     {0x067, "GPUREG_SCISSORTEST_DIM"}, | ||||
|     {0x068, "GPUREG_VIEWPORT_XY"}, | ||||
| 
 | ||||
|     {0x06A, "GPUREG_EARLYDEPTH_DATA"}, | ||||
| 
 | ||||
|     {0x06D, "GPUREG_DEPTHMAP_ENABLE"}, | ||||
|     {0x06E, "GPUREG_RENDERBUF_DIM"}, | ||||
|     {0x06F, "GPUREG_SH_OUTATTR_CLOCK"}, | ||||
| 
 | ||||
|     {0x080, "GPUREG_TEXUNIT_CONFIG"}, | ||||
|     {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"}, | ||||
|     {0x082, "GPUREG_TEXUNIT0_DIM"}, | ||||
|     {0x083, "GPUREG_TEXUNIT0_PARAM"}, | ||||
|     {0x084, "GPUREG_TEXUNIT0_LOD"}, | ||||
|     {0x085, "GPUREG_TEXUNIT0_ADDR1"}, | ||||
|     {0x086, "GPUREG_TEXUNIT0_ADDR2"}, | ||||
|     {0x087, "GPUREG_TEXUNIT0_ADDR3"}, | ||||
|     {0x088, "GPUREG_TEXUNIT0_ADDR4"}, | ||||
|     {0x089, "GPUREG_TEXUNIT0_ADDR5"}, | ||||
|     {0x08A, "GPUREG_TEXUNIT0_ADDR6"}, | ||||
|     {0x08B, "GPUREG_TEXUNIT0_SHADOW"}, | ||||
| 
 | ||||
|     {0x08E, "GPUREG_TEXUNIT0_TYPE"}, | ||||
|     {0x08F, "GPUREG_LIGHTING_ENABLE0"}, | ||||
| 
 | ||||
|     {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"}, | ||||
|     {0x092, "GPUREG_TEXUNIT1_DIM"}, | ||||
|     {0x093, "GPUREG_TEXUNIT1_PARAM"}, | ||||
|     {0x094, "GPUREG_TEXUNIT1_LOD"}, | ||||
|     {0x095, "GPUREG_TEXUNIT1_ADDR"}, | ||||
|     {0x096, "GPUREG_TEXUNIT1_TYPE"}, | ||||
| 
 | ||||
|     {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"}, | ||||
|     {0x09A, "GPUREG_TEXUNIT2_DIM"}, | ||||
|     {0x09B, "GPUREG_TEXUNIT2_PARAM"}, | ||||
|     {0x09C, "GPUREG_TEXUNIT2_LOD"}, | ||||
|     {0x09D, "GPUREG_TEXUNIT2_ADDR"}, | ||||
|     {0x09E, "GPUREG_TEXUNIT2_TYPE"}, | ||||
| 
 | ||||
|     {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"}, | ||||
|     {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"}, | ||||
|     {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"}, | ||||
|     {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"}, | ||||
|     {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"}, | ||||
|     {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"}, | ||||
| 
 | ||||
|     {0x0AF, "GPUREG_PROCTEX_LUT"}, | ||||
|     {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"}, | ||||
|     {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"}, | ||||
|     {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"}, | ||||
|     {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"}, | ||||
|     {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"}, | ||||
|     {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"}, | ||||
|     {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"}, | ||||
|     {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"}, | ||||
| 
 | ||||
|     {0x0C0, "GPUREG_TEXENV0_SOURCE"}, | ||||
|     {0x0C1, "GPUREG_TEXENV0_OPERAND"}, | ||||
|     {0x0C2, "GPUREG_TEXENV0_COMBINER"}, | ||||
|     {0x0C3, "GPUREG_TEXENV0_COLOR"}, | ||||
|     {0x0C4, "GPUREG_TEXENV0_SCALE"}, | ||||
| 
 | ||||
|     {0x0C8, "GPUREG_TEXENV1_SOURCE"}, | ||||
|     {0x0C9, "GPUREG_TEXENV1_OPERAND"}, | ||||
|     {0x0CA, "GPUREG_TEXENV1_COMBINER"}, | ||||
|     {0x0CB, "GPUREG_TEXENV1_COLOR"}, | ||||
|     {0x0CC, "GPUREG_TEXENV1_SCALE"}, | ||||
| 
 | ||||
|     {0x0D0, "GPUREG_TEXENV2_SOURCE"}, | ||||
|     {0x0D1, "GPUREG_TEXENV2_OPERAND"}, | ||||
|     {0x0D2, "GPUREG_TEXENV2_COMBINER"}, | ||||
|     {0x0D3, "GPUREG_TEXENV2_COLOR"}, | ||||
|     {0x0D4, "GPUREG_TEXENV2_SCALE"}, | ||||
| 
 | ||||
|     {0x0D8, "GPUREG_TEXENV3_SOURCE"}, | ||||
|     {0x0D9, "GPUREG_TEXENV3_OPERAND"}, | ||||
|     {0x0DA, "GPUREG_TEXENV3_COMBINER"}, | ||||
|     {0x0DB, "GPUREG_TEXENV3_COLOR"}, | ||||
|     {0x0DC, "GPUREG_TEXENV3_SCALE"}, | ||||
| 
 | ||||
|     {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"}, | ||||
|     {0x0E1, "GPUREG_FOG_COLOR"}, | ||||
| 
 | ||||
|     {0x0E4, "GPUREG_GAS_ATTENUATION"}, | ||||
|     {0x0E5, "GPUREG_GAS_ACCMAX"}, | ||||
|     {0x0E6, "GPUREG_FOG_LUT_INDEX"}, | ||||
| 
 | ||||
|     {0x0E8, "GPUREG_FOG_LUT_DATA0"}, | ||||
|     {0x0E9, "GPUREG_FOG_LUT_DATA1"}, | ||||
|     {0x0EA, "GPUREG_FOG_LUT_DATA2"}, | ||||
|     {0x0EB, "GPUREG_FOG_LUT_DATA3"}, | ||||
|     {0x0EC, "GPUREG_FOG_LUT_DATA4"}, | ||||
|     {0x0ED, "GPUREG_FOG_LUT_DATA5"}, | ||||
|     {0x0EE, "GPUREG_FOG_LUT_DATA6"}, | ||||
|     {0x0EF, "GPUREG_FOG_LUT_DATA7"}, | ||||
|     {0x0F0, "GPUREG_TEXENV4_SOURCE"}, | ||||
|     {0x0F1, "GPUREG_TEXENV4_OPERAND"}, | ||||
|     {0x0F2, "GPUREG_TEXENV4_COMBINER"}, | ||||
|     {0x0F3, "GPUREG_TEXENV4_COLOR"}, | ||||
|     {0x0F4, "GPUREG_TEXENV4_SCALE"}, | ||||
| 
 | ||||
|     {0x0F8, "GPUREG_TEXENV5_SOURCE"}, | ||||
|     {0x0F9, "GPUREG_TEXENV5_OPERAND"}, | ||||
|     {0x0FA, "GPUREG_TEXENV5_COMBINER"}, | ||||
|     {0x0FB, "GPUREG_TEXENV5_COLOR"}, | ||||
|     {0x0FC, "GPUREG_TEXENV5_SCALE"}, | ||||
|     {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"}, | ||||
| 
 | ||||
|     {0x100, "GPUREG_COLOR_OPERATION"}, | ||||
|     {0x101, "GPUREG_BLEND_FUNC"}, | ||||
|     {0x102, "GPUREG_LOGIC_OP"}, | ||||
|     {0x103, "GPUREG_BLEND_COLOR"}, | ||||
|     {0x104, "GPUREG_FRAGOP_ALPHA_TEST"}, | ||||
|     {0x105, "GPUREG_STENCIL_TEST"}, | ||||
|     {0x106, "GPUREG_STENCIL_OP"}, | ||||
|     {0x107, "GPUREG_DEPTH_COLOR_MASK"}, | ||||
| 
 | ||||
|     {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"}, | ||||
|     {0x111, "GPUREG_FRAMEBUFFER_FLUSH"}, | ||||
|     {0x112, "GPUREG_COLORBUFFER_READ"}, | ||||
|     {0x113, "GPUREG_COLORBUFFER_WRITE"}, | ||||
|     {0x114, "GPUREG_DEPTHBUFFER_READ"}, | ||||
|     {0x115, "GPUREG_DEPTHBUFFER_WRITE"}, | ||||
|     {0x116, "GPUREG_DEPTHBUFFER_FORMAT"}, | ||||
|     {0x117, "GPUREG_COLORBUFFER_FORMAT"}, | ||||
|     {0x118, "GPUREG_EARLYDEPTH_TEST2"}, | ||||
| 
 | ||||
|     {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"}, | ||||
|     {0x11C, "GPUREG_DEPTHBUFFER_LOC"}, | ||||
|     {0x11D, "GPUREG_COLORBUFFER_LOC"}, | ||||
|     {0x11E, "GPUREG_FRAMEBUFFER_DIM"}, | ||||
| 
 | ||||
|     {0x120, "GPUREG_GAS_LIGHT_XY"}, | ||||
|     {0x121, "GPUREG_GAS_LIGHT_Z"}, | ||||
|     {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"}, | ||||
|     {0x123, "GPUREG_GAS_LUT_INDEX"}, | ||||
|     {0x124, "GPUREG_GAS_LUT_DATA"}, | ||||
| 
 | ||||
|     {0x126, "GPUREG_GAS_DELTAZ_DEPTH"}, | ||||
| 
 | ||||
|     {0x130, "GPUREG_FRAGOP_SHADOW"}, | ||||
| 
 | ||||
|     {0x140, "GPUREG_LIGHT0_SPECULAR0"}, | ||||
|     {0x141, "GPUREG_LIGHT0_SPECULAR1"}, | ||||
|     {0x142, "GPUREG_LIGHT0_DIFFUSE"}, | ||||
|     {0x143, "GPUREG_LIGHT0_AMBIENT"}, | ||||
|     {0x144, "GPUREG_LIGHT0_XY"}, | ||||
|     {0x145, "GPUREG_LIGHT0_Z"}, | ||||
|     {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"}, | ||||
|     {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x149, "GPUREG_LIGHT0_CONFIG"}, | ||||
|     {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"}, | ||||
|     {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x150, "GPUREG_LIGHT1_SPECULAR0"}, | ||||
|     {0x151, "GPUREG_LIGHT1_SPECULAR1"}, | ||||
|     {0x152, "GPUREG_LIGHT1_DIFFUSE"}, | ||||
|     {0x153, "GPUREG_LIGHT1_AMBIENT"}, | ||||
|     {0x154, "GPUREG_LIGHT1_XY"}, | ||||
|     {0x155, "GPUREG_LIGHT1_Z"}, | ||||
|     {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"}, | ||||
|     {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x159, "GPUREG_LIGHT1_CONFIG"}, | ||||
|     {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"}, | ||||
|     {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x160, "GPUREG_LIGHT2_SPECULAR0"}, | ||||
|     {0x161, "GPUREG_LIGHT2_SPECULAR1"}, | ||||
|     {0x162, "GPUREG_LIGHT2_DIFFUSE"}, | ||||
|     {0x163, "GPUREG_LIGHT2_AMBIENT"}, | ||||
|     {0x164, "GPUREG_LIGHT2_XY"}, | ||||
|     {0x165, "GPUREG_LIGHT2_Z"}, | ||||
|     {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"}, | ||||
|     {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x169, "GPUREG_LIGHT2_CONFIG"}, | ||||
|     {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"}, | ||||
|     {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x170, "GPUREG_LIGHT3_SPECULAR0"}, | ||||
|     {0x171, "GPUREG_LIGHT3_SPECULAR1"}, | ||||
|     {0x172, "GPUREG_LIGHT3_DIFFUSE"}, | ||||
|     {0x173, "GPUREG_LIGHT3_AMBIENT"}, | ||||
|     {0x174, "GPUREG_LIGHT3_XY"}, | ||||
|     {0x175, "GPUREG_LIGHT3_Z"}, | ||||
|     {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"}, | ||||
|     {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x179, "GPUREG_LIGHT3_CONFIG"}, | ||||
|     {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"}, | ||||
|     {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x180, "GPUREG_LIGHT4_SPECULAR0"}, | ||||
|     {0x181, "GPUREG_LIGHT4_SPECULAR1"}, | ||||
|     {0x182, "GPUREG_LIGHT4_DIFFUSE"}, | ||||
|     {0x183, "GPUREG_LIGHT4_AMBIENT"}, | ||||
|     {0x184, "GPUREG_LIGHT4_XY"}, | ||||
|     {0x185, "GPUREG_LIGHT4_Z"}, | ||||
|     {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"}, | ||||
|     {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x189, "GPUREG_LIGHT4_CONFIG"}, | ||||
|     {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"}, | ||||
|     {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x190, "GPUREG_LIGHT5_SPECULAR0"}, | ||||
|     {0x191, "GPUREG_LIGHT5_SPECULAR1"}, | ||||
|     {0x192, "GPUREG_LIGHT5_DIFFUSE"}, | ||||
|     {0x193, "GPUREG_LIGHT5_AMBIENT"}, | ||||
|     {0x194, "GPUREG_LIGHT5_XY"}, | ||||
|     {0x195, "GPUREG_LIGHT5_Z"}, | ||||
|     {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"}, | ||||
|     {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x199, "GPUREG_LIGHT5_CONFIG"}, | ||||
|     {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"}, | ||||
|     {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1A0, "GPUREG_LIGHT6_SPECULAR0"}, | ||||
|     {0x1A1, "GPUREG_LIGHT6_SPECULAR1"}, | ||||
|     {0x1A2, "GPUREG_LIGHT6_DIFFUSE"}, | ||||
|     {0x1A3, "GPUREG_LIGHT6_AMBIENT"}, | ||||
|     {0x1A4, "GPUREG_LIGHT6_XY"}, | ||||
|     {0x1A5, "GPUREG_LIGHT6_Z"}, | ||||
|     {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"}, | ||||
|     {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x1A9, "GPUREG_LIGHT6_CONFIG"}, | ||||
|     {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"}, | ||||
|     {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1B0, "GPUREG_LIGHT7_SPECULAR0"}, | ||||
|     {0x1B1, "GPUREG_LIGHT7_SPECULAR1"}, | ||||
|     {0x1B2, "GPUREG_LIGHT7_DIFFUSE"}, | ||||
|     {0x1B3, "GPUREG_LIGHT7_AMBIENT"}, | ||||
|     {0x1B4, "GPUREG_LIGHT7_XY"}, | ||||
|     {0x1B5, "GPUREG_LIGHT7_Z"}, | ||||
|     {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"}, | ||||
|     {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x1B9, "GPUREG_LIGHT7_CONFIG"}, | ||||
|     {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"}, | ||||
|     {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1C0, "GPUREG_LIGHTING_AMBIENT"}, | ||||
| 
 | ||||
|     {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"}, | ||||
|     {0x1C3, "GPUREG_LIGHTING_CONFIG0"}, | ||||
|     {0x1C4, "GPUREG_LIGHTING_CONFIG1"}, | ||||
|     {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"}, | ||||
|     {0x1C6, "GPUREG_LIGHTING_ENABLE1"}, | ||||
| 
 | ||||
|     {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"}, | ||||
|     {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"}, | ||||
|     {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"}, | ||||
|     {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"}, | ||||
|     {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"}, | ||||
|     {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"}, | ||||
|     {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"}, | ||||
|     {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"}, | ||||
|     {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"}, | ||||
|     {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"}, | ||||
|     {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"}, | ||||
| 
 | ||||
|     {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"}, | ||||
| 
 | ||||
|     {0x200, "GPUREG_ATTRIBBUFFERS_LOC"}, | ||||
|     {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"}, | ||||
|     {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"}, | ||||
|     {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"}, | ||||
|     {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"}, | ||||
|     {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"}, | ||||
|     {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"}, | ||||
|     {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"}, | ||||
|     {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"}, | ||||
|     {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"}, | ||||
|     {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"}, | ||||
|     {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"}, | ||||
|     {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"}, | ||||
|     {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"}, | ||||
|     {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"}, | ||||
|     {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"}, | ||||
|     {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"}, | ||||
|     {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"}, | ||||
|     {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"}, | ||||
|     {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"}, | ||||
|     {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"}, | ||||
|     {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"}, | ||||
|     {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"}, | ||||
|     {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"}, | ||||
|     {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"}, | ||||
|     {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"}, | ||||
|     {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"}, | ||||
|     {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"}, | ||||
|     {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"}, | ||||
|     {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"}, | ||||
|     {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"}, | ||||
|     {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"}, | ||||
|     {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"}, | ||||
|     {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"}, | ||||
|     {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"}, | ||||
|     {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"}, | ||||
|     {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"}, | ||||
|     {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"}, | ||||
|     {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"}, | ||||
|     {0x227, "GPUREG_INDEXBUFFER_CONFIG"}, | ||||
|     {0x228, "GPUREG_NUMVERTICES"}, | ||||
|     {0x229, "GPUREG_GEOSTAGE_CONFIG"}, | ||||
|     {0x22A, "GPUREG_VERTEX_OFFSET"}, | ||||
| 
 | ||||
|     {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"}, | ||||
|     {0x22E, "GPUREG_DRAWARRAYS"}, | ||||
|     {0x22F, "GPUREG_DRAWELEMENTS"}, | ||||
| 
 | ||||
|     {0x231, "GPUREG_VTX_FUNC"}, | ||||
|     {0x232, "GPUREG_FIXEDATTRIB_INDEX"}, | ||||
|     {0x233, "GPUREG_FIXEDATTRIB_DATA0"}, | ||||
|     {0x234, "GPUREG_FIXEDATTRIB_DATA1"}, | ||||
|     {0x235, "GPUREG_FIXEDATTRIB_DATA2"}, | ||||
| 
 | ||||
|     {0x238, "GPUREG_CMDBUF_SIZE0"}, | ||||
|     {0x239, "GPUREG_CMDBUF_SIZE1"}, | ||||
|     {0x23A, "GPUREG_CMDBUF_ADDR0"}, | ||||
|     {0x23B, "GPUREG_CMDBUF_ADDR1"}, | ||||
|     {0x23C, "GPUREG_CMDBUF_JUMP0"}, | ||||
|     {0x23D, "GPUREG_CMDBUF_JUMP1"}, | ||||
| 
 | ||||
|     {0x242, "GPUREG_VSH_NUM_ATTR"}, | ||||
| 
 | ||||
|     {0x244, "GPUREG_VSH_COM_MODE"}, | ||||
|     {0x245, "GPUREG_START_DRAW_FUNC0"}, | ||||
| 
 | ||||
|     {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"}, | ||||
| 
 | ||||
|     {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"}, | ||||
|     {0x252, "GPUREG_GSH_MISC0"}, | ||||
|     {0x253, "GPUREG_GEOSTAGE_CONFIG2"}, | ||||
|     {0x254, "GPUREG_GSH_MISC1"}, | ||||
| 
 | ||||
|     {0x25E, "GPUREG_PRIMITIVE_CONFIG"}, | ||||
|     {0x25F, "GPUREG_RESTART_PRIMITIVE"}, | ||||
| 
 | ||||
|     {0x280, "GPUREG_GSH_BOOLUNIFORM"}, | ||||
|     {0x281, "GPUREG_GSH_INTUNIFORM_I0"}, | ||||
|     {0x282, "GPUREG_GSH_INTUNIFORM_I1"}, | ||||
|     {0x283, "GPUREG_GSH_INTUNIFORM_I2"}, | ||||
|     {0x284, "GPUREG_GSH_INTUNIFORM_I3"}, | ||||
| 
 | ||||
|     {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"}, | ||||
|     {0x28A, "GPUREG_GSH_ENTRYPOINT"}, | ||||
|     {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"}, | ||||
|     {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"}, | ||||
|     {0x28D, "GPUREG_GSH_OUTMAP_MASK"}, | ||||
| 
 | ||||
|     {0x28F, "GPUREG_GSH_CODETRANSFER_END"}, | ||||
|     {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"}, | ||||
|     {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"}, | ||||
|     {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"}, | ||||
|     {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"}, | ||||
|     {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"}, | ||||
|     {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"}, | ||||
|     {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"}, | ||||
|     {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"}, | ||||
|     {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"}, | ||||
| 
 | ||||
|     {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"}, | ||||
|     {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"}, | ||||
|     {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"}, | ||||
|     {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"}, | ||||
|     {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"}, | ||||
|     {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"}, | ||||
|     {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"}, | ||||
|     {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"}, | ||||
|     {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"}, | ||||
| 
 | ||||
|     {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"}, | ||||
|     {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"}, | ||||
|     {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"}, | ||||
|     {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"}, | ||||
|     {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"}, | ||||
|     {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"}, | ||||
|     {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"}, | ||||
|     {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"}, | ||||
|     {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"}, | ||||
| 
 | ||||
|     {0x2B0, "GPUREG_VSH_BOOLUNIFORM"}, | ||||
|     {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"}, | ||||
|     {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"}, | ||||
|     {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"}, | ||||
|     {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"}, | ||||
| 
 | ||||
|     {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"}, | ||||
|     {0x2BA, "GPUREG_VSH_ENTRYPOINT"}, | ||||
|     {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"}, | ||||
|     {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"}, | ||||
|     {0x2BD, "GPUREG_VSH_OUTMAP_MASK"}, | ||||
| 
 | ||||
|     {0x2BF, "GPUREG_VSH_CODETRANSFER_END"}, | ||||
|     {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"}, | ||||
|     {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"}, | ||||
|     {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"}, | ||||
|     {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"}, | ||||
|     {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"}, | ||||
|     {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"}, | ||||
|     {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"}, | ||||
|     {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"}, | ||||
|     {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"}, | ||||
| 
 | ||||
|     {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"}, | ||||
|     {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"}, | ||||
|     {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"}, | ||||
|     {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"}, | ||||
|     {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"}, | ||||
|     {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"}, | ||||
|     {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"}, | ||||
|     {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"}, | ||||
|     {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"}, | ||||
| 
 | ||||
|     {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"}, | ||||
|     {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"}, | ||||
|     {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"}, | ||||
|     {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"}, | ||||
|     {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"}, | ||||
|     {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"}, | ||||
|     {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"}, | ||||
|     {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"}, | ||||
|     {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"}, | ||||
| }; | ||||
| 
 | ||||
| std::string Regs::GetCommandName(int index) { | ||||
|     static std::unordered_map<u32, const char*> map; | ||||
| 
 | ||||
|     if (map.empty()) { | ||||
|         map.insert(std::begin(register_names), std::end(register_names)); | ||||
|     } | ||||
| 
 | ||||
|     // Return empty string if no match is found
 | ||||
|     auto it = map.find(index); | ||||
|     if (it != map.end()) { | ||||
|         return it->second; | ||||
|     } else { | ||||
|         return std::string(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Init() { | ||||
|     g_state.Reset(); | ||||
| } | ||||
|  | @ -513,6 +30,6 @@ void State::Reset() { | |||
|     Zero(gs); | ||||
|     Zero(cmd_list); | ||||
|     Zero(immediate); | ||||
|     primitive_assembler.Reconfigure(Regs::TriangleTopology::List); | ||||
|     primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List); | ||||
| } | ||||
| } | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -7,8 +7,8 @@ | |||
| #include <array> | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
|  |  | |||
|  | @ -3,14 +3,14 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/primitive_assembly.h" | ||||
| #include "video_core/regs_pipeline.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| template <typename VertexType> | ||||
| PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology) | ||||
| PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology) | ||||
|     : topology(topology), buffer_index(0) {} | ||||
| 
 | ||||
| template <typename VertexType> | ||||
|  | @ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, | |||
|                                                   TriangleHandler triangle_handler) { | ||||
|     switch (topology) { | ||||
|     // TODO: Figure out what's different with TriangleTopology::Shader.
 | ||||
|     case Regs::TriangleTopology::List: | ||||
|     case Regs::TriangleTopology::Shader: | ||||
|     case PipelineRegs::TriangleTopology::List: | ||||
|     case PipelineRegs::TriangleTopology::Shader: | ||||
|         if (buffer_index < 2) { | ||||
|             buffer[buffer_index++] = vtx; | ||||
|         } else { | ||||
|  | @ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, | |||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::TriangleTopology::Strip: | ||||
|     case Regs::TriangleTopology::Fan: | ||||
|     case PipelineRegs::TriangleTopology::Strip: | ||||
|     case PipelineRegs::TriangleTopology::Fan: | ||||
|         if (strip_ready) | ||||
|             triangle_handler(buffer[0], buffer[1], vtx); | ||||
| 
 | ||||
|  | @ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx, | |||
| 
 | ||||
|         strip_ready |= (buffer_index == 1); | ||||
| 
 | ||||
|         if (topology == Regs::TriangleTopology::Strip) | ||||
|         if (topology == PipelineRegs::TriangleTopology::Strip) | ||||
|             buffer_index = !buffer_index; | ||||
|         else if (topology == Regs::TriangleTopology::Fan) | ||||
|         else if (topology == PipelineRegs::TriangleTopology::Fan) | ||||
|             buffer_index = 1; | ||||
|         break; | ||||
| 
 | ||||
|  | @ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() { | |||
| } | ||||
| 
 | ||||
| template <typename VertexType> | ||||
| void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) { | ||||
| void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) { | ||||
|     Reset(); | ||||
|     this->topology = topology; | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs_pipeline.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
|  | @ -18,7 +18,8 @@ struct PrimitiveAssembler { | |||
|     using TriangleHandler = | ||||
|         std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>; | ||||
| 
 | ||||
|     PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List); | ||||
|     PrimitiveAssembler( | ||||
|         PipelineRegs::TriangleTopology topology = PipelineRegs::TriangleTopology::List); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Queues a vertex, builds primitives from the vertex queue according to the given | ||||
|  | @ -36,10 +37,10 @@ struct PrimitiveAssembler { | |||
|     /**
 | ||||
|      * Reconfigures the PrimitiveAssembler to use a different triangle topology. | ||||
|      */ | ||||
|     void Reconfigure(Regs::TriangleTopology topology); | ||||
|     void Reconfigure(PipelineRegs::TriangleTopology topology); | ||||
| 
 | ||||
| private: | ||||
|     Regs::TriangleTopology topology; | ||||
|     PipelineRegs::TriangleTopology topology; | ||||
| 
 | ||||
|     int buffer_index; | ||||
|     VertexType buffer[2]; | ||||
|  |  | |||
|  | @ -16,10 +16,10 @@ | |||
| #include "core/hw/gpu.h" | ||||
| #include "core/memory.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/rasterizer.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/texture/texture_decode.h" | ||||
| #include "video_core/utils.h" | ||||
|  | @ -29,7 +29,7 @@ namespace Pica { | |||
| namespace Rasterizer { | ||||
| 
 | ||||
| static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | ||||
| 
 | ||||
|     // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
 | ||||
|  | @ -44,23 +44,23 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
|     u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.color_format) { | ||||
|     case Regs::ColorFormat::RGBA8: | ||||
|     case FramebufferRegs::ColorFormat::RGBA8: | ||||
|         Color::EncodeRGBA8(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB8: | ||||
|     case FramebufferRegs::ColorFormat::RGB8: | ||||
|         Color::EncodeRGB8(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB5A1: | ||||
|     case FramebufferRegs::ColorFormat::RGB5A1: | ||||
|         Color::EncodeRGB5A1(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB565: | ||||
|     case FramebufferRegs::ColorFormat::RGB565: | ||||
|         Color::EncodeRGB565(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGBA4: | ||||
|     case FramebufferRegs::ColorFormat::RGBA4: | ||||
|         Color::EncodeRGBA4(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| } | ||||
| 
 | ||||
| static const Math::Vec4<u8> GetPixel(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
|  | @ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
|     u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.color_format) { | ||||
|     case Regs::ColorFormat::RGBA8: | ||||
|     case FramebufferRegs::ColorFormat::RGBA8: | ||||
|         return Color::DecodeRGBA8(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB8: | ||||
|     case FramebufferRegs::ColorFormat::RGB8: | ||||
|         return Color::DecodeRGB8(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB5A1: | ||||
|     case FramebufferRegs::ColorFormat::RGB5A1: | ||||
|         return Color::DecodeRGB5A1(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB565: | ||||
|     case FramebufferRegs::ColorFormat::RGB565: | ||||
|         return Color::DecodeRGB565(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGBA4: | ||||
|     case FramebufferRegs::ColorFormat::RGBA4: | ||||
|         return Color::DecodeRGBA4(src_pixel); | ||||
| 
 | ||||
|     default: | ||||
|  | @ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static u32 GetDepth(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* src_pixel = depth_buffer + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D16: | ||||
|     case FramebufferRegs::DepthFormat::D16: | ||||
|         return Color::DecodeD16(src_pixel); | ||||
|     case Regs::DepthFormat::D24: | ||||
|     case FramebufferRegs::DepthFormat::D24: | ||||
|         return Color::DecodeD24(src_pixel); | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         return Color::DecodeD24S8(src_pixel).x; | ||||
|     default: | ||||
|         LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); | ||||
|  | @ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static u8 GetStencil(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* src_pixel = depth_buffer + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         return Color::DecodeD24S8(src_pixel).y; | ||||
| 
 | ||||
|     default: | ||||
|  | @ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static void SetDepth(int x, int y, u32 value) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* dst_pixel = depth_buffer + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D16: | ||||
|     case FramebufferRegs::DepthFormat::D16: | ||||
|         Color::EncodeD16(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::DepthFormat::D24: | ||||
|     case FramebufferRegs::DepthFormat::D24: | ||||
|         Color::EncodeD24(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         Color::EncodeD24X8(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) { | |||
| } | ||||
| 
 | ||||
| static void SetStencil(int x, int y, u8 value) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* dst_pixel = depth_buffer + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Pica::Regs::DepthFormat::D16: | ||||
|     case Pica::Regs::DepthFormat::D24: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D16: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D24: | ||||
|         // Nothing to do
 | ||||
|         break; | ||||
| 
 | ||||
|     case Pica::Regs::DepthFormat::D24S8: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D24S8: | ||||
|         Color::EncodeX24S8(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { | ||||
| static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) { | ||||
|     switch (action) { | ||||
|     case Regs::StencilAction::Keep: | ||||
|     case FramebufferRegs::StencilAction::Keep: | ||||
|         return old_stencil; | ||||
| 
 | ||||
|     case Regs::StencilAction::Zero: | ||||
|     case FramebufferRegs::StencilAction::Zero: | ||||
|         return 0; | ||||
| 
 | ||||
|     case Regs::StencilAction::Replace: | ||||
|     case FramebufferRegs::StencilAction::Replace: | ||||
|         return ref; | ||||
| 
 | ||||
|     case Regs::StencilAction::Increment: | ||||
|     case FramebufferRegs::StencilAction::Increment: | ||||
|         // Saturated increment
 | ||||
|         return std::min<u8>(old_stencil, 254) + 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::Decrement: | ||||
|     case FramebufferRegs::StencilAction::Decrement: | ||||
|         // Saturated decrement
 | ||||
|         return std::max<u8>(old_stencil, 1) - 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::Invert: | ||||
|     case FramebufferRegs::StencilAction::Invert: | ||||
|         return ~old_stencil; | ||||
| 
 | ||||
|     case Regs::StencilAction::IncrementWrap: | ||||
|     case FramebufferRegs::StencilAction::IncrementWrap: | ||||
|         return old_stencil + 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::DecrementWrap: | ||||
|     case FramebufferRegs::StencilAction::DecrementWrap: | ||||
|         return old_stencil - 1; | ||||
| 
 | ||||
|     default: | ||||
|  | @ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                                   ScreenToRasterizerCoordinates(v1.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
 | ||||
|         if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { | ||||
|             ProcessTriangleInternal(v0, v2, v1, true); | ||||
|             return; | ||||
|         } | ||||
|     } 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.
 | ||||
|             ProcessTriangleInternal(v0, v2, v1, true); | ||||
|             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}); | ||||
| 
 | ||||
|     // Convert the scissor box coordinates to 12.4 fixed point
 | ||||
|     u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4); | ||||
|     u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4); | ||||
|     u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4); | ||||
|     u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4); | ||||
|     // x2,y2 have +1 added to cover the entire sub-pixel area
 | ||||
|     u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); | ||||
|     u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); | ||||
|     u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 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
 | ||||
|         min_x = std::max(min_x, scissor_x1); | ||||
|         min_y = std::max(min_y, scissor_y1); | ||||
|  | @ -397,12 +397,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 
 | ||||
|     auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w); | ||||
| 
 | ||||
|     auto textures = regs.GetTextures(); | ||||
|     auto tev_stages = regs.GetTevStages(); | ||||
|     auto textures = regs.texturing.GetTextures(); | ||||
|     auto tev_stages = regs.texturing.GetTevStages(); | ||||
| 
 | ||||
|     bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && | ||||
|                                  g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; | ||||
|     const auto stencil_test = g_state.regs.output_merger.stencil_test; | ||||
|     bool stencil_action_enable = | ||||
|         g_state.regs.framebuffer.output_merger.stencil_test.enable && | ||||
|         g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8; | ||||
|     const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test; | ||||
| 
 | ||||
|     // Enter rasterization loop, starting at the center of the topleft bounding box corner.
 | ||||
|     // TODO: Not sure if looping through x first might be faster
 | ||||
|  | @ -411,7 +412,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
 | ||||
|             // 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) | ||||
|                     continue; | ||||
|             } | ||||
|  | @ -441,12 +442,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 
 | ||||
|             // Not fully accurate. About 3 bits in precision are missing.
 | ||||
|             // Z-Buffer (z / w * scale + offset)
 | ||||
|             float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); | ||||
|             float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); | ||||
|             float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32(); | ||||
|             float depth_offset = | ||||
|                 float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32(); | ||||
|             float depth = interpolated_z_over_w * depth_scale + depth_offset; | ||||
| 
 | ||||
|             // 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)
 | ||||
|                 depth *= interpolated_w_inverse.ToFloat32() * wsum; | ||||
|             } | ||||
|  | @ -513,9 +516,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 // TODO: Refactor so cubemaps and shadowmaps can be handled
 | ||||
|                 if (i == 0) { | ||||
|                     switch (texture.config.type) { | ||||
|                     case Regs::TextureConfig::Texture2D: | ||||
|                     case TexturingRegs::TextureConfig::Texture2D: | ||||
|                         break; | ||||
|                     case Regs::TextureConfig::Projection2D: { | ||||
|                     case TexturingRegs::TextureConfig::Projection2D: { | ||||
|                         auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w); | ||||
|                         u /= tc0_w; | ||||
|                         v /= tc0_w; | ||||
|  | @ -534,21 +537,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height))) | ||||
|                             .ToFloat32(); | ||||
| 
 | ||||
|                 static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, | ||||
|                                                     unsigned size) { | ||||
|                 static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode, | ||||
|                                                     int val, unsigned size) { | ||||
|                     switch (mode) { | ||||
|                     case Regs::TextureConfig::ClampToEdge: | ||||
|                     case TexturingRegs::TextureConfig::ClampToEdge: | ||||
|                         val = std::max(val, 0); | ||||
|                         val = std::min(val, (int)size - 1); | ||||
|                         return val; | ||||
| 
 | ||||
|                     case Regs::TextureConfig::ClampToBorder: | ||||
|                     case TexturingRegs::TextureConfig::ClampToBorder: | ||||
|                         return val; | ||||
| 
 | ||||
|                     case Regs::TextureConfig::Repeat: | ||||
|                     case TexturingRegs::TextureConfig::Repeat: | ||||
|                         return (int)((unsigned)val % size); | ||||
| 
 | ||||
|                     case Regs::TextureConfig::MirroredRepeat: { | ||||
|                     case TexturingRegs::TextureConfig::MirroredRepeat: { | ||||
|                         unsigned int coord = ((unsigned)val % (2 * size)); | ||||
|                         if (coord >= size) | ||||
|                             coord = 2 * size - 1 - coord; | ||||
|  | @ -562,9 +565,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                     } | ||||
|                 }; | ||||
| 
 | ||||
|                 if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && | ||||
|                 if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder && | ||||
|                      (s < 0 || static_cast<u32>(s) >= texture.config.width)) || | ||||
|                     (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && | ||||
|                     (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder && | ||||
|                      (t < 0 || static_cast<u32>(t) >= texture.config.height))) { | ||||
|                     auto border_color = texture.config.border_color; | ||||
|                     texture_color[i] = {border_color.r, border_color.g, border_color.b, | ||||
|  | @ -600,17 +603,19 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             Math::Vec4<u8> combiner_output; | ||||
|             Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0}; | ||||
|             Math::Vec4<u8> next_combiner_buffer = { | ||||
|                 regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, | ||||
|                 regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a, | ||||
|                 regs.texturing.tev_combiner_buffer_color.r, | ||||
|                 regs.texturing.tev_combiner_buffer_color.g, | ||||
|                 regs.texturing.tev_combiner_buffer_color.b, | ||||
|                 regs.texturing.tev_combiner_buffer_color.a, | ||||
|             }; | ||||
| 
 | ||||
|             for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); | ||||
|                  ++tev_stage_index) { | ||||
|                 const auto& tev_stage = tev_stages[tev_stage_index]; | ||||
|                 using Source = Regs::TevStageConfig::Source; | ||||
|                 using ColorModifier = Regs::TevStageConfig::ColorModifier; | ||||
|                 using AlphaModifier = Regs::TevStageConfig::AlphaModifier; | ||||
|                 using Operation = Regs::TevStageConfig::Operation; | ||||
|                 using Source = TexturingRegs::TevStageConfig::Source; | ||||
|                 using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier; | ||||
|                 using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier; | ||||
|                 using Operation = TexturingRegs::TevStageConfig::Operation; | ||||
| 
 | ||||
|                 auto GetSource = [&](Source source) -> Math::Vec4<u8> { | ||||
|                     switch (source) { | ||||
|  | @ -862,54 +867,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 
 | ||||
|                 combiner_buffer = next_combiner_buffer; | ||||
| 
 | ||||
|                 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor( | ||||
|                 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor( | ||||
|                         tev_stage_index)) { | ||||
|                     next_combiner_buffer.r() = combiner_output.r(); | ||||
|                     next_combiner_buffer.g() = combiner_output.g(); | ||||
|                     next_combiner_buffer.b() = combiner_output.b(); | ||||
|                 } | ||||
| 
 | ||||
|                 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha( | ||||
|                 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha( | ||||
|                         tev_stage_index)) { | ||||
|                     next_combiner_buffer.a() = combiner_output.a(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             const auto& output_merger = regs.output_merger; | ||||
|             const auto& output_merger = regs.framebuffer.output_merger; | ||||
|             // TODO: Does alpha testing happen before or after stencil?
 | ||||
|             if (output_merger.alpha_test.enable) { | ||||
|                 bool pass = false; | ||||
| 
 | ||||
|                 switch (output_merger.alpha_test.func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = combiner_output.a() == output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = combiner_output.a() != output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = combiner_output.a() < output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = combiner_output.a() <= output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = combiner_output.a() > output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = combiner_output.a() >= output_merger.alpha_test.ref; | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -922,16 +927,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             // Not fully accurate. We'd have to know what data type is used to
 | ||||
|             // store the depth etc. Using float for now until we know more
 | ||||
|             // about Pica datatypes
 | ||||
|             if (regs.fog_mode == Regs::FogMode::Fog) { | ||||
|             if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) { | ||||
|                 const Math::Vec3<u8> fog_color = { | ||||
|                     static_cast<u8>(regs.fog_color.r.Value()), | ||||
|                     static_cast<u8>(regs.fog_color.g.Value()), | ||||
|                     static_cast<u8>(regs.fog_color.b.Value()), | ||||
|                     static_cast<u8>(regs.texturing.fog_color.r.Value()), | ||||
|                     static_cast<u8>(regs.texturing.fog_color.g.Value()), | ||||
|                     static_cast<u8>(regs.texturing.fog_color.b.Value()), | ||||
|                 }; | ||||
| 
 | ||||
|                 // Get index into fog LUT
 | ||||
|                 float fog_index; | ||||
|                 if (g_state.regs.fog_flip) { | ||||
|                 if (g_state.regs.texturing.fog_flip) { | ||||
|                     fog_index = (1.0f - depth) * 128.0f; | ||||
|                 } else { | ||||
|                     fog_index = depth * 128.0f; | ||||
|  | @ -955,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             u8 old_stencil = 0; | ||||
| 
 | ||||
|             auto UpdateStencil = [stencil_test, x, y, | ||||
|                                   &old_stencil](Pica::Regs::StencilAction action) { | ||||
|                                   &old_stencil](Pica::FramebufferRegs::StencilAction action) { | ||||
|                 u8 new_stencil = | ||||
|                     PerformStencilAction(action, old_stencil, stencil_test.reference_value); | ||||
|                 if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) | ||||
|                 if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) | ||||
|                     SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | | ||||
|                                                    (old_stencil & ~stencil_test.write_mask)); | ||||
|             }; | ||||
|  | @ -970,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 
 | ||||
|                 bool pass = false; | ||||
|                 switch (stencil_test.func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = (ref == dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = (ref != dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = (ref < dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = (ref <= dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = (ref > dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = (ref >= dest); | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -1010,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             } | ||||
| 
 | ||||
|             // Convert float to integer
 | ||||
|             unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); | ||||
|             unsigned num_bits = | ||||
|                 FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format); | ||||
|             u32 z = (u32)(depth * ((1 << num_bits) - 1)); | ||||
| 
 | ||||
|             if (output_merger.depth_test_enable) { | ||||
|  | @ -1019,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 bool pass = false; | ||||
| 
 | ||||
|                 switch (output_merger.depth_test_func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = z == ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = z != ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = z < ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = z <= ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = z > ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = z >= ref_z; | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -1059,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable) | ||||
|             if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && | ||||
|                 output_merger.depth_write_enable) { | ||||
| 
 | ||||
|                 SetDepth(x >> 4, y >> 4, z); | ||||
|             } | ||||
| 
 | ||||
|             // The stencil depth_pass action is executed even if depth testing is disabled
 | ||||
|             if (stencil_action_enable) | ||||
|  | @ -1072,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             if (output_merger.alphablend_enable) { | ||||
|                 auto params = output_merger.alpha_blending; | ||||
| 
 | ||||
|                 auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { | ||||
|                 auto LookupFactor = [&](unsigned channel, | ||||
|                                         FramebufferRegs::BlendFactor factor) -> u8 { | ||||
|                     DEBUG_ASSERT(channel < 4); | ||||
| 
 | ||||
|                     const Math::Vec4<u8> blend_const = { | ||||
|  | @ -1083,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                     }; | ||||
| 
 | ||||
|                     switch (factor) { | ||||
|                     case Regs::BlendFactor::Zero: | ||||
|                     case FramebufferRegs::BlendFactor::Zero: | ||||
|                         return 0; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::One: | ||||
|                     case FramebufferRegs::BlendFactor::One: | ||||
|                         return 255; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceColor: | ||||
|                     case FramebufferRegs::BlendFactor::SourceColor: | ||||
|                         return combiner_output[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusSourceColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusSourceColor: | ||||
|                         return 255 - combiner_output[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::DestColor: | ||||
|                     case FramebufferRegs::BlendFactor::DestColor: | ||||
|                         return dest[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusDestColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusDestColor: | ||||
|                         return 255 - dest[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::SourceAlpha: | ||||
|                         return combiner_output.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusSourceAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusSourceAlpha: | ||||
|                         return 255 - combiner_output.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::DestAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::DestAlpha: | ||||
|                         return dest.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusDestAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusDestAlpha: | ||||
|                         return 255 - dest.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::ConstantColor: | ||||
|                     case FramebufferRegs::BlendFactor::ConstantColor: | ||||
|                         return blend_const[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusConstantColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusConstantColor: | ||||
|                         return 255 - blend_const[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::ConstantAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::ConstantAlpha: | ||||
|                         return blend_const.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusConstantAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusConstantAlpha: | ||||
|                         return 255 - blend_const.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceAlphaSaturate: | ||||
|                     case FramebufferRegs::BlendFactor::SourceAlphaSaturate: | ||||
|                         // Returns 1.0 for the alpha channel
 | ||||
|                         if (channel == 3) | ||||
|                             return 255; | ||||
|  | @ -1143,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 static auto EvaluateBlendEquation = []( | ||||
|                     const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, | ||||
|                     const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, | ||||
|                     Regs::BlendEquation equation) { | ||||
|                     FramebufferRegs::BlendEquation equation) { | ||||
| 
 | ||||
|                     Math::Vec4<int> result; | ||||
| 
 | ||||
|                     auto src_result = (src * srcfactor).Cast<int>(); | ||||
|                     auto dst_result = (dest * destfactor).Cast<int>(); | ||||
| 
 | ||||
|                     switch (equation) { | ||||
|                     case Regs::BlendEquation::Add: | ||||
|                     case FramebufferRegs::BlendEquation::Add: | ||||
|                         result = (src_result + dst_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::Subtract: | ||||
|                     case FramebufferRegs::BlendEquation::Subtract: | ||||
|                         result = (src_result - dst_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::ReverseSubtract: | ||||
|                     case FramebufferRegs::BlendEquation::ReverseSubtract: | ||||
|                         result = (dst_result - src_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     // TODO: How do these two actually work?
 | ||||
|                     //       OpenGL doesn't include the blend factors in the min/max computations,
 | ||||
|                     //       but is this what the 3DS actually does?
 | ||||
|                     case Regs::BlendEquation::Min: | ||||
|                     case FramebufferRegs::BlendEquation::Min: | ||||
|                         result.r() = std::min(src.r(), dest.r()); | ||||
|                         result.g() = std::min(src.g(), dest.g()); | ||||
|                         result.b() = std::min(src.b(), dest.b()); | ||||
|                         result.a() = std::min(src.a(), dest.a()); | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::Max: | ||||
|                     case FramebufferRegs::BlendEquation::Max: | ||||
|                         result.r() = std::max(src.r(), dest.r()); | ||||
|                         result.g() = std::max(src.g(), dest.g()); | ||||
|                         result.b() = std::max(src.b(), dest.b()); | ||||
|  | @ -1205,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                                                          dstfactor, params.blend_equation_a) | ||||
|                                        .a(); | ||||
|             } else { | ||||
|                 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { | ||||
|                 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 { | ||||
|                     switch (op) { | ||||
|                     case Regs::LogicOp::Clear: | ||||
|                     case FramebufferRegs::LogicOp::Clear: | ||||
|                         return 0; | ||||
| 
 | ||||
|                     case Regs::LogicOp::And: | ||||
|                     case FramebufferRegs::LogicOp::And: | ||||
|                         return src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndReverse: | ||||
|                     case FramebufferRegs::LogicOp::AndReverse: | ||||
|                         return src & ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Copy: | ||||
|                     case FramebufferRegs::LogicOp::Copy: | ||||
|                         return src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Set: | ||||
|                     case FramebufferRegs::LogicOp::Set: | ||||
|                         return 255; | ||||
| 
 | ||||
|                     case Regs::LogicOp::CopyInverted: | ||||
|                     case FramebufferRegs::LogicOp::CopyInverted: | ||||
|                         return ~src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::NoOp: | ||||
|                     case FramebufferRegs::LogicOp::NoOp: | ||||
|                         return dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Invert: | ||||
|                     case FramebufferRegs::LogicOp::Invert: | ||||
|                         return ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nand: | ||||
|                     case FramebufferRegs::LogicOp::Nand: | ||||
|                         return ~(src & dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Or: | ||||
|                     case FramebufferRegs::LogicOp::Or: | ||||
|                         return src | dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nor: | ||||
|                     case FramebufferRegs::LogicOp::Nor: | ||||
|                         return ~(src | dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Xor: | ||||
|                     case FramebufferRegs::LogicOp::Xor: | ||||
|                         return src ^ dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Equiv: | ||||
|                     case FramebufferRegs::LogicOp::Equiv: | ||||
|                         return ~(src ^ dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndInverted: | ||||
|                     case FramebufferRegs::LogicOp::AndInverted: | ||||
|                         return ~src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrReverse: | ||||
|                     case FramebufferRegs::LogicOp::OrReverse: | ||||
|                         return src | ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrInverted: | ||||
|                     case FramebufferRegs::LogicOp::OrInverted: | ||||
|                         return ~src | dest; | ||||
|                     } | ||||
|                 }; | ||||
|  | @ -1271,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 output_merger.alpha_enable ? blend_output.a() : dest.a(), | ||||
|             }; | ||||
| 
 | ||||
|             if (regs.framebuffer.allow_color_write != 0) | ||||
|             if (regs.framebuffer.framebuffer.allow_color_write != 0) | ||||
|                 DrawPixel(x >> 4, y >> 4, result); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										493
									
								
								src/video_core/regs.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										493
									
								
								src/video_core/regs.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,493 @@ | |||
| // Copyright 2015 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <iterator> | ||||
| #include <unordered_map> | ||||
| #include <utility> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/regs.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| static const std::pair<u16, const char*> register_names[] = { | ||||
|     {0x010, "GPUREG_FINALIZE"}, | ||||
| 
 | ||||
|     {0x040, "GPUREG_FACECULLING_CONFIG"}, | ||||
|     {0x041, "GPUREG_VIEWPORT_WIDTH"}, | ||||
|     {0x042, "GPUREG_VIEWPORT_INVW"}, | ||||
|     {0x043, "GPUREG_VIEWPORT_HEIGHT"}, | ||||
|     {0x044, "GPUREG_VIEWPORT_INVH"}, | ||||
| 
 | ||||
|     {0x047, "GPUREG_FRAGOP_CLIP"}, | ||||
|     {0x048, "GPUREG_FRAGOP_CLIP_DATA0"}, | ||||
|     {0x049, "GPUREG_FRAGOP_CLIP_DATA1"}, | ||||
|     {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"}, | ||||
|     {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"}, | ||||
| 
 | ||||
|     {0x04D, "GPUREG_DEPTHMAP_SCALE"}, | ||||
|     {0x04E, "GPUREG_DEPTHMAP_OFFSET"}, | ||||
|     {0x04F, "GPUREG_SH_OUTMAP_TOTAL"}, | ||||
|     {0x050, "GPUREG_SH_OUTMAP_O0"}, | ||||
|     {0x051, "GPUREG_SH_OUTMAP_O1"}, | ||||
|     {0x052, "GPUREG_SH_OUTMAP_O2"}, | ||||
|     {0x053, "GPUREG_SH_OUTMAP_O3"}, | ||||
|     {0x054, "GPUREG_SH_OUTMAP_O4"}, | ||||
|     {0x055, "GPUREG_SH_OUTMAP_O5"}, | ||||
|     {0x056, "GPUREG_SH_OUTMAP_O6"}, | ||||
| 
 | ||||
|     {0x061, "GPUREG_EARLYDEPTH_FUNC"}, | ||||
|     {0x062, "GPUREG_EARLYDEPTH_TEST1"}, | ||||
|     {0x063, "GPUREG_EARLYDEPTH_CLEAR"}, | ||||
|     {0x064, "GPUREG_SH_OUTATTR_MODE"}, | ||||
|     {0x065, "GPUREG_SCISSORTEST_MODE"}, | ||||
|     {0x066, "GPUREG_SCISSORTEST_POS"}, | ||||
|     {0x067, "GPUREG_SCISSORTEST_DIM"}, | ||||
|     {0x068, "GPUREG_VIEWPORT_XY"}, | ||||
| 
 | ||||
|     {0x06A, "GPUREG_EARLYDEPTH_DATA"}, | ||||
| 
 | ||||
|     {0x06D, "GPUREG_DEPTHMAP_ENABLE"}, | ||||
|     {0x06E, "GPUREG_RENDERBUF_DIM"}, | ||||
|     {0x06F, "GPUREG_SH_OUTATTR_CLOCK"}, | ||||
| 
 | ||||
|     {0x080, "GPUREG_TEXUNIT_CONFIG"}, | ||||
|     {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"}, | ||||
|     {0x082, "GPUREG_TEXUNIT0_DIM"}, | ||||
|     {0x083, "GPUREG_TEXUNIT0_PARAM"}, | ||||
|     {0x084, "GPUREG_TEXUNIT0_LOD"}, | ||||
|     {0x085, "GPUREG_TEXUNIT0_ADDR1"}, | ||||
|     {0x086, "GPUREG_TEXUNIT0_ADDR2"}, | ||||
|     {0x087, "GPUREG_TEXUNIT0_ADDR3"}, | ||||
|     {0x088, "GPUREG_TEXUNIT0_ADDR4"}, | ||||
|     {0x089, "GPUREG_TEXUNIT0_ADDR5"}, | ||||
|     {0x08A, "GPUREG_TEXUNIT0_ADDR6"}, | ||||
|     {0x08B, "GPUREG_TEXUNIT0_SHADOW"}, | ||||
| 
 | ||||
|     {0x08E, "GPUREG_TEXUNIT0_TYPE"}, | ||||
|     {0x08F, "GPUREG_LIGHTING_ENABLE0"}, | ||||
| 
 | ||||
|     {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"}, | ||||
|     {0x092, "GPUREG_TEXUNIT1_DIM"}, | ||||
|     {0x093, "GPUREG_TEXUNIT1_PARAM"}, | ||||
|     {0x094, "GPUREG_TEXUNIT1_LOD"}, | ||||
|     {0x095, "GPUREG_TEXUNIT1_ADDR"}, | ||||
|     {0x096, "GPUREG_TEXUNIT1_TYPE"}, | ||||
| 
 | ||||
|     {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"}, | ||||
|     {0x09A, "GPUREG_TEXUNIT2_DIM"}, | ||||
|     {0x09B, "GPUREG_TEXUNIT2_PARAM"}, | ||||
|     {0x09C, "GPUREG_TEXUNIT2_LOD"}, | ||||
|     {0x09D, "GPUREG_TEXUNIT2_ADDR"}, | ||||
|     {0x09E, "GPUREG_TEXUNIT2_TYPE"}, | ||||
| 
 | ||||
|     {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"}, | ||||
|     {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"}, | ||||
|     {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"}, | ||||
|     {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"}, | ||||
|     {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"}, | ||||
|     {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"}, | ||||
| 
 | ||||
|     {0x0AF, "GPUREG_PROCTEX_LUT"}, | ||||
|     {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"}, | ||||
|     {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"}, | ||||
|     {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"}, | ||||
|     {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"}, | ||||
|     {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"}, | ||||
|     {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"}, | ||||
|     {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"}, | ||||
|     {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"}, | ||||
| 
 | ||||
|     {0x0C0, "GPUREG_TEXENV0_SOURCE"}, | ||||
|     {0x0C1, "GPUREG_TEXENV0_OPERAND"}, | ||||
|     {0x0C2, "GPUREG_TEXENV0_COMBINER"}, | ||||
|     {0x0C3, "GPUREG_TEXENV0_COLOR"}, | ||||
|     {0x0C4, "GPUREG_TEXENV0_SCALE"}, | ||||
| 
 | ||||
|     {0x0C8, "GPUREG_TEXENV1_SOURCE"}, | ||||
|     {0x0C9, "GPUREG_TEXENV1_OPERAND"}, | ||||
|     {0x0CA, "GPUREG_TEXENV1_COMBINER"}, | ||||
|     {0x0CB, "GPUREG_TEXENV1_COLOR"}, | ||||
|     {0x0CC, "GPUREG_TEXENV1_SCALE"}, | ||||
| 
 | ||||
|     {0x0D0, "GPUREG_TEXENV2_SOURCE"}, | ||||
|     {0x0D1, "GPUREG_TEXENV2_OPERAND"}, | ||||
|     {0x0D2, "GPUREG_TEXENV2_COMBINER"}, | ||||
|     {0x0D3, "GPUREG_TEXENV2_COLOR"}, | ||||
|     {0x0D4, "GPUREG_TEXENV2_SCALE"}, | ||||
| 
 | ||||
|     {0x0D8, "GPUREG_TEXENV3_SOURCE"}, | ||||
|     {0x0D9, "GPUREG_TEXENV3_OPERAND"}, | ||||
|     {0x0DA, "GPUREG_TEXENV3_COMBINER"}, | ||||
|     {0x0DB, "GPUREG_TEXENV3_COLOR"}, | ||||
|     {0x0DC, "GPUREG_TEXENV3_SCALE"}, | ||||
| 
 | ||||
|     {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"}, | ||||
|     {0x0E1, "GPUREG_FOG_COLOR"}, | ||||
| 
 | ||||
|     {0x0E4, "GPUREG_GAS_ATTENUATION"}, | ||||
|     {0x0E5, "GPUREG_GAS_ACCMAX"}, | ||||
|     {0x0E6, "GPUREG_FOG_LUT_INDEX"}, | ||||
| 
 | ||||
|     {0x0E8, "GPUREG_FOG_LUT_DATA0"}, | ||||
|     {0x0E9, "GPUREG_FOG_LUT_DATA1"}, | ||||
|     {0x0EA, "GPUREG_FOG_LUT_DATA2"}, | ||||
|     {0x0EB, "GPUREG_FOG_LUT_DATA3"}, | ||||
|     {0x0EC, "GPUREG_FOG_LUT_DATA4"}, | ||||
|     {0x0ED, "GPUREG_FOG_LUT_DATA5"}, | ||||
|     {0x0EE, "GPUREG_FOG_LUT_DATA6"}, | ||||
|     {0x0EF, "GPUREG_FOG_LUT_DATA7"}, | ||||
|     {0x0F0, "GPUREG_TEXENV4_SOURCE"}, | ||||
|     {0x0F1, "GPUREG_TEXENV4_OPERAND"}, | ||||
|     {0x0F2, "GPUREG_TEXENV4_COMBINER"}, | ||||
|     {0x0F3, "GPUREG_TEXENV4_COLOR"}, | ||||
|     {0x0F4, "GPUREG_TEXENV4_SCALE"}, | ||||
| 
 | ||||
|     {0x0F8, "GPUREG_TEXENV5_SOURCE"}, | ||||
|     {0x0F9, "GPUREG_TEXENV5_OPERAND"}, | ||||
|     {0x0FA, "GPUREG_TEXENV5_COMBINER"}, | ||||
|     {0x0FB, "GPUREG_TEXENV5_COLOR"}, | ||||
|     {0x0FC, "GPUREG_TEXENV5_SCALE"}, | ||||
|     {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"}, | ||||
| 
 | ||||
|     {0x100, "GPUREG_COLOR_OPERATION"}, | ||||
|     {0x101, "GPUREG_BLEND_FUNC"}, | ||||
|     {0x102, "GPUREG_LOGIC_OP"}, | ||||
|     {0x103, "GPUREG_BLEND_COLOR"}, | ||||
|     {0x104, "GPUREG_FRAGOP_ALPHA_TEST"}, | ||||
|     {0x105, "GPUREG_STENCIL_TEST"}, | ||||
|     {0x106, "GPUREG_STENCIL_OP"}, | ||||
|     {0x107, "GPUREG_DEPTH_COLOR_MASK"}, | ||||
| 
 | ||||
|     {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"}, | ||||
|     {0x111, "GPUREG_FRAMEBUFFER_FLUSH"}, | ||||
|     {0x112, "GPUREG_COLORBUFFER_READ"}, | ||||
|     {0x113, "GPUREG_COLORBUFFER_WRITE"}, | ||||
|     {0x114, "GPUREG_DEPTHBUFFER_READ"}, | ||||
|     {0x115, "GPUREG_DEPTHBUFFER_WRITE"}, | ||||
|     {0x116, "GPUREG_DEPTHBUFFER_FORMAT"}, | ||||
|     {0x117, "GPUREG_COLORBUFFER_FORMAT"}, | ||||
|     {0x118, "GPUREG_EARLYDEPTH_TEST2"}, | ||||
| 
 | ||||
|     {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"}, | ||||
|     {0x11C, "GPUREG_DEPTHBUFFER_LOC"}, | ||||
|     {0x11D, "GPUREG_COLORBUFFER_LOC"}, | ||||
|     {0x11E, "GPUREG_FRAMEBUFFER_DIM"}, | ||||
| 
 | ||||
|     {0x120, "GPUREG_GAS_LIGHT_XY"}, | ||||
|     {0x121, "GPUREG_GAS_LIGHT_Z"}, | ||||
|     {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"}, | ||||
|     {0x123, "GPUREG_GAS_LUT_INDEX"}, | ||||
|     {0x124, "GPUREG_GAS_LUT_DATA"}, | ||||
| 
 | ||||
|     {0x126, "GPUREG_GAS_DELTAZ_DEPTH"}, | ||||
| 
 | ||||
|     {0x130, "GPUREG_FRAGOP_SHADOW"}, | ||||
| 
 | ||||
|     {0x140, "GPUREG_LIGHT0_SPECULAR0"}, | ||||
|     {0x141, "GPUREG_LIGHT0_SPECULAR1"}, | ||||
|     {0x142, "GPUREG_LIGHT0_DIFFUSE"}, | ||||
|     {0x143, "GPUREG_LIGHT0_AMBIENT"}, | ||||
|     {0x144, "GPUREG_LIGHT0_XY"}, | ||||
|     {0x145, "GPUREG_LIGHT0_Z"}, | ||||
|     {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"}, | ||||
|     {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x149, "GPUREG_LIGHT0_CONFIG"}, | ||||
|     {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"}, | ||||
|     {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x150, "GPUREG_LIGHT1_SPECULAR0"}, | ||||
|     {0x151, "GPUREG_LIGHT1_SPECULAR1"}, | ||||
|     {0x152, "GPUREG_LIGHT1_DIFFUSE"}, | ||||
|     {0x153, "GPUREG_LIGHT1_AMBIENT"}, | ||||
|     {0x154, "GPUREG_LIGHT1_XY"}, | ||||
|     {0x155, "GPUREG_LIGHT1_Z"}, | ||||
|     {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"}, | ||||
|     {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x159, "GPUREG_LIGHT1_CONFIG"}, | ||||
|     {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"}, | ||||
|     {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x160, "GPUREG_LIGHT2_SPECULAR0"}, | ||||
|     {0x161, "GPUREG_LIGHT2_SPECULAR1"}, | ||||
|     {0x162, "GPUREG_LIGHT2_DIFFUSE"}, | ||||
|     {0x163, "GPUREG_LIGHT2_AMBIENT"}, | ||||
|     {0x164, "GPUREG_LIGHT2_XY"}, | ||||
|     {0x165, "GPUREG_LIGHT2_Z"}, | ||||
|     {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"}, | ||||
|     {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x169, "GPUREG_LIGHT2_CONFIG"}, | ||||
|     {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"}, | ||||
|     {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x170, "GPUREG_LIGHT3_SPECULAR0"}, | ||||
|     {0x171, "GPUREG_LIGHT3_SPECULAR1"}, | ||||
|     {0x172, "GPUREG_LIGHT3_DIFFUSE"}, | ||||
|     {0x173, "GPUREG_LIGHT3_AMBIENT"}, | ||||
|     {0x174, "GPUREG_LIGHT3_XY"}, | ||||
|     {0x175, "GPUREG_LIGHT3_Z"}, | ||||
|     {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"}, | ||||
|     {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x179, "GPUREG_LIGHT3_CONFIG"}, | ||||
|     {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"}, | ||||
|     {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x180, "GPUREG_LIGHT4_SPECULAR0"}, | ||||
|     {0x181, "GPUREG_LIGHT4_SPECULAR1"}, | ||||
|     {0x182, "GPUREG_LIGHT4_DIFFUSE"}, | ||||
|     {0x183, "GPUREG_LIGHT4_AMBIENT"}, | ||||
|     {0x184, "GPUREG_LIGHT4_XY"}, | ||||
|     {0x185, "GPUREG_LIGHT4_Z"}, | ||||
|     {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"}, | ||||
|     {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x189, "GPUREG_LIGHT4_CONFIG"}, | ||||
|     {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"}, | ||||
|     {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x190, "GPUREG_LIGHT5_SPECULAR0"}, | ||||
|     {0x191, "GPUREG_LIGHT5_SPECULAR1"}, | ||||
|     {0x192, "GPUREG_LIGHT5_DIFFUSE"}, | ||||
|     {0x193, "GPUREG_LIGHT5_AMBIENT"}, | ||||
|     {0x194, "GPUREG_LIGHT5_XY"}, | ||||
|     {0x195, "GPUREG_LIGHT5_Z"}, | ||||
|     {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"}, | ||||
|     {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x199, "GPUREG_LIGHT5_CONFIG"}, | ||||
|     {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"}, | ||||
|     {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1A0, "GPUREG_LIGHT6_SPECULAR0"}, | ||||
|     {0x1A1, "GPUREG_LIGHT6_SPECULAR1"}, | ||||
|     {0x1A2, "GPUREG_LIGHT6_DIFFUSE"}, | ||||
|     {0x1A3, "GPUREG_LIGHT6_AMBIENT"}, | ||||
|     {0x1A4, "GPUREG_LIGHT6_XY"}, | ||||
|     {0x1A5, "GPUREG_LIGHT6_Z"}, | ||||
|     {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"}, | ||||
|     {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x1A9, "GPUREG_LIGHT6_CONFIG"}, | ||||
|     {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"}, | ||||
|     {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1B0, "GPUREG_LIGHT7_SPECULAR0"}, | ||||
|     {0x1B1, "GPUREG_LIGHT7_SPECULAR1"}, | ||||
|     {0x1B2, "GPUREG_LIGHT7_DIFFUSE"}, | ||||
|     {0x1B3, "GPUREG_LIGHT7_AMBIENT"}, | ||||
|     {0x1B4, "GPUREG_LIGHT7_XY"}, | ||||
|     {0x1B5, "GPUREG_LIGHT7_Z"}, | ||||
|     {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"}, | ||||
|     {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"}, | ||||
| 
 | ||||
|     {0x1B9, "GPUREG_LIGHT7_CONFIG"}, | ||||
|     {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"}, | ||||
|     {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"}, | ||||
| 
 | ||||
|     {0x1C0, "GPUREG_LIGHTING_AMBIENT"}, | ||||
| 
 | ||||
|     {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"}, | ||||
|     {0x1C3, "GPUREG_LIGHTING_CONFIG0"}, | ||||
|     {0x1C4, "GPUREG_LIGHTING_CONFIG1"}, | ||||
|     {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"}, | ||||
|     {0x1C6, "GPUREG_LIGHTING_ENABLE1"}, | ||||
| 
 | ||||
|     {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"}, | ||||
|     {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"}, | ||||
|     {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"}, | ||||
|     {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"}, | ||||
|     {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"}, | ||||
|     {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"}, | ||||
|     {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"}, | ||||
|     {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"}, | ||||
|     {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"}, | ||||
|     {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"}, | ||||
|     {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"}, | ||||
| 
 | ||||
|     {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"}, | ||||
| 
 | ||||
|     {0x200, "GPUREG_ATTRIBBUFFERS_LOC"}, | ||||
|     {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"}, | ||||
|     {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"}, | ||||
|     {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"}, | ||||
|     {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"}, | ||||
|     {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"}, | ||||
|     {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"}, | ||||
|     {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"}, | ||||
|     {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"}, | ||||
|     {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"}, | ||||
|     {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"}, | ||||
|     {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"}, | ||||
|     {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"}, | ||||
|     {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"}, | ||||
|     {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"}, | ||||
|     {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"}, | ||||
|     {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"}, | ||||
|     {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"}, | ||||
|     {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"}, | ||||
|     {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"}, | ||||
|     {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"}, | ||||
|     {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"}, | ||||
|     {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"}, | ||||
|     {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"}, | ||||
|     {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"}, | ||||
|     {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"}, | ||||
|     {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"}, | ||||
|     {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"}, | ||||
|     {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"}, | ||||
|     {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"}, | ||||
|     {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"}, | ||||
|     {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"}, | ||||
|     {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"}, | ||||
|     {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"}, | ||||
|     {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"}, | ||||
|     {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"}, | ||||
|     {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"}, | ||||
|     {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"}, | ||||
|     {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"}, | ||||
|     {0x227, "GPUREG_INDEXBUFFER_CONFIG"}, | ||||
|     {0x228, "GPUREG_NUMVERTICES"}, | ||||
|     {0x229, "GPUREG_GEOSTAGE_CONFIG"}, | ||||
|     {0x22A, "GPUREG_VERTEX_OFFSET"}, | ||||
| 
 | ||||
|     {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"}, | ||||
|     {0x22E, "GPUREG_DRAWARRAYS"}, | ||||
|     {0x22F, "GPUREG_DRAWELEMENTS"}, | ||||
| 
 | ||||
|     {0x231, "GPUREG_VTX_FUNC"}, | ||||
|     {0x232, "GPUREG_FIXEDATTRIB_INDEX"}, | ||||
|     {0x233, "GPUREG_FIXEDATTRIB_DATA0"}, | ||||
|     {0x234, "GPUREG_FIXEDATTRIB_DATA1"}, | ||||
|     {0x235, "GPUREG_FIXEDATTRIB_DATA2"}, | ||||
| 
 | ||||
|     {0x238, "GPUREG_CMDBUF_SIZE0"}, | ||||
|     {0x239, "GPUREG_CMDBUF_SIZE1"}, | ||||
|     {0x23A, "GPUREG_CMDBUF_ADDR0"}, | ||||
|     {0x23B, "GPUREG_CMDBUF_ADDR1"}, | ||||
|     {0x23C, "GPUREG_CMDBUF_JUMP0"}, | ||||
|     {0x23D, "GPUREG_CMDBUF_JUMP1"}, | ||||
| 
 | ||||
|     {0x242, "GPUREG_VSH_NUM_ATTR"}, | ||||
| 
 | ||||
|     {0x244, "GPUREG_VSH_COM_MODE"}, | ||||
|     {0x245, "GPUREG_START_DRAW_FUNC0"}, | ||||
| 
 | ||||
|     {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"}, | ||||
| 
 | ||||
|     {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"}, | ||||
|     {0x252, "GPUREG_GSH_MISC0"}, | ||||
|     {0x253, "GPUREG_GEOSTAGE_CONFIG2"}, | ||||
|     {0x254, "GPUREG_GSH_MISC1"}, | ||||
| 
 | ||||
|     {0x25E, "GPUREG_PRIMITIVE_CONFIG"}, | ||||
|     {0x25F, "GPUREG_RESTART_PRIMITIVE"}, | ||||
| 
 | ||||
|     {0x280, "GPUREG_GSH_BOOLUNIFORM"}, | ||||
|     {0x281, "GPUREG_GSH_INTUNIFORM_I0"}, | ||||
|     {0x282, "GPUREG_GSH_INTUNIFORM_I1"}, | ||||
|     {0x283, "GPUREG_GSH_INTUNIFORM_I2"}, | ||||
|     {0x284, "GPUREG_GSH_INTUNIFORM_I3"}, | ||||
| 
 | ||||
|     {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"}, | ||||
|     {0x28A, "GPUREG_GSH_ENTRYPOINT"}, | ||||
|     {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"}, | ||||
|     {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"}, | ||||
|     {0x28D, "GPUREG_GSH_OUTMAP_MASK"}, | ||||
| 
 | ||||
|     {0x28F, "GPUREG_GSH_CODETRANSFER_END"}, | ||||
|     {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"}, | ||||
|     {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"}, | ||||
|     {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"}, | ||||
|     {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"}, | ||||
|     {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"}, | ||||
|     {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"}, | ||||
|     {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"}, | ||||
|     {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"}, | ||||
|     {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"}, | ||||
| 
 | ||||
|     {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"}, | ||||
|     {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"}, | ||||
|     {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"}, | ||||
|     {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"}, | ||||
|     {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"}, | ||||
|     {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"}, | ||||
|     {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"}, | ||||
|     {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"}, | ||||
|     {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"}, | ||||
| 
 | ||||
|     {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"}, | ||||
|     {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"}, | ||||
|     {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"}, | ||||
|     {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"}, | ||||
|     {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"}, | ||||
|     {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"}, | ||||
|     {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"}, | ||||
|     {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"}, | ||||
|     {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"}, | ||||
| 
 | ||||
|     {0x2B0, "GPUREG_VSH_BOOLUNIFORM"}, | ||||
|     {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"}, | ||||
|     {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"}, | ||||
|     {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"}, | ||||
|     {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"}, | ||||
| 
 | ||||
|     {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"}, | ||||
|     {0x2BA, "GPUREG_VSH_ENTRYPOINT"}, | ||||
|     {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"}, | ||||
|     {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"}, | ||||
|     {0x2BD, "GPUREG_VSH_OUTMAP_MASK"}, | ||||
| 
 | ||||
|     {0x2BF, "GPUREG_VSH_CODETRANSFER_END"}, | ||||
|     {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"}, | ||||
|     {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"}, | ||||
|     {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"}, | ||||
|     {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"}, | ||||
|     {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"}, | ||||
|     {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"}, | ||||
|     {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"}, | ||||
|     {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"}, | ||||
|     {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"}, | ||||
| 
 | ||||
|     {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"}, | ||||
|     {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"}, | ||||
|     {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"}, | ||||
|     {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"}, | ||||
|     {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"}, | ||||
|     {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"}, | ||||
|     {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"}, | ||||
|     {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"}, | ||||
|     {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"}, | ||||
| 
 | ||||
|     {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"}, | ||||
|     {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"}, | ||||
|     {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"}, | ||||
|     {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"}, | ||||
|     {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"}, | ||||
|     {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"}, | ||||
|     {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"}, | ||||
|     {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"}, | ||||
|     {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"}, | ||||
| }; | ||||
| 
 | ||||
| std::string Regs::GetCommandName(int index) { | ||||
|     static std::unordered_map<u32, const char*> map; | ||||
| 
 | ||||
|     if (map.empty()) { | ||||
|         map.insert(std::begin(register_names), std::end(register_names)); | ||||
|     } | ||||
| 
 | ||||
|     // Return empty string if no match is found
 | ||||
|     auto it = map.find(index); | ||||
|     if (it != map.end()) { | ||||
|         return it->second; | ||||
|     } else { | ||||
|         return std::string(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										164
									
								
								src/video_core/regs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/video_core/regs.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,164 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
| #ifndef _MSC_VER | ||||
| #include <type_traits> // for std::enable_if | ||||
| #endif | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/regs_framebuffer.h" | ||||
| #include "video_core/regs_lighting.h" | ||||
| #include "video_core/regs_pipeline.h" | ||||
| #include "video_core/regs_rasterizer.h" | ||||
| #include "video_core/regs_shader.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| // Returns index corresponding to the Regs member labeled by field_name
 | ||||
| // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
 | ||||
| //       when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
 | ||||
| //       For details cf.
 | ||||
| //       https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
 | ||||
| //       Hopefully, this will be fixed sometime in the future.
 | ||||
| //       For lack of better alternatives, we currently hardcode the offsets when constant
 | ||||
| //       expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
 | ||||
| //       will then make sure the offsets indeed match the automatically calculated ones).
 | ||||
| #define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32)) | ||||
| #if defined(_MSC_VER) | ||||
| #define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index) | ||||
| #else | ||||
| // NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
 | ||||
| //       really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
 | ||||
| //       and then performs a (no-op) cast to size_t iff the second argument matches the expected
 | ||||
| //       field offset. Otherwise, the compiler will fail to compile this code.
 | ||||
| #define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index)                             \ | ||||
|     ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name),               \ | ||||
|                               size_t>::type)PICA_REG_INDEX(field_name)) | ||||
| #endif // _MSC_VER
 | ||||
| 
 | ||||
| struct Regs { | ||||
|     INSERT_PADDING_WORDS(0x10); | ||||
|     u32 trigger_irq; | ||||
|     INSERT_PADDING_WORDS(0x2f); | ||||
|     RasterizerRegs rasterizer; | ||||
|     TexturingRegs texturing; | ||||
|     FramebufferRegs framebuffer; | ||||
|     LightingRegs lighting; | ||||
|     PipelineRegs pipeline; | ||||
|     ShaderRegs gs; | ||||
|     ShaderRegs vs; | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
| 
 | ||||
|     // Map register indices to names readable by humans
 | ||||
|     // Used for debugging purposes, so performance is not an issue here
 | ||||
|     static std::string GetCommandName(int index); | ||||
| 
 | ||||
|     static constexpr size_t NumIds() { | ||||
|         return sizeof(Regs) / sizeof(u32); | ||||
|     } | ||||
| 
 | ||||
|     const u32& operator[](int index) const { | ||||
|         const u32* content = reinterpret_cast<const u32*>(this); | ||||
|         return content[index]; | ||||
|     } | ||||
| 
 | ||||
|     u32& operator[](int index) { | ||||
|         u32* content = reinterpret_cast<u32*>(this); | ||||
|         return content[index]; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     /*
 | ||||
|     * Most physical addresses which Pica registers refer to are 8-byte aligned. | ||||
|     * This function should be used to get the address from a raw register value. | ||||
|     */ | ||||
|     static inline u32 DecodeAddressRegister(u32 register_value) { | ||||
|         return register_value * 8; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // TODO: MSVC does not support using offsetof() on non-static data members even though this
 | ||||
| //       is technically allowed since C++11. This macro should be enabled once MSVC adds
 | ||||
| //       support for that.
 | ||||
| #ifndef _MSC_VER | ||||
| #define ASSERT_REG_POSITION(field_name, position)                                                  \ | ||||
|     static_assert(offsetof(Regs, field_name) == position * 4,                                      \ | ||||
|                   "Field " #field_name " has invalid position") | ||||
| 
 | ||||
| ASSERT_REG_POSITION(trigger_irq, 0x10); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(rasterizer, 0x40); | ||||
| ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40); | ||||
| ASSERT_REG_POSITION(rasterizer.viewport_size_x, 0x41); | ||||
| ASSERT_REG_POSITION(rasterizer.viewport_size_y, 0x43); | ||||
| ASSERT_REG_POSITION(rasterizer.viewport_depth_range, 0x4d); | ||||
| ASSERT_REG_POSITION(rasterizer.viewport_depth_near_plane, 0x4e); | ||||
| ASSERT_REG_POSITION(rasterizer.vs_output_attributes[0], 0x50); | ||||
| ASSERT_REG_POSITION(rasterizer.vs_output_attributes[1], 0x51); | ||||
| ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65); | ||||
| ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68); | ||||
| ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(texturing, 0x80); | ||||
| ASSERT_REG_POSITION(texturing.texture0_enable, 0x80); | ||||
| ASSERT_REG_POSITION(texturing.texture0, 0x81); | ||||
| ASSERT_REG_POSITION(texturing.texture0_format, 0x8e); | ||||
| ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f); | ||||
| ASSERT_REG_POSITION(texturing.texture1, 0x91); | ||||
| ASSERT_REG_POSITION(texturing.texture1_format, 0x96); | ||||
| ASSERT_REG_POSITION(texturing.texture2, 0x99); | ||||
| ASSERT_REG_POSITION(texturing.texture2_format, 0x9e); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage0, 0xc0); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage1, 0xc8); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage2, 0xd0); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage3, 0xd8); | ||||
| ASSERT_REG_POSITION(texturing.tev_combiner_buffer_input, 0xe0); | ||||
| ASSERT_REG_POSITION(texturing.fog_mode, 0xe0); | ||||
| ASSERT_REG_POSITION(texturing.fog_color, 0xe1); | ||||
| ASSERT_REG_POSITION(texturing.fog_lut_offset, 0xe6); | ||||
| ASSERT_REG_POSITION(texturing.fog_lut_data, 0xe8); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0); | ||||
| ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); | ||||
| ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(framebuffer, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer.output_merger, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(lighting, 0x140); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(pipeline, 0x200); | ||||
| ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200); | ||||
| ASSERT_REG_POSITION(pipeline.index_array, 0x227); | ||||
| ASSERT_REG_POSITION(pipeline.num_vertices, 0x228); | ||||
| ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a); | ||||
| ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e); | ||||
| ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f); | ||||
| ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232); | ||||
| ASSERT_REG_POSITION(pipeline.command_buffer, 0x238); | ||||
| ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245); | ||||
| ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e); | ||||
| ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(gs, 0x280); | ||||
| ASSERT_REG_POSITION(vs, 0x2b0); | ||||
| 
 | ||||
| #undef ASSERT_REG_POSITION | ||||
| #endif // !defined(_MSC_VER)
 | ||||
| 
 | ||||
| // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
 | ||||
| // anyway.
 | ||||
| static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), | ||||
|               "Register set structure larger than it should be"); | ||||
| static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), | ||||
|               "Register set structure smaller than it should be"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										284
									
								
								src/video_core/regs_framebuffer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								src/video_core/regs_framebuffer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,284 @@ | |||
| // 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/assert.h" | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| struct FramebufferRegs { | ||||
|     enum class LogicOp : u32 { | ||||
|         Clear = 0, | ||||
|         And = 1, | ||||
|         AndReverse = 2, | ||||
|         Copy = 3, | ||||
|         Set = 4, | ||||
|         CopyInverted = 5, | ||||
|         NoOp = 6, | ||||
|         Invert = 7, | ||||
|         Nand = 8, | ||||
|         Or = 9, | ||||
|         Nor = 10, | ||||
|         Xor = 11, | ||||
|         Equiv = 12, | ||||
|         AndInverted = 13, | ||||
|         OrReverse = 14, | ||||
|         OrInverted = 15, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendEquation : u32 { | ||||
|         Add = 0, | ||||
|         Subtract = 1, | ||||
|         ReverseSubtract = 2, | ||||
|         Min = 3, | ||||
|         Max = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendFactor : u32 { | ||||
|         Zero = 0, | ||||
|         One = 1, | ||||
|         SourceColor = 2, | ||||
|         OneMinusSourceColor = 3, | ||||
|         DestColor = 4, | ||||
|         OneMinusDestColor = 5, | ||||
|         SourceAlpha = 6, | ||||
|         OneMinusSourceAlpha = 7, | ||||
|         DestAlpha = 8, | ||||
|         OneMinusDestAlpha = 9, | ||||
|         ConstantColor = 10, | ||||
|         OneMinusConstantColor = 11, | ||||
|         ConstantAlpha = 12, | ||||
|         OneMinusConstantAlpha = 13, | ||||
|         SourceAlphaSaturate = 14, | ||||
|     }; | ||||
| 
 | ||||
|     enum class CompareFunc : u32 { | ||||
|         Never = 0, | ||||
|         Always = 1, | ||||
|         Equal = 2, | ||||
|         NotEqual = 3, | ||||
|         LessThan = 4, | ||||
|         LessThanOrEqual = 5, | ||||
|         GreaterThan = 6, | ||||
|         GreaterThanOrEqual = 7, | ||||
|     }; | ||||
| 
 | ||||
|     enum class StencilAction : u32 { | ||||
|         Keep = 0, | ||||
|         Zero = 1, | ||||
|         Replace = 2, | ||||
|         Increment = 3, | ||||
|         Decrement = 4, | ||||
|         Invert = 5, | ||||
|         IncrementWrap = 6, | ||||
|         DecrementWrap = 7, | ||||
|     }; | ||||
| 
 | ||||
|     struct { | ||||
|         union { | ||||
|             // If false, logic blending is used
 | ||||
|             BitField<8, 1, u32> alphablend_enable; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 8, BlendEquation> blend_equation_rgb; | ||||
|             BitField<8, 8, BlendEquation> blend_equation_a; | ||||
| 
 | ||||
|             BitField<16, 4, BlendFactor> factor_source_rgb; | ||||
|             BitField<20, 4, BlendFactor> factor_dest_rgb; | ||||
| 
 | ||||
|             BitField<24, 4, BlendFactor> factor_source_a; | ||||
|             BitField<28, 4, BlendFactor> factor_dest_a; | ||||
|         } alpha_blending; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, LogicOp> logic_op; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 raw; | ||||
|             BitField<0, 8, u32> r; | ||||
|             BitField<8, 8, u32> g; | ||||
|             BitField<16, 8, u32> b; | ||||
|             BitField<24, 8, u32> a; | ||||
|         } blend_const; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> enable; | ||||
|             BitField<4, 3, CompareFunc> func; | ||||
|             BitField<8, 8, u32> ref; | ||||
|         } alpha_test; | ||||
| 
 | ||||
|         struct { | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_func; | ||||
| 
 | ||||
|                 // If true, enable stencil testing
 | ||||
|                 BitField<0, 1, u32> enable; | ||||
| 
 | ||||
|                 // Comparison operation for stencil testing
 | ||||
|                 BitField<4, 3, CompareFunc> func; | ||||
| 
 | ||||
|                 // Mask used to control writing to the stencil buffer
 | ||||
|                 BitField<8, 8, u32> write_mask; | ||||
| 
 | ||||
|                 // Value to compare against for stencil testing
 | ||||
|                 BitField<16, 8, u32> reference_value; | ||||
| 
 | ||||
|                 // Mask to apply on stencil test inputs
 | ||||
|                 BitField<24, 8, u32> input_mask; | ||||
|             }; | ||||
| 
 | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_op; | ||||
| 
 | ||||
|                 // Action to perform when the stencil test fails
 | ||||
|                 BitField<0, 3, StencilAction> action_stencil_fail; | ||||
| 
 | ||||
|                 // Action to perform when stencil testing passed but depth testing fails
 | ||||
|                 BitField<4, 3, StencilAction> action_depth_fail; | ||||
| 
 | ||||
|                 // Action to perform when both stencil and depth testing pass
 | ||||
|                 BitField<8, 3, StencilAction> action_depth_pass; | ||||
|             }; | ||||
|         } stencil_test; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> depth_test_enable; | ||||
|             BitField<4, 3, CompareFunc> depth_test_func; | ||||
|             BitField<8, 1, u32> red_enable; | ||||
|             BitField<9, 1, u32> green_enable; | ||||
|             BitField<10, 1, u32> blue_enable; | ||||
|             BitField<11, 1, u32> alpha_enable; | ||||
|             BitField<12, 1, u32> depth_write_enable; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x8); | ||||
|     } output_merger; | ||||
| 
 | ||||
|     // Components are laid out in reverse byte order, most significant bits first.
 | ||||
|     enum class ColorFormat : u32 { | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class DepthFormat : u32 { | ||||
|         D16 = 0, | ||||
|         D24 = 2, | ||||
|         D24S8 = 3, | ||||
|     }; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified color format
 | ||||
|     static unsigned BytesPerColorPixel(ColorFormat format) { | ||||
|         switch (format) { | ||||
|         case ColorFormat::RGBA8: | ||||
|             return 4; | ||||
|         case ColorFormat::RGB8: | ||||
|             return 3; | ||||
|         case ColorFormat::RGB5A1: | ||||
|         case ColorFormat::RGB565: | ||||
|         case ColorFormat::RGBA4: | ||||
|             return 2; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     struct FramebufferConfig { | ||||
|         INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         DepthFormat depth_format; // TODO: Should be a BitField!
 | ||||
|         BitField<16, 3, ColorFormat> color_format; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x4); | ||||
| 
 | ||||
|         u32 depth_buffer_address; | ||||
|         u32 color_buffer_address; | ||||
| 
 | ||||
|         union { | ||||
|             // Apparently, the framebuffer width is stored as expected,
 | ||||
|             // while the height is stored as the actual height minus one.
 | ||||
|             // Hence, don't access these fields directly but use the accessors
 | ||||
|             // GetWidth() and GetHeight() instead.
 | ||||
|             BitField<0, 11, u32> width; | ||||
|             BitField<12, 10, u32> height; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         inline PAddr GetColorBufferPhysicalAddress() const { | ||||
|             return color_buffer_address * 8; | ||||
|         } | ||||
|         inline PAddr GetDepthBufferPhysicalAddress() const { | ||||
|             return depth_buffer_address * 8; | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetWidth() const { | ||||
|             return width; | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetHeight() const { | ||||
|             return height + 1; | ||||
|         } | ||||
|     } framebuffer; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified depth format
 | ||||
|     static u32 BytesPerDepthPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 2; | ||||
|         case DepthFormat::D24: | ||||
|             return 3; | ||||
|         case DepthFormat::D24S8: | ||||
|             return 4; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Returns the number of bits per depth component of the specified depth format
 | ||||
|     static u32 DepthBitsPerPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 16; | ||||
|         case DepthFormat::D24: | ||||
|         case DepthFormat::D24S8: | ||||
|             return 24; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32), | ||||
|               "FramebufferRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										294
									
								
								src/video_core/regs_lighting.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								src/video_core/regs_lighting.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,294 @@ | |||
| // 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/assert.h" | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/vector_math.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| struct LightingRegs { | ||||
|     enum class LightingSampler { | ||||
|         Distribution0 = 0, | ||||
|         Distribution1 = 1, | ||||
|         Fresnel = 3, | ||||
|         ReflectBlue = 4, | ||||
|         ReflectGreen = 5, | ||||
|         ReflectRed = 6, | ||||
|         SpotlightAttenuation = 8, | ||||
|         DistanceAttenuation = 16, | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|     * Pica fragment lighting supports using different LUTs for each lighting component:  Reflectance | ||||
|     * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor, | ||||
|     * and spotlight attenuation.  Furthermore, which LUTs are used for each channel (or whether a | ||||
|     * channel is enabled at all) is specified by various pre-defined lighting configurations.  With | ||||
|     * configurations that require more LUTs, more cycles are required on HW to perform lighting | ||||
|     * computations. | ||||
|     */ | ||||
|     enum class LightingConfig { | ||||
|         Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
 | ||||
|         Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
 | ||||
|         Config2 = 2, ///< Reflect Red, Distribution 0/1
 | ||||
|         Config3 = 3, ///< Distribution 0/1, Fresnel
 | ||||
|         Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
 | ||||
|         Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
 | ||||
|         Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
 | ||||
| 
 | ||||
|         Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
 | ||||
|                      ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
 | ||||
|     }; | ||||
| 
 | ||||
|     /// Selects which lighting components are affected by fresnel
 | ||||
|     enum class LightingFresnelSelector { | ||||
|         None = 0,           ///< Fresnel is disabled
 | ||||
|         PrimaryAlpha = 1,   ///< Primary (diffuse) lighting alpha is affected by fresnel
 | ||||
|         SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
 | ||||
|         Both = | ||||
|             PrimaryAlpha | | ||||
|             SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
 | ||||
|     }; | ||||
| 
 | ||||
|     /// Factor used to scale the output of a lighting LUT
 | ||||
|     enum class LightingScale { | ||||
|         Scale1 = 0, ///< Scale is 1x
 | ||||
|         Scale2 = 1, ///< Scale is 2x
 | ||||
|         Scale4 = 2, ///< Scale is 4x
 | ||||
|         Scale8 = 3, ///< Scale is 8x
 | ||||
| 
 | ||||
|         Scale1_4 = 6, ///< Scale is 0.25x
 | ||||
|         Scale1_2 = 7, ///< Scale is 0.5x
 | ||||
|     }; | ||||
| 
 | ||||
|     enum class LightingLutInput { | ||||
|         NH = 0, // Cosine of the angle between the normal and half-angle vectors
 | ||||
|         VH = 1, // Cosine of the angle between the view and half-angle vectors
 | ||||
|         NV = 2, // Cosine of the angle between the normal and the view vector
 | ||||
|         LN = 3, // Cosine of the angle between the light and the normal vectors
 | ||||
|     }; | ||||
| 
 | ||||
|     enum class LightingBumpMode : u32 { | ||||
|         None = 0, | ||||
|         NormalMap = 1, | ||||
|         TangentMap = 2, | ||||
|     }; | ||||
| 
 | ||||
|     union LightColor { | ||||
|         BitField<0, 10, u32> b; | ||||
|         BitField<10, 10, u32> g; | ||||
|         BitField<20, 10, u32> r; | ||||
| 
 | ||||
|         Math::Vec3f ToVec3f() const { | ||||
|             // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
 | ||||
|             // component
 | ||||
|             return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /// Returns true if the specified lighting sampler is supported by the current Pica lighting
 | ||||
|     /// configuration
 | ||||
|     static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) { | ||||
|         switch (sampler) { | ||||
|         case LightingSampler::Distribution0: | ||||
|             return (config != LightingConfig::Config1); | ||||
| 
 | ||||
|         case LightingSampler::Distribution1: | ||||
|             return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) && | ||||
|                    (config != LightingConfig::Config5); | ||||
| 
 | ||||
|         case LightingSampler::Fresnel: | ||||
|             return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) && | ||||
|                    (config != LightingConfig::Config4); | ||||
| 
 | ||||
|         case LightingSampler::ReflectRed: | ||||
|             return (config != LightingConfig::Config3); | ||||
| 
 | ||||
|         case LightingSampler::ReflectGreen: | ||||
|         case LightingSampler::ReflectBlue: | ||||
|             return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) || | ||||
|                    (config == LightingConfig::Config7); | ||||
|         default: | ||||
|             UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached " | ||||
|                             "unreachable section, sampler should be one " | ||||
|                             "of Distribution0, Distribution1, Fresnel, " | ||||
|                             "ReflectRed, ReflectGreen or ReflectBlue, instead " | ||||
|                             "got %i", | ||||
|                             static_cast<int>(config)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     struct LightSrc { | ||||
|         LightColor specular_0; // material.specular_0 * light.specular_0
 | ||||
|         LightColor specular_1; // material.specular_1 * light.specular_1
 | ||||
|         LightColor diffuse;    // material.diffuse * light.diffuse
 | ||||
|         LightColor ambient;    // material.ambient * light.ambient
 | ||||
| 
 | ||||
|         // Encoded as 16-bit floating point
 | ||||
|         union { | ||||
|             BitField<0, 16, u32> x; | ||||
|             BitField<16, 16, u32> y; | ||||
|         }; | ||||
|         union { | ||||
|             BitField<0, 16, u32> z; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> directional; | ||||
|             BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
 | ||||
|         } config; | ||||
| 
 | ||||
|         BitField<0, 20, u32> dist_atten_bias; | ||||
|         BitField<0, 20, u32> dist_atten_scale; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x4); | ||||
|     }; | ||||
|     static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32), "LightSrc structure must be 0x10 words"); | ||||
| 
 | ||||
|     LightSrc light[8]; | ||||
|     LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
 | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
|     BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
 | ||||
| 
 | ||||
|     union { | ||||
|         BitField<2, 2, LightingFresnelSelector> fresnel_selector; | ||||
|         BitField<4, 4, LightingConfig> config; | ||||
|         BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
 | ||||
|         BitField<27, 1, u32> clamp_highlights; | ||||
|         BitField<28, 2, LightingBumpMode> bump_mode; | ||||
|         BitField<30, 1, u32> disable_bump_renorm; | ||||
|     } config0; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<16, 1, u32> disable_lut_d0; | ||||
|         BitField<17, 1, u32> disable_lut_d1; | ||||
|         BitField<19, 1, u32> disable_lut_fr; | ||||
|         BitField<20, 1, u32> disable_lut_rr; | ||||
|         BitField<21, 1, u32> disable_lut_rg; | ||||
|         BitField<22, 1, u32> disable_lut_rb; | ||||
| 
 | ||||
|         // Each bit specifies whether distance attenuation should be applied for the corresponding
 | ||||
|         // light.
 | ||||
|         BitField<24, 1, u32> disable_dist_atten_light_0; | ||||
|         BitField<25, 1, u32> disable_dist_atten_light_1; | ||||
|         BitField<26, 1, u32> disable_dist_atten_light_2; | ||||
|         BitField<27, 1, u32> disable_dist_atten_light_3; | ||||
|         BitField<28, 1, u32> disable_dist_atten_light_4; | ||||
|         BitField<29, 1, u32> disable_dist_atten_light_5; | ||||
|         BitField<30, 1, u32> disable_dist_atten_light_6; | ||||
|         BitField<31, 1, u32> disable_dist_atten_light_7; | ||||
|     } config1; | ||||
| 
 | ||||
|     bool IsDistAttenDisabled(unsigned index) const { | ||||
|         const unsigned disable[] = { | ||||
|             config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1, | ||||
|             config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3, | ||||
|             config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5, | ||||
|             config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7}; | ||||
|         return disable[index] != 0; | ||||
|     } | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
 | ||||
|         BitField<8, 5, u32> type;  ///< Type of LUT for which to set data
 | ||||
|     } lut_config; | ||||
| 
 | ||||
|     BitField<0, 1, u32> disable; | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|     // When data is written to any of these registers, it gets written to the lookup table of the
 | ||||
|     // selected type at the selected index, specified above in the `lut_config` register.  With each
 | ||||
|     // write, `lut_config.index` is incremented.  It does not matter which of these registers is
 | ||||
|     // written to, the behavior will be the same.
 | ||||
|     u32 lut_data[8]; | ||||
| 
 | ||||
|     // These are used to specify if absolute (abs) value should be used for each LUT index.  When
 | ||||
|     // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0).  Otherwise, they are in
 | ||||
|     // the range of (0.0, 1.0).
 | ||||
|     union { | ||||
|         BitField<1, 1, u32> disable_d0; | ||||
|         BitField<5, 1, u32> disable_d1; | ||||
|         BitField<9, 1, u32> disable_sp; | ||||
|         BitField<13, 1, u32> disable_fr; | ||||
|         BitField<17, 1, u32> disable_rb; | ||||
|         BitField<21, 1, u32> disable_rg; | ||||
|         BitField<25, 1, u32> disable_rr; | ||||
|     } abs_lut_input; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 3, LightingLutInput> d0; | ||||
|         BitField<4, 3, LightingLutInput> d1; | ||||
|         BitField<8, 3, LightingLutInput> sp; | ||||
|         BitField<12, 3, LightingLutInput> fr; | ||||
|         BitField<16, 3, LightingLutInput> rb; | ||||
|         BitField<20, 3, LightingLutInput> rg; | ||||
|         BitField<24, 3, LightingLutInput> rr; | ||||
|     } lut_input; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 3, LightingScale> d0; | ||||
|         BitField<4, 3, LightingScale> d1; | ||||
|         BitField<8, 3, LightingScale> sp; | ||||
|         BitField<12, 3, LightingScale> fr; | ||||
|         BitField<16, 3, LightingScale> rb; | ||||
|         BitField<20, 3, LightingScale> rg; | ||||
|         BitField<24, 3, LightingScale> rr; | ||||
| 
 | ||||
|         static float GetScale(LightingScale scale) { | ||||
|             switch (scale) { | ||||
|             case LightingScale::Scale1: | ||||
|                 return 1.0f; | ||||
|             case LightingScale::Scale2: | ||||
|                 return 2.0f; | ||||
|             case LightingScale::Scale4: | ||||
|                 return 4.0f; | ||||
|             case LightingScale::Scale8: | ||||
|                 return 8.0f; | ||||
|             case LightingScale::Scale1_4: | ||||
|                 return 0.25f; | ||||
|             case LightingScale::Scale1_2: | ||||
|                 return 0.5f; | ||||
|             } | ||||
|             return 0.0f; | ||||
|         } | ||||
|     } lut_scale; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x6); | ||||
| 
 | ||||
|     union { | ||||
|         // There are 8 light enable "slots", corresponding to the total number of lights supported
 | ||||
|         // by Pica.  For N enabled lights (specified by register 0x1c2, or 'src_num' above), the
 | ||||
|         // first N slots below will be set to integers within the range of 0-7, corresponding to the
 | ||||
|         // actual light that is enabled for each slot.
 | ||||
| 
 | ||||
|         BitField<0, 3, u32> slot_0; | ||||
|         BitField<4, 3, u32> slot_1; | ||||
|         BitField<8, 3, u32> slot_2; | ||||
|         BitField<12, 3, u32> slot_3; | ||||
|         BitField<16, 3, u32> slot_4; | ||||
|         BitField<20, 3, u32> slot_5; | ||||
|         BitField<24, 3, u32> slot_6; | ||||
|         BitField<28, 3, u32> slot_7; | ||||
| 
 | ||||
|         unsigned GetNum(unsigned index) const { | ||||
|             const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3, | ||||
|                                              slot_4, slot_5, slot_6, slot_7}; | ||||
|             return enable_slots[index]; | ||||
|         } | ||||
|     } light_enable; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x26); | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(LightingRegs) == 0xC0 * sizeof(u32), "LightingRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										224
									
								
								src/video_core/regs_pipeline.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/video_core/regs_pipeline.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,224 @@ | |||
| // 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/assert.h" | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| struct PipelineRegs { | ||||
|     enum class VertexAttributeFormat : u64 { | ||||
|         BYTE = 0, | ||||
|         UBYTE = 1, | ||||
|         SHORT = 2, | ||||
|         FLOAT = 3, | ||||
|     }; | ||||
| 
 | ||||
|     struct { | ||||
|         BitField<0, 29, u32> base_address; | ||||
| 
 | ||||
|         PAddr GetPhysicalBaseAddress() const { | ||||
|             return base_address * 8; | ||||
|         } | ||||
| 
 | ||||
|         // Descriptor for internal vertex attributes
 | ||||
|         union { | ||||
|             BitField<0, 2, VertexAttributeFormat> format0; // size of one element
 | ||||
|             BitField<2, 2, u64> size0;                     // number of elements minus 1
 | ||||
|             BitField<4, 2, VertexAttributeFormat> format1; | ||||
|             BitField<6, 2, u64> size1; | ||||
|             BitField<8, 2, VertexAttributeFormat> format2; | ||||
|             BitField<10, 2, u64> size2; | ||||
|             BitField<12, 2, VertexAttributeFormat> format3; | ||||
|             BitField<14, 2, u64> size3; | ||||
|             BitField<16, 2, VertexAttributeFormat> format4; | ||||
|             BitField<18, 2, u64> size4; | ||||
|             BitField<20, 2, VertexAttributeFormat> format5; | ||||
|             BitField<22, 2, u64> size5; | ||||
|             BitField<24, 2, VertexAttributeFormat> format6; | ||||
|             BitField<26, 2, u64> size6; | ||||
|             BitField<28, 2, VertexAttributeFormat> format7; | ||||
|             BitField<30, 2, u64> size7; | ||||
|             BitField<32, 2, VertexAttributeFormat> format8; | ||||
|             BitField<34, 2, u64> size8; | ||||
|             BitField<36, 2, VertexAttributeFormat> format9; | ||||
|             BitField<38, 2, u64> size9; | ||||
|             BitField<40, 2, VertexAttributeFormat> format10; | ||||
|             BitField<42, 2, u64> size10; | ||||
|             BitField<44, 2, VertexAttributeFormat> format11; | ||||
|             BitField<46, 2, u64> size11; | ||||
| 
 | ||||
|             BitField<48, 12, u64> attribute_mask; | ||||
| 
 | ||||
|             // number of total attributes minus 1
 | ||||
|             BitField<60, 4, u64> max_attribute_index; | ||||
|         }; | ||||
| 
 | ||||
|         inline VertexAttributeFormat GetFormat(int n) const { | ||||
|             VertexAttributeFormat formats[] = {format0, format1, format2,  format3, | ||||
|                                                format4, format5, format6,  format7, | ||||
|                                                format8, format9, format10, format11}; | ||||
|             return formats[n]; | ||||
|         } | ||||
| 
 | ||||
|         inline int GetNumElements(int n) const { | ||||
|             u64 sizes[] = {size0, size1, size2, size3, size4,  size5, | ||||
|                            size6, size7, size8, size9, size10, size11}; | ||||
|             return (int)sizes[n] + 1; | ||||
|         } | ||||
| 
 | ||||
|         inline int GetElementSizeInBytes(int n) const { | ||||
|             return (GetFormat(n) == VertexAttributeFormat::FLOAT) | ||||
|                        ? 4 | ||||
|                        : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1; | ||||
|         } | ||||
| 
 | ||||
|         inline int GetStride(int n) const { | ||||
|             return GetNumElements(n) * GetElementSizeInBytes(n); | ||||
|         } | ||||
| 
 | ||||
|         inline bool IsDefaultAttribute(int id) const { | ||||
|             return (id >= 12) || (attribute_mask & (1ULL << id)) != 0; | ||||
|         } | ||||
| 
 | ||||
|         inline int GetNumTotalAttributes() const { | ||||
|             return (int)max_attribute_index + 1; | ||||
|         } | ||||
| 
 | ||||
|         // Attribute loaders map the source vertex data to input attributes
 | ||||
|         // This e.g. allows to load different attributes from different memory locations
 | ||||
|         struct { | ||||
|             // Source attribute data offset from the base address
 | ||||
|             u32 data_offset; | ||||
| 
 | ||||
|             union { | ||||
|                 BitField<0, 4, u64> comp0; | ||||
|                 BitField<4, 4, u64> comp1; | ||||
|                 BitField<8, 4, u64> comp2; | ||||
|                 BitField<12, 4, u64> comp3; | ||||
|                 BitField<16, 4, u64> comp4; | ||||
|                 BitField<20, 4, u64> comp5; | ||||
|                 BitField<24, 4, u64> comp6; | ||||
|                 BitField<28, 4, u64> comp7; | ||||
|                 BitField<32, 4, u64> comp8; | ||||
|                 BitField<36, 4, u64> comp9; | ||||
|                 BitField<40, 4, u64> comp10; | ||||
|                 BitField<44, 4, u64> comp11; | ||||
| 
 | ||||
|                 // bytes for a single vertex in this loader
 | ||||
|                 BitField<48, 8, u64> byte_count; | ||||
| 
 | ||||
|                 BitField<60, 4, u64> component_count; | ||||
|             }; | ||||
| 
 | ||||
|             inline int GetComponent(int n) const { | ||||
|                 u64 components[] = {comp0, comp1, comp2, comp3, comp4,  comp5, | ||||
|                                     comp6, comp7, comp8, comp9, comp10, comp11}; | ||||
|                 return (int)components[n]; | ||||
|             } | ||||
|         } attribute_loaders[12]; | ||||
|     } vertex_attributes; | ||||
| 
 | ||||
|     struct { | ||||
|         enum IndexFormat : u32 { | ||||
|             BYTE = 0, | ||||
|             SHORT = 1, | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 31, u32> offset; // relative to base attribute address
 | ||||
|             BitField<31, 1, IndexFormat> format; | ||||
|         }; | ||||
|     } index_array; | ||||
| 
 | ||||
|     // Number of vertices to render
 | ||||
|     u32 num_vertices; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|     // The index of the first vertex to render
 | ||||
|     u32 vertex_offset; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|     // These two trigger rendering of triangles
 | ||||
|     u32 trigger_draw; | ||||
|     u32 trigger_draw_indexed; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|     // These registers are used to setup the default "fall-back" vertex shader attributes
 | ||||
|     struct { | ||||
|         // Index of the current default attribute
 | ||||
|         u32 index; | ||||
| 
 | ||||
|         // Writing to these registers sets the "current" default attribute.
 | ||||
|         u32 set_value[3]; | ||||
|     } vs_default_attributes_setup; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|     struct { | ||||
|         // There are two channels that can be used to configure the next command buffer, which can
 | ||||
|         // be then executed by writing to the "trigger" registers. There are two reasons why a game
 | ||||
|         // might use this feature:
 | ||||
|         //  1) With this, an arbitrary number of additional command buffers may be executed in
 | ||||
|         //     sequence without requiring any intervention of the CPU after the initial one is
 | ||||
|         //     kicked off.
 | ||||
|         //  2) Games can configure these registers to provide a command list subroutine mechanism.
 | ||||
| 
 | ||||
|         BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
 | ||||
|         BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
 | ||||
|         u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
 | ||||
| 
 | ||||
|         unsigned GetSize(unsigned index) const { | ||||
|             ASSERT(index < 2); | ||||
|             return 8 * size[index]; | ||||
|         } | ||||
| 
 | ||||
|         PAddr GetPhysicalAddress(unsigned index) const { | ||||
|             ASSERT(index < 2); | ||||
|             return (PAddr)(8 * addr[index]); | ||||
|         } | ||||
|     } command_buffer; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(4); | ||||
| 
 | ||||
|     /// Number of input attributes to the vertex shader minus 1
 | ||||
|     BitField<0, 4, u32> max_input_attrib_index; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(2); | ||||
| 
 | ||||
|     enum class GPUMode : u32 { | ||||
|         Drawing = 0, | ||||
|         Configuring = 1, | ||||
|     }; | ||||
| 
 | ||||
|     GPUMode gpu_mode; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x18); | ||||
| 
 | ||||
|     enum class TriangleTopology : u32 { | ||||
|         List = 0, | ||||
|         Strip = 1, | ||||
|         Fan = 2, | ||||
|         Shader = 3, // Programmable setup unit implemented in a geometry shader
 | ||||
|     }; | ||||
| 
 | ||||
|     BitField<8, 2, TriangleTopology> triangle_topology; | ||||
| 
 | ||||
|     u32 restart_primitive; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										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
 | ||||
							
								
								
									
										104
									
								
								src/video_core/regs_shader.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/video_core/regs_shader.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | |||
| // 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 ShaderRegs { | ||||
|     BitField<0, 16, u32> bool_uniforms; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 8, u32> x; | ||||
|         BitField<8, 8, u32> y; | ||||
|         BitField<16, 8, u32> z; | ||||
|         BitField<24, 8, u32> w; | ||||
|     } int_uniforms[4]; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x4); | ||||
| 
 | ||||
|     union { | ||||
|         // Number of input attributes to shader unit - 1
 | ||||
|         BitField<0, 4, u32> max_input_attribute_index; | ||||
|     }; | ||||
| 
 | ||||
|     // Offset to shader program entry point (in words)
 | ||||
|     BitField<0, 16, u32> main_offset; | ||||
| 
 | ||||
|     /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
 | ||||
|     u32 input_attribute_to_register_map_low; | ||||
|     u32 input_attribute_to_register_map_high; | ||||
| 
 | ||||
|     unsigned int GetRegisterForAttribute(unsigned int attribute_index) const { | ||||
|         u64 map = ((u64)input_attribute_to_register_map_high << 32) | | ||||
|                   (u64)input_attribute_to_register_map_low; | ||||
|         return (map >> (attribute_index * 4)) & 0b1111; | ||||
|     } | ||||
| 
 | ||||
|     BitField<0, 16, u32> output_mask; | ||||
| 
 | ||||
|     // 0x28E, CODETRANSFER_END
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|     struct { | ||||
|         enum Format : u32 { | ||||
|             FLOAT24 = 0, | ||||
|             FLOAT32 = 1, | ||||
|         }; | ||||
| 
 | ||||
|         bool IsFloat32() const { | ||||
|             return format == FLOAT32; | ||||
|         } | ||||
| 
 | ||||
|         union { | ||||
|             // Index of the next uniform to write to
 | ||||
|             // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
 | ||||
|             // indices
 | ||||
|             // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
 | ||||
|             BitField<0, 7, u32> index; | ||||
| 
 | ||||
|             BitField<31, 1, Format> format; | ||||
|         }; | ||||
| 
 | ||||
|         // Writing to these registers sets the current uniform.
 | ||||
|         u32 set_value[8]; | ||||
| 
 | ||||
|     } uniform_setup; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|     struct { | ||||
|         // Offset of the next instruction to write code to.
 | ||||
|         // Incremented with each instruction write.
 | ||||
|         u32 offset; | ||||
| 
 | ||||
|         // Writing to these registers sets the "current" word in the shader program.
 | ||||
|         u32 set_word[8]; | ||||
|     } program; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|     // This register group is used to load an internal table of swizzling patterns,
 | ||||
|     // which are indexed by each shader instruction to specify vector component swizzling.
 | ||||
|     struct { | ||||
|         // Offset of the next swizzle pattern to write code to.
 | ||||
|         // Incremented with each instruction write.
 | ||||
|         u32 offset; | ||||
| 
 | ||||
|         // Writing to these registers sets the current swizzle pattern in the table.
 | ||||
|         u32 set_word[8]; | ||||
|     } swizzle_patterns; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(ShaderRegs) == 0x30 * sizeof(u32), "ShaderRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
							
								
								
									
										328
									
								
								src/video_core/regs_texturing.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								src/video_core/regs_texturing.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,328 @@ | |||
| // 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/assert.h" | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| struct TexturingRegs { | ||||
|     struct TextureConfig { | ||||
|         enum TextureType : u32 { | ||||
|             Texture2D = 0, | ||||
|             TextureCube = 1, | ||||
|             Shadow2D = 2, | ||||
|             Projection2D = 3, | ||||
|             ShadowCube = 4, | ||||
|             Disabled = 5, | ||||
|         }; | ||||
| 
 | ||||
|         enum WrapMode : u32 { | ||||
|             ClampToEdge = 0, | ||||
|             ClampToBorder = 1, | ||||
|             Repeat = 2, | ||||
|             MirroredRepeat = 3, | ||||
|         }; | ||||
| 
 | ||||
|         enum TextureFilter : u32 { | ||||
|             Nearest = 0, | ||||
|             Linear = 1, | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 raw; | ||||
|             BitField<0, 8, u32> r; | ||||
|             BitField<8, 8, u32> g; | ||||
|             BitField<16, 8, u32> b; | ||||
|             BitField<24, 8, u32> a; | ||||
|         } border_color; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 16, u32> height; | ||||
|             BitField<16, 16, u32> width; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<1, 1, TextureFilter> mag_filter; | ||||
|             BitField<2, 1, TextureFilter> min_filter; | ||||
|             BitField<8, 2, WrapMode> wrap_t; | ||||
|             BitField<12, 2, WrapMode> wrap_s; | ||||
|             BitField<28, 2, TextureType> | ||||
|                 type; ///< @note Only valid for texture 0 according to 3DBrew.
 | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         u32 address; | ||||
| 
 | ||||
|         PAddr GetPhysicalAddress() const { | ||||
|             return address * 8; | ||||
|         } | ||||
| 
 | ||||
|         // texture1 and texture2 store the texture format directly after the address
 | ||||
|         // whereas texture0 inserts some additional flags inbetween.
 | ||||
|         // Hence, we store the format separately so that all other parameters can be described
 | ||||
|         // in a single structure.
 | ||||
|     }; | ||||
| 
 | ||||
|     enum class TextureFormat : u32 { | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
|         IA8 = 5, | ||||
|         RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
 | ||||
|         I8 = 7, | ||||
|         A8 = 8, | ||||
|         IA4 = 9, | ||||
|         I4 = 10, | ||||
|         A4 = 11, | ||||
|         ETC1 = 12,   // compressed
 | ||||
|         ETC1A4 = 13, // compressed
 | ||||
|     }; | ||||
| 
 | ||||
|     static unsigned NibblesPerPixel(TextureFormat format) { | ||||
|         switch (format) { | ||||
|         case TextureFormat::RGBA8: | ||||
|             return 8; | ||||
| 
 | ||||
|         case TextureFormat::RGB8: | ||||
|             return 6; | ||||
| 
 | ||||
|         case TextureFormat::RGB5A1: | ||||
|         case TextureFormat::RGB565: | ||||
|         case TextureFormat::RGBA4: | ||||
|         case TextureFormat::IA8: | ||||
|         case TextureFormat::RG8: | ||||
|             return 4; | ||||
| 
 | ||||
|         case TextureFormat::I4: | ||||
|         case TextureFormat::A4: | ||||
|             return 1; | ||||
| 
 | ||||
|         case TextureFormat::I8: | ||||
|         case TextureFormat::A8: | ||||
|         case TextureFormat::IA4: | ||||
| 
 | ||||
|         default: // placeholder for yet unknown formats
 | ||||
|             UNIMPLEMENTED(); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 1, u32> texture0_enable; | ||||
|         BitField<1, 1, u32> texture1_enable; | ||||
|         BitField<2, 1, u32> texture2_enable; | ||||
|     }; | ||||
|     TextureConfig texture0; | ||||
|     INSERT_PADDING_WORDS(0x8); | ||||
|     BitField<0, 4, TextureFormat> texture0_format; | ||||
|     BitField<0, 1, u32> fragment_lighting_enable; | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
|     TextureConfig texture1; | ||||
|     BitField<0, 4, TextureFormat> texture1_format; | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
|     TextureConfig texture2; | ||||
|     BitField<0, 4, TextureFormat> texture2_format; | ||||
|     INSERT_PADDING_WORDS(0x21); | ||||
| 
 | ||||
|     struct FullTextureConfig { | ||||
|         const bool enabled; | ||||
|         const TextureConfig config; | ||||
|         const TextureFormat format; | ||||
|     }; | ||||
|     const std::array<FullTextureConfig, 3> GetTextures() const { | ||||
|         return {{ | ||||
|             {texture0_enable.ToBool(), texture0, texture0_format}, | ||||
|             {texture1_enable.ToBool(), texture1, texture1_format}, | ||||
|             {texture2_enable.ToBool(), texture2, texture2_format}, | ||||
|         }}; | ||||
|     } | ||||
| 
 | ||||
|     // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
 | ||||
|     struct TevStageConfig { | ||||
|         enum class Source : u32 { | ||||
|             PrimaryColor = 0x0, | ||||
|             PrimaryFragmentColor = 0x1, | ||||
|             SecondaryFragmentColor = 0x2, | ||||
| 
 | ||||
|             Texture0 = 0x3, | ||||
|             Texture1 = 0x4, | ||||
|             Texture2 = 0x5, | ||||
|             Texture3 = 0x6, | ||||
| 
 | ||||
|             PreviousBuffer = 0xd, | ||||
|             Constant = 0xe, | ||||
|             Previous = 0xf, | ||||
|         }; | ||||
| 
 | ||||
|         enum class ColorModifier : u32 { | ||||
|             SourceColor = 0x0, | ||||
|             OneMinusSourceColor = 0x1, | ||||
|             SourceAlpha = 0x2, | ||||
|             OneMinusSourceAlpha = 0x3, | ||||
|             SourceRed = 0x4, | ||||
|             OneMinusSourceRed = 0x5, | ||||
| 
 | ||||
|             SourceGreen = 0x8, | ||||
|             OneMinusSourceGreen = 0x9, | ||||
| 
 | ||||
|             SourceBlue = 0xc, | ||||
|             OneMinusSourceBlue = 0xd, | ||||
|         }; | ||||
| 
 | ||||
|         enum class AlphaModifier : u32 { | ||||
|             SourceAlpha = 0x0, | ||||
|             OneMinusSourceAlpha = 0x1, | ||||
|             SourceRed = 0x2, | ||||
|             OneMinusSourceRed = 0x3, | ||||
|             SourceGreen = 0x4, | ||||
|             OneMinusSourceGreen = 0x5, | ||||
|             SourceBlue = 0x6, | ||||
|             OneMinusSourceBlue = 0x7, | ||||
|         }; | ||||
| 
 | ||||
|         enum class Operation : u32 { | ||||
|             Replace = 0, | ||||
|             Modulate = 1, | ||||
|             Add = 2, | ||||
|             AddSigned = 3, | ||||
|             Lerp = 4, | ||||
|             Subtract = 5, | ||||
|             Dot3_RGB = 6, | ||||
| 
 | ||||
|             MultiplyThenAdd = 8, | ||||
|             AddThenMultiply = 9, | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 sources_raw; | ||||
|             BitField<0, 4, Source> color_source1; | ||||
|             BitField<4, 4, Source> color_source2; | ||||
|             BitField<8, 4, Source> color_source3; | ||||
|             BitField<16, 4, Source> alpha_source1; | ||||
|             BitField<20, 4, Source> alpha_source2; | ||||
|             BitField<24, 4, Source> alpha_source3; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 modifiers_raw; | ||||
|             BitField<0, 4, ColorModifier> color_modifier1; | ||||
|             BitField<4, 4, ColorModifier> color_modifier2; | ||||
|             BitField<8, 4, ColorModifier> color_modifier3; | ||||
|             BitField<12, 3, AlphaModifier> alpha_modifier1; | ||||
|             BitField<16, 3, AlphaModifier> alpha_modifier2; | ||||
|             BitField<20, 3, AlphaModifier> alpha_modifier3; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 ops_raw; | ||||
|             BitField<0, 4, Operation> color_op; | ||||
|             BitField<16, 4, Operation> alpha_op; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 const_color; | ||||
|             BitField<0, 8, u32> const_r; | ||||
|             BitField<8, 8, u32> const_g; | ||||
|             BitField<16, 8, u32> const_b; | ||||
|             BitField<24, 8, u32> const_a; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 scales_raw; | ||||
|             BitField<0, 2, u32> color_scale; | ||||
|             BitField<16, 2, u32> alpha_scale; | ||||
|         }; | ||||
| 
 | ||||
|         inline unsigned GetColorMultiplier() const { | ||||
|             return (color_scale < 3) ? (1 << color_scale) : 1; | ||||
|         } | ||||
| 
 | ||||
|         inline unsigned GetAlphaMultiplier() const { | ||||
|             return (alpha_scale < 3) ? (1 << alpha_scale) : 1; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     TevStageConfig tev_stage0; | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
|     TevStageConfig tev_stage1; | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
|     TevStageConfig tev_stage2; | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
|     TevStageConfig tev_stage3; | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|     enum class FogMode : u32 { | ||||
|         None = 0, | ||||
|         Fog = 5, | ||||
|         Gas = 7, | ||||
|     }; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 3, FogMode> fog_mode; | ||||
|         BitField<16, 1, u32> fog_flip; | ||||
| 
 | ||||
|         union { | ||||
|             // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
 | ||||
|             // these masks are set
 | ||||
|             BitField<8, 4, u32> update_mask_rgb; | ||||
|             BitField<12, 4, u32> update_mask_a; | ||||
| 
 | ||||
|             bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { | ||||
|                 return (stage_index < 4) && (update_mask_rgb & (1 << stage_index)); | ||||
|             } | ||||
| 
 | ||||
|             bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { | ||||
|                 return (stage_index < 4) && (update_mask_a & (1 << stage_index)); | ||||
|             } | ||||
|         } tev_combiner_buffer_input; | ||||
|     }; | ||||
| 
 | ||||
|     union { | ||||
|         u32 raw; | ||||
|         BitField<0, 8, u32> r; | ||||
|         BitField<8, 8, u32> g; | ||||
|         BitField<16, 8, u32> b; | ||||
|     } fog_color; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x4); | ||||
| 
 | ||||
|     BitField<0, 16, u32> fog_lut_offset; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|     u32 fog_lut_data[8]; | ||||
| 
 | ||||
|     TevStageConfig tev_stage4; | ||||
|     INSERT_PADDING_WORDS(0x3); | ||||
|     TevStageConfig tev_stage5; | ||||
| 
 | ||||
|     union { | ||||
|         u32 raw; | ||||
|         BitField<0, 8, u32> r; | ||||
|         BitField<8, 8, u32> g; | ||||
|         BitField<16, 8, u32> b; | ||||
|         BitField<24, 8, u32> a; | ||||
|     } tev_combiner_buffer_color; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|     const std::array<TevStageConfig, 6> GetTevStages() const { | ||||
|         return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}}; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(TexturingRegs) == 0x80 * sizeof(u32), | ||||
|               "TexturingRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
|  | @ -14,8 +14,8 @@ | |||
| #include "common/microprofile.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_gen.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | ||||
|  | @ -26,13 +26,15 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); | |||
| MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); | ||||
| MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); | ||||
| 
 | ||||
| static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { | ||||
|     return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && | ||||
|             stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && | ||||
|             stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous && | ||||
|             stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && | ||||
|             stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && | ||||
|             stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && | ||||
| static bool IsPassThroughTevStage(const Pica::TexturingRegs::TevStageConfig& stage) { | ||||
|     using TevStageConfig = Pica::TexturingRegs::TevStageConfig; | ||||
| 
 | ||||
|     return (stage.color_op == TevStageConfig::Operation::Replace && | ||||
|             stage.alpha_op == TevStageConfig::Operation::Replace && | ||||
|             stage.color_source1 == TevStageConfig::Source::Previous && | ||||
|             stage.alpha_source1 == TevStageConfig::Source::Previous && | ||||
|             stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && | ||||
|             stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && | ||||
|             stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); | ||||
| } | ||||
| 
 | ||||
|  | @ -181,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
|     CachedSurface* depth_surface; | ||||
|     MathUtil::Rectangle<int> rect; | ||||
|     std::tie(color_surface, depth_surface, rect) = | ||||
|         res_cache.GetFramebufferSurfaces(regs.framebuffer); | ||||
|         res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer); | ||||
| 
 | ||||
|     state.draw.draw_framebuffer = framebuffer.handle; | ||||
|     state.Apply(); | ||||
|  | @ -190,20 +192,24 @@ void RasterizerOpenGL::DrawTriangles() { | |||
|                            color_surface != nullptr ? color_surface->texture.handle : 0, 0); | ||||
|     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||||
|                            depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); | ||||
|     bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | ||||
|     bool has_stencil = | ||||
|         regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; | ||||
|     glFramebufferTexture2D( | ||||
|         GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||||
|         (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); | ||||
| 
 | ||||
|     // Sync the viewport
 | ||||
|     // 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_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2; | ||||
|     GLsizei viewport_width = | ||||
|         (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), | ||||
|                (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), | ||||
|                (GLsizei)(viewport_width * color_surface->res_scale_width), | ||||
|                (GLsizei)(viewport_height * color_surface->res_scale_height)); | ||||
|     glViewport( | ||||
|         (GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width), | ||||
|         (GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * 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 || | ||||
|         uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { | ||||
|  | @ -215,16 +221,16 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 
 | ||||
|     // 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.
 | ||||
|     GLint scissor_x1 = | ||||
|         static_cast<GLint>(rect.left + regs.scissor_test.x1 * color_surface->res_scale_width); | ||||
|     GLint scissor_y1 = | ||||
|         static_cast<GLint>(rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height); | ||||
|     GLint scissor_x1 = static_cast<GLint>( | ||||
|         rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width); | ||||
|     GLint scissor_y1 = static_cast<GLint>( | ||||
|         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
 | ||||
|     // scaling or doing multisampling.
 | ||||
|     GLint scissor_x2 = | ||||
|         static_cast<GLint>(rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width); | ||||
|     GLint scissor_x2 = static_cast<GLint>( | ||||
|         rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width); | ||||
|     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 || | ||||
|         uniform_block_data.data.scissor_x2 != scissor_x2 || | ||||
|  | @ -239,7 +245,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
|     } | ||||
| 
 | ||||
|     // Sync and bind the texture surfaces
 | ||||
|     const auto pica_textures = regs.GetTextures(); | ||||
|     const auto pica_textures = regs.texturing.GetTextures(); | ||||
|     for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { | ||||
|         const auto& texture = pica_textures[texture_index]; | ||||
| 
 | ||||
|  | @ -316,69 +322,69 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 
 | ||||
|     switch (id) { | ||||
|     // Culling
 | ||||
|     case PICA_REG_INDEX(cull_mode): | ||||
|     case PICA_REG_INDEX(rasterizer.cull_mode): | ||||
|         SyncCullMode(); | ||||
|         break; | ||||
| 
 | ||||
|     // Depth modifiers
 | ||||
|     case PICA_REG_INDEX(viewport_depth_range): | ||||
|     case PICA_REG_INDEX(rasterizer.viewport_depth_range): | ||||
|         SyncDepthScale(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(viewport_depth_near_plane): | ||||
|     case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane): | ||||
|         SyncDepthOffset(); | ||||
|         break; | ||||
| 
 | ||||
|     // Depth buffering
 | ||||
|     case PICA_REG_INDEX(depthmap_enable): | ||||
|     case PICA_REG_INDEX(rasterizer.depthmap_enable): | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // Blending
 | ||||
|     case PICA_REG_INDEX(output_merger.alphablend_enable): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): | ||||
|         SyncBlendEnabled(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.alpha_blending): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): | ||||
|         SyncBlendFuncs(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.blend_const): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.blend_const): | ||||
|         SyncBlendColor(); | ||||
|         break; | ||||
| 
 | ||||
|     // Fog state
 | ||||
|     case PICA_REG_INDEX(fog_color): | ||||
|     case PICA_REG_INDEX(texturing.fog_color): | ||||
|         SyncFogColor(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): | ||||
|     case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee): | ||||
|     case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): | ||||
|         uniform_block_data.fog_lut_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // Alpha test
 | ||||
|     case PICA_REG_INDEX(output_merger.alpha_test): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alpha_test): | ||||
|         SyncAlphaTest(); | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL stencil test + stencil write mask
 | ||||
|     // (Pica stencil test function register also contains a stencil write mask)
 | ||||
|     case PICA_REG_INDEX(output_merger.stencil_test.raw_func): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func): | ||||
|         SyncStencilTest(); | ||||
|         SyncStencilWriteMask(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.stencil_test.raw_op): | ||||
|     case PICA_REG_INDEX(framebuffer.depth_format): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.depth_format): | ||||
|         SyncStencilTest(); | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL depth test + depth and color write mask
 | ||||
|     // (Pica depth test function register also contains a depth and color write mask)
 | ||||
|     case PICA_REG_INDEX(output_merger.depth_test_enable): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable): | ||||
|         SyncDepthTest(); | ||||
|         SyncDepthWriteMask(); | ||||
|         SyncColorWriteMask(); | ||||
|  | @ -386,82 +392,82 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 
 | ||||
|     // Sync GL depth and stencil write mask
 | ||||
|     // (This is a dedicated combined depth / stencil write-enable register)
 | ||||
|     case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write): | ||||
|         SyncDepthWriteMask(); | ||||
|         SyncStencilWriteMask(); | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL color write mask
 | ||||
|     // (This is a dedicated color write-enable register)
 | ||||
|     case PICA_REG_INDEX(framebuffer.allow_color_write): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write): | ||||
|         SyncColorWriteMask(); | ||||
|         break; | ||||
| 
 | ||||
|     // Scissor test
 | ||||
|     case PICA_REG_INDEX(scissor_test.mode): | ||||
|     case PICA_REG_INDEX(rasterizer.scissor_test.mode): | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // Logic op
 | ||||
|     case PICA_REG_INDEX(output_merger.logic_op): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.logic_op): | ||||
|         SyncLogicOp(); | ||||
|         break; | ||||
| 
 | ||||
|     // Texture 0 type
 | ||||
|     case PICA_REG_INDEX(texture0.type): | ||||
|     case PICA_REG_INDEX(texturing.texture0.type): | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // TEV stages
 | ||||
|     // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
 | ||||
|     case PICA_REG_INDEX(tev_stage0.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage0.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage0.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage0.color_scale): | ||||
|     case PICA_REG_INDEX(tev_stage1.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage1.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage1.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage1.color_scale): | ||||
|     case PICA_REG_INDEX(tev_stage2.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage2.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage2.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage2.color_scale): | ||||
|     case PICA_REG_INDEX(tev_stage3.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage3.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage3.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage3.color_scale): | ||||
|     case PICA_REG_INDEX(tev_stage4.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage4.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage4.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage4.color_scale): | ||||
|     case PICA_REG_INDEX(tev_stage5.color_source1): | ||||
|     case PICA_REG_INDEX(tev_stage5.color_modifier1): | ||||
|     case PICA_REG_INDEX(tev_stage5.color_op): | ||||
|     case PICA_REG_INDEX(tev_stage5.color_scale): | ||||
|     case PICA_REG_INDEX(tev_combiner_buffer_input): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage0.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage0.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage0.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage1.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage1.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage1.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage2.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage2.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage2.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage3.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage3.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage3.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage4.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage4.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage4.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage5.color_source1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage5.color_op): | ||||
|     case PICA_REG_INDEX(texturing.tev_stage5.color_scale): | ||||
|     case PICA_REG_INDEX(texturing.tev_combiner_buffer_input): | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage0.const_r): | ||||
|         SyncTevConstColor(0, regs.tev_stage0); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage0.const_r): | ||||
|         SyncTevConstColor(0, regs.texturing.tev_stage0); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage1.const_r): | ||||
|         SyncTevConstColor(1, regs.tev_stage1); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage1.const_r): | ||||
|         SyncTevConstColor(1, regs.texturing.tev_stage1); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage2.const_r): | ||||
|         SyncTevConstColor(2, regs.tev_stage2); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage2.const_r): | ||||
|         SyncTevConstColor(2, regs.texturing.tev_stage2); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage3.const_r): | ||||
|         SyncTevConstColor(3, regs.tev_stage3); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage3.const_r): | ||||
|         SyncTevConstColor(3, regs.texturing.tev_stage3); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage4.const_r): | ||||
|         SyncTevConstColor(4, regs.tev_stage4); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage4.const_r): | ||||
|         SyncTevConstColor(4, regs.texturing.tev_stage4); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(tev_stage5.const_r): | ||||
|         SyncTevConstColor(5, regs.tev_stage5); | ||||
|     case PICA_REG_INDEX(texturing.tev_stage5.const_r): | ||||
|         SyncTevConstColor(5, regs.texturing.tev_stage5); | ||||
|         break; | ||||
| 
 | ||||
|     // TEV combiner buffer color
 | ||||
|     case PICA_REG_INDEX(tev_combiner_buffer_color): | ||||
|     case PICA_REG_INDEX(texturing.tev_combiner_buffer_color): | ||||
|         SyncCombinerColor(); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -976,7 +982,9 @@ void RasterizerOpenGL::SamplerInfo::Create() { | |||
|     // Other attributes have correct defaults
 | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConfig& config) { | ||||
| void RasterizerOpenGL::SamplerInfo::SyncWithConfig( | ||||
|     const Pica::TexturingRegs::TextureConfig& config) { | ||||
| 
 | ||||
|     GLuint s = sampler.handle; | ||||
| 
 | ||||
|     if (mag_filter != config.mag_filter) { | ||||
|  | @ -1088,7 +1096,7 @@ void RasterizerOpenGL::SetShader() { | |||
|         SyncDepthOffset(); | ||||
|         SyncAlphaTest(); | ||||
|         SyncCombinerColor(); | ||||
|         auto& tev_stages = Pica::g_state.regs.GetTevStages(); | ||||
|         auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages(); | ||||
|         for (int index = 0; index < tev_stages.size(); ++index) | ||||
|             SyncTevConstColor(index, tev_stages[index]); | ||||
| 
 | ||||
|  | @ -1110,30 +1118,31 @@ void RasterizerOpenGL::SetShader() { | |||
| void RasterizerOpenGL::SyncCullMode() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
| 
 | ||||
|     switch (regs.cull_mode) { | ||||
|     case Pica::Regs::CullMode::KeepAll: | ||||
|     switch (regs.rasterizer.cull_mode) { | ||||
|     case Pica::RasterizerRegs::CullMode::KeepAll: | ||||
|         state.cull.enabled = false; | ||||
|         break; | ||||
| 
 | ||||
|     case Pica::Regs::CullMode::KeepClockWise: | ||||
|     case Pica::RasterizerRegs::CullMode::KeepClockWise: | ||||
|         state.cull.enabled = true; | ||||
|         state.cull.front_face = GL_CW; | ||||
|         break; | ||||
| 
 | ||||
|     case Pica::Regs::CullMode::KeepCounterClockWise: | ||||
|     case Pica::RasterizerRegs::CullMode::KeepCounterClockWise: | ||||
|         state.cull.enabled = true; | ||||
|         state.cull.front_face = GL_CCW; | ||||
|         break; | ||||
| 
 | ||||
|     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(); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|         uniform_block_data.data.depth_scale = depth_scale; | ||||
|         uniform_block_data.dirty = true; | ||||
|  | @ -1142,7 +1151,7 @@ void RasterizerOpenGL::SyncDepthScale() { | |||
| 
 | ||||
| void RasterizerOpenGL::SyncDepthOffset() { | ||||
|     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) { | ||||
|         uniform_block_data.data.depth_offset = depth_offset; | ||||
|         uniform_block_data.dirty = true; | ||||
|  | @ -1150,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() { | |||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendEnabled() { | ||||
|     state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); | ||||
|     state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendFuncs() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.blend.rgb_equation = | ||||
|         PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); | ||||
|         PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb); | ||||
|     state.blend.a_equation = | ||||
|         PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); | ||||
|         PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a); | ||||
|     state.blend.src_rgb_func = | ||||
|         PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb); | ||||
|     state.blend.dst_rgb_func = | ||||
|         PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); | ||||
|     state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); | ||||
|     state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb); | ||||
|     state.blend.src_a_func = | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a); | ||||
|     state.blend.dst_a_func = | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendColor() { | ||||
|     auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); | ||||
|     auto blend_color = | ||||
|         PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw); | ||||
|     state.blend.color.red = blend_color[0]; | ||||
|     state.blend.color.green = blend_color[1]; | ||||
|     state.blend.color.blue = blend_color[2]; | ||||
|  | @ -1178,8 +1190,8 @@ void RasterizerOpenGL::SyncBlendColor() { | |||
| void RasterizerOpenGL::SyncFogColor() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     uniform_block_data.data.fog_color = { | ||||
|         regs.fog_color.r.Value() / 255.0f, regs.fog_color.g.Value() / 255.0f, | ||||
|         regs.fog_color.b.Value() / 255.0f, | ||||
|         regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f, | ||||
|         regs.texturing.fog_color.b.Value() / 255.0f, | ||||
|     }; | ||||
|     uniform_block_data.dirty = true; | ||||
| } | ||||
|  | @ -1200,70 +1212,78 @@ void RasterizerOpenGL::SyncFogLUT() { | |||
| 
 | ||||
| void RasterizerOpenGL::SyncAlphaTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { | ||||
|         uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; | ||||
|     if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { | ||||
|         uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref; | ||||
|         uniform_block_data.dirty = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncLogicOp() { | ||||
|     state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); | ||||
|     state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncColorWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
| 
 | ||||
|     auto IsColorWriteEnabled = [&](u32 value) { | ||||
|         return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; | ||||
|         return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE | ||||
|                                                                                    : GL_FALSE; | ||||
|     }; | ||||
| 
 | ||||
|     state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); | ||||
|     state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); | ||||
|     state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); | ||||
|     state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); | ||||
|     state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable); | ||||
|     state.color_mask.green_enabled = | ||||
|         IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable); | ||||
|     state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable); | ||||
|     state.color_mask.alpha_enabled = | ||||
|         IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncStencilWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) | ||||
|                                    ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) | ||||
|                                    : 0; | ||||
|     state.stencil.write_mask = | ||||
|         (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) | ||||
|             ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask) | ||||
|             : 0; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncDepthWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.depth.write_mask = | ||||
|         (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) | ||||
|             ? GL_TRUE | ||||
|             : GL_FALSE; | ||||
|     state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && | ||||
|                               regs.framebuffer.output_merger.depth_write_enable) | ||||
|                                  ? GL_TRUE | ||||
|                                  : GL_FALSE; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncStencilTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.stencil.test_enabled = regs.output_merger.stencil_test.enable && | ||||
|                                  regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | ||||
|     state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); | ||||
|     state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; | ||||
|     state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; | ||||
|     state.stencil.test_enabled = | ||||
|         regs.framebuffer.output_merger.stencil_test.enable && | ||||
|         regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; | ||||
|     state.stencil.test_func = | ||||
|         PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func); | ||||
|     state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value; | ||||
|     state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask; | ||||
|     state.stencil.action_stencil_fail = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail); | ||||
|     state.stencil.action_depth_fail = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail); | ||||
|     state.stencil.action_depth_pass = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncDepthTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.depth.test_enabled = | ||||
|         regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; | ||||
|     state.depth.test_func = regs.output_merger.depth_test_enable == 1 | ||||
|                                 ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) | ||||
|                                 : GL_ALWAYS; | ||||
|     state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 || | ||||
|                                regs.framebuffer.output_merger.depth_write_enable == 1; | ||||
|     state.depth.test_func = | ||||
|         regs.framebuffer.output_merger.depth_test_enable == 1 | ||||
|             ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func) | ||||
|             : GL_ALWAYS; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncCombinerColor() { | ||||
|     auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); | ||||
|     auto combiner_color = | ||||
|         PicaToGL::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw); | ||||
|     if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { | ||||
|         uniform_block_data.data.tev_combiner_buffer_color = combiner_color; | ||||
|         uniform_block_data.dirty = true; | ||||
|  | @ -1271,7 +1291,7 @@ void RasterizerOpenGL::SyncCombinerColor() { | |||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncTevConstColor(int stage_index, | ||||
|                                          const Pica::Regs::TevStageConfig& tev_stage) { | ||||
|                                          const Pica::TexturingRegs::TevStageConfig& tev_stage) { | ||||
|     auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); | ||||
|     if (const_color != uniform_block_data.data.const_color[stage_index]) { | ||||
|         uniform_block_data.data.const_color[stage_index] = const_color; | ||||
|  |  | |||
|  | @ -16,10 +16,10 @@ | |||
| #include "common/hash.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/rasterizer_interface.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
|  | @ -52,20 +52,20 @@ union PicaShaderConfig { | |||
| 
 | ||||
|         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 | ||||
|                                     ? regs.output_merger.alpha_test.func.Value() | ||||
|                                     : Pica::Regs::CompareFunc::Always; | ||||
|         state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable | ||||
|                                     ? regs.framebuffer.output_merger.alpha_test.func.Value() | ||||
|                                     : Pica::FramebufferRegs::CompareFunc::Always; | ||||
| 
 | ||||
|         state.texture0_type = regs.texture0.type; | ||||
|         state.texture0_type = regs.texturing.texture0.type; | ||||
| 
 | ||||
|         // Copy relevant tev stages fields.
 | ||||
|         // We don't sync const_color here because of the high variance, it is a
 | ||||
|         // shader uniform instead.
 | ||||
|         const auto& tev_stages = regs.GetTevStages(); | ||||
|         const auto& tev_stages = regs.texturing.GetTevStages(); | ||||
|         DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size()); | ||||
|         for (size_t i = 0; i < tev_stages.size(); i++) { | ||||
|             const auto& tev_stage = tev_stages[i]; | ||||
|  | @ -75,11 +75,12 @@ union PicaShaderConfig { | |||
|             state.tev_stages[i].scales_raw = tev_stage.scales_raw; | ||||
|         } | ||||
| 
 | ||||
|         state.fog_mode = regs.fog_mode; | ||||
|         state.fog_flip = regs.fog_flip != 0; | ||||
|         state.fog_mode = regs.texturing.fog_mode; | ||||
|         state.fog_flip = regs.texturing.fog_flip != 0; | ||||
| 
 | ||||
|         state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||||
|                                       regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||||
|         state.combiner_buffer_input = | ||||
|             regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||||
|             regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||||
| 
 | ||||
|         // Fragment lighting
 | ||||
| 
 | ||||
|  | @ -159,8 +160,8 @@ union PicaShaderConfig { | |||
|         u32 modifiers_raw; | ||||
|         u32 ops_raw; | ||||
|         u32 scales_raw; | ||||
|         explicit operator Pica::Regs::TevStageConfig() const noexcept { | ||||
|             Pica::Regs::TevStageConfig stage; | ||||
|         explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept { | ||||
|             Pica::TexturingRegs::TevStageConfig stage; | ||||
|             stage.sources_raw = sources_raw; | ||||
|             stage.modifiers_raw = modifiers_raw; | ||||
|             stage.ops_raw = ops_raw; | ||||
|  | @ -171,14 +172,14 @@ union PicaShaderConfig { | |||
|     }; | ||||
| 
 | ||||
|     struct State { | ||||
|         Pica::Regs::CompareFunc alpha_test_func; | ||||
|         Pica::Regs::ScissorMode scissor_test_mode; | ||||
|         Pica::Regs::TextureConfig::TextureType texture0_type; | ||||
|         Pica::FramebufferRegs::CompareFunc alpha_test_func; | ||||
|         Pica::RasterizerRegs::ScissorMode scissor_test_mode; | ||||
|         Pica::TexturingRegs::TextureConfig::TextureType texture0_type; | ||||
|         std::array<TevStageConfigRaw, 6> tev_stages; | ||||
|         u8 combiner_buffer_input; | ||||
| 
 | ||||
|         Pica::Regs::DepthBuffering depthmap_enable; | ||||
|         Pica::Regs::FogMode fog_mode; | ||||
|         Pica::RasterizerRegs::DepthBuffering depthmap_enable; | ||||
|         Pica::TexturingRegs::FogMode fog_mode; | ||||
|         bool fog_flip; | ||||
| 
 | ||||
|         struct { | ||||
|  | @ -191,18 +192,18 @@ union PicaShaderConfig { | |||
| 
 | ||||
|             bool enable; | ||||
|             unsigned src_num; | ||||
|             Pica::Regs::LightingBumpMode bump_mode; | ||||
|             Pica::LightingRegs::LightingBumpMode bump_mode; | ||||
|             unsigned bump_selector; | ||||
|             bool bump_renorm; | ||||
|             bool clamp_highlights; | ||||
| 
 | ||||
|             Pica::Regs::LightingConfig config; | ||||
|             Pica::Regs::LightingFresnelSelector fresnel_selector; | ||||
|             Pica::LightingRegs::LightingConfig config; | ||||
|             Pica::LightingRegs::LightingFresnelSelector fresnel_selector; | ||||
| 
 | ||||
|             struct { | ||||
|                 bool enable; | ||||
|                 bool abs_input; | ||||
|                 Pica::Regs::LightingLutInput type; | ||||
|                 Pica::LightingRegs::LightingLutInput type; | ||||
|                 float scale; | ||||
|             } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb; | ||||
|         } lighting; | ||||
|  | @ -251,7 +252,7 @@ public: | |||
| 
 | ||||
| private: | ||||
|     struct SamplerInfo { | ||||
|         using TextureConfig = Pica::Regs::TextureConfig; | ||||
|         using TextureConfig = Pica::TexturingRegs::TextureConfig; | ||||
| 
 | ||||
|         OGLSampler sampler; | ||||
| 
 | ||||
|  | @ -398,7 +399,7 @@ private: | |||
|     void SyncCombinerColor(); | ||||
| 
 | ||||
|     /// Syncs the TEV constant color to match the PICA register
 | ||||
|     void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage); | ||||
|     void SyncTevConstColor(int tev_index, const Pica::TexturingRegs::TevStageConfig& tev_stage); | ||||
| 
 | ||||
|     /// Syncs the lighting global ambient color to match the PICA register
 | ||||
|     void SyncGlobalAmbient(); | ||||
|  |  | |||
|  | @ -342,7 +342,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
|                 Pica::Texture::TextureInfo tex_info; | ||||
|                 tex_info.width = params.width; | ||||
|                 tex_info.height = params.height; | ||||
|                 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; | ||||
|                 tex_info.format = (Pica::TexturingRegs::TextureFormat)params.pixel_format; | ||||
|                 tex_info.SetDefaultStride(); | ||||
|                 tex_info.physical_address = params.addr; | ||||
| 
 | ||||
|  | @ -510,7 +510,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params | |||
| } | ||||
| 
 | ||||
| CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( | ||||
|     const Pica::Regs::FullTextureConfig& config) { | ||||
|     const Pica::TexturingRegs::FullTextureConfig& config) { | ||||
| 
 | ||||
|     Pica::Texture::TextureInfo info = | ||||
|         Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format); | ||||
|  | @ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( | |||
| } | ||||
| 
 | ||||
| std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> | ||||
| RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { | ||||
| RasterizerCacheOpenGL::GetFramebufferSurfaces( | ||||
|     const Pica::FramebufferRegs::FramebufferConfig& config) { | ||||
| 
 | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
| 
 | ||||
|     // Make sur that framebuffers don't overlap if both color and depth are being used
 | ||||
|  | @ -537,11 +539,12 @@ RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfi | |||
|             config.GetColorBufferPhysicalAddress(), | ||||
|             fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), | ||||
|             config.GetDepthBufferPhysicalAddress(), | ||||
|             fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); | ||||
|             fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format)); | ||||
|     bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; | ||||
|     bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && | ||||
|                           (regs.output_merger.depth_test_enable || | ||||
|                            regs.output_merger.depth_write_enable || !framebuffers_overlap); | ||||
|     bool using_depth_fb = | ||||
|         config.GetDepthBufferPhysicalAddress() != 0 && | ||||
|         (regs.framebuffer.output_merger.depth_test_enable || | ||||
|          regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap); | ||||
| 
 | ||||
|     if (framebuffers_overlap && using_color_fb && using_depth_fb) { | ||||
|         LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ | |||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| 
 | ||||
| namespace MathUtil { | ||||
|  | @ -96,15 +96,15 @@ struct CachedSurface { | |||
|         return bpp_table[(unsigned int)format]; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromTextureFormat(Pica::Regs::TextureFormat format) { | ||||
|     static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) { | ||||
|         return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) { | ||||
|     static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { | ||||
|         return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { | ||||
|     static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { | ||||
|         return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) | ||||
|                                           : PixelFormat::Invalid; | ||||
|     } | ||||
|  | @ -212,12 +212,12 @@ public: | |||
|                                   bool load_if_create, MathUtil::Rectangle<int>& out_rect); | ||||
| 
 | ||||
|     /// Gets a surface based on the texture configuration
 | ||||
|     CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); | ||||
|     CachedSurface* GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config); | ||||
| 
 | ||||
|     /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
 | ||||
|     /// configuration
 | ||||
|     std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( | ||||
|         const Pica::Regs::FramebufferConfig& config); | ||||
|         const Pica::FramebufferRegs::FramebufferConfig& config); | ||||
| 
 | ||||
|     /// Attempt to get a surface that exactly matches the fill region and format
 | ||||
|     CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); | ||||
|  |  | |||
|  | @ -7,13 +7,15 @@ | |||
| #include "common/assert.h" | ||||
| #include "common/bit_field.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_gen.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | ||||
| 
 | ||||
| using Pica::Regs; | ||||
| using TevStageConfig = Regs::TevStageConfig; | ||||
| using Pica::RasterizerRegs; | ||||
| using Pica::LightingRegs; | ||||
| using TevStageConfig = Pica::TexturingRegs::TevStageConfig; | ||||
| 
 | ||||
| namespace GLShader { | ||||
| 
 | ||||
|  | @ -46,10 +48,10 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, | |||
|     case Source::Texture0: | ||||
|         // Only unit 0 respects the texturing type (according to 3DBrew)
 | ||||
|         switch (state.texture0_type) { | ||||
|         case Pica::Regs::TextureConfig::Texture2D: | ||||
|         case Pica::TexturingRegs::TextureConfig::Texture2D: | ||||
|             out += "texture(tex[0], texcoord[0])"; | ||||
|             break; | ||||
|         case Pica::Regs::TextureConfig::Projection2D: | ||||
|         case Pica::TexturingRegs::TextureConfig::Projection2D: | ||||
|             out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; | ||||
|             break; | ||||
|         default: | ||||
|  | @ -276,8 +278,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper | |||
| } | ||||
| 
 | ||||
| /// Writes the if-statement condition used to evaluate alpha testing
 | ||||
| static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||||
|     using CompareFunc = Regs::CompareFunc; | ||||
| static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) { | ||||
|     using CompareFunc = Pica::FramebufferRegs::CompareFunc; | ||||
|     switch (func) { | ||||
|     case CompareFunc::Never: | ||||
|         out += "true"; | ||||
|  | @ -307,7 +309,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | |||
| /// Writes the code to emulate the specified TEV stage
 | ||||
| static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | ||||
|     const auto stage = | ||||
|         static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); | ||||
|         static_cast<const Pica::TexturingRegs::TevStageConfig>(config.state.tev_stages[index]); | ||||
|     if (!IsPassThroughTevStage(stage)) { | ||||
|         std::string index_name = std::to_string(index); | ||||
| 
 | ||||
|  | @ -364,7 +366,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|            "vec3 refl_value = vec3(0.0);\n"; | ||||
| 
 | ||||
|     // Compute fragment normals
 | ||||
|     if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { | ||||
|     if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { | ||||
|         // Bump mapping is enabled using a normal map, read perturbation vector from the selected
 | ||||
|         // texture
 | ||||
|         std::string bump_selector = std::to_string(lighting.bump_selector); | ||||
|  | @ -378,7 +380,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|                 "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; | ||||
|             out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; | ||||
|         } | ||||
|     } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { | ||||
|     } else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) { | ||||
|         // Bump mapping is enabled using a tangent map
 | ||||
|         LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)"); | ||||
|         UNIMPLEMENTED(); | ||||
|  | @ -392,23 +394,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|     out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; | ||||
| 
 | ||||
|     // Gets the index into the specified lookup table for specular lighting
 | ||||
|     auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) { | ||||
|     auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input, | ||||
|                                    bool abs) { | ||||
|         const std::string half_angle = "normalize(normalize(view) + light_vector)"; | ||||
|         std::string index; | ||||
|         switch (input) { | ||||
|         case Regs::LightingLutInput::NH: | ||||
|         case LightingRegs::LightingLutInput::NH: | ||||
|             index = "dot(normal, " + half_angle + ")"; | ||||
|             break; | ||||
| 
 | ||||
|         case Regs::LightingLutInput::VH: | ||||
|         case LightingRegs::LightingLutInput::VH: | ||||
|             index = std::string("dot(normalize(view), " + half_angle + ")"); | ||||
|             break; | ||||
| 
 | ||||
|         case Regs::LightingLutInput::NV: | ||||
|         case LightingRegs::LightingLutInput::NV: | ||||
|             index = std::string("dot(normal, normalize(view))"); | ||||
|             break; | ||||
| 
 | ||||
|         case Regs::LightingLutInput::LN: | ||||
|         case LightingRegs::LightingLutInput::LN: | ||||
|             index = std::string("dot(light_vector, normal)"); | ||||
|             break; | ||||
| 
 | ||||
|  | @ -432,7 +435,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|     }; | ||||
| 
 | ||||
|     // Gets the lighting lookup table value given the specified sampler and index
 | ||||
|     auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) { | ||||
|     auto GetLutValue = [](LightingRegs::LightingSampler sampler, std::string lut_index) { | ||||
|         return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " + | ||||
|                            lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]"); | ||||
|     }; | ||||
|  | @ -461,8 +464,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|                                 light_src + ".position) + " + light_src + ".dist_atten_bias)"; | ||||
|             index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; | ||||
|             const unsigned lut_num = | ||||
|                 ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); | ||||
|             dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); | ||||
|                 ((unsigned)LightingRegs::LightingSampler::DistanceAttenuation + light_config.num); | ||||
|             dist_atten = GetLutValue((LightingRegs::LightingSampler)lut_num, index); | ||||
|         } | ||||
| 
 | ||||
|         // If enabled, clamp specular component if lighting result is negative
 | ||||
|  | @ -472,24 +475,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|         // Specular 0 component
 | ||||
|         std::string d0_lut_value = "1.0"; | ||||
|         if (lighting.lut_d0.enable && | ||||
|             Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                    Pica::Regs::LightingSampler::Distribution0)) { | ||||
|             LightingRegs::IsLightingSamplerSupported( | ||||
|                 lighting.config, LightingRegs::LightingSampler::Distribution0)) { | ||||
|             // Lookup specular "distribution 0" LUT value
 | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); | ||||
|             d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + | ||||
|                            GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; | ||||
|                            GetLutValue(LightingRegs::LightingSampler::Distribution0, index) + ")"; | ||||
|         } | ||||
|         std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; | ||||
| 
 | ||||
|         // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
 | ||||
|         if (lighting.lut_rr.enable && | ||||
|             Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                    Pica::Regs::LightingSampler::ReflectRed)) { | ||||
|             LightingRegs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                      LightingRegs::LightingSampler::ReflectRed)) { | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); | ||||
|             std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + | ||||
|                                 GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; | ||||
|                                 GetLutValue(LightingRegs::LightingSampler::ReflectRed, index) + ")"; | ||||
|             out += "refl_value.r = " + value + ";\n"; | ||||
|         } else { | ||||
|             out += "refl_value.r = 1.0;\n"; | ||||
|  | @ -497,12 +500,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 
 | ||||
|         // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
 | ||||
|         if (lighting.lut_rg.enable && | ||||
|             Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                    Pica::Regs::LightingSampler::ReflectGreen)) { | ||||
|             LightingRegs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                      LightingRegs::LightingSampler::ReflectGreen)) { | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); | ||||
|             std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + | ||||
|                                 GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; | ||||
|                                 GetLutValue(LightingRegs::LightingSampler::ReflectGreen, index) + | ||||
|                                 ")"; | ||||
|             out += "refl_value.g = " + value + ";\n"; | ||||
|         } else { | ||||
|             out += "refl_value.g = refl_value.r;\n"; | ||||
|  | @ -510,12 +514,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 
 | ||||
|         // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
 | ||||
|         if (lighting.lut_rb.enable && | ||||
|             Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                    Pica::Regs::LightingSampler::ReflectBlue)) { | ||||
|             LightingRegs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                      LightingRegs::LightingSampler::ReflectBlue)) { | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); | ||||
|             std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + | ||||
|                                 GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; | ||||
|                                 GetLutValue(LightingRegs::LightingSampler::ReflectBlue, index) + | ||||
|                                 ")"; | ||||
|             out += "refl_value.b = " + value + ";\n"; | ||||
|         } else { | ||||
|             out += "refl_value.b = refl_value.r;\n"; | ||||
|  | @ -524,35 +529,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
|         // Specular 1 component
 | ||||
|         std::string d1_lut_value = "1.0"; | ||||
|         if (lighting.lut_d1.enable && | ||||
|             Pica::Regs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                    Pica::Regs::LightingSampler::Distribution1)) { | ||||
|             LightingRegs::IsLightingSamplerSupported( | ||||
|                 lighting.config, LightingRegs::LightingSampler::Distribution1)) { | ||||
|             // Lookup specular "distribution 1" LUT value
 | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); | ||||
|             d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + | ||||
|                            GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; | ||||
|                            GetLutValue(LightingRegs::LightingSampler::Distribution1, index) + ")"; | ||||
|         } | ||||
|         std::string specular_1 = | ||||
|             "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; | ||||
| 
 | ||||
|         // Fresnel
 | ||||
|         if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported( | ||||
|                                           lighting.config, Pica::Regs::LightingSampler::Fresnel)) { | ||||
|         if (lighting.lut_fr.enable && | ||||
|             LightingRegs::IsLightingSamplerSupported(lighting.config, | ||||
|                                                      LightingRegs::LightingSampler::Fresnel)) { | ||||
|             // Lookup fresnel LUT value
 | ||||
|             std::string index = | ||||
|                 GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); | ||||
|             std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + | ||||
|                                 GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; | ||||
|                                 GetLutValue(LightingRegs::LightingSampler::Fresnel, index) + ")"; | ||||
| 
 | ||||
|             // Enabled for difffuse lighting alpha component
 | ||||
|             if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || | ||||
|                 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) | ||||
|             if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha || | ||||
|                 lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { | ||||
|                 out += "diffuse_sum.a  *= " + value + ";\n"; | ||||
|             } | ||||
| 
 | ||||
|             // Enabled for the specular lighting alpha component
 | ||||
|             if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha || | ||||
|                 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) | ||||
|             if (lighting.fresnel_selector == | ||||
|                     LightingRegs::LightingFresnelSelector::SecondaryAlpha || | ||||
|                 lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) { | ||||
|                 out += "specular_sum.a *= " + value + ";\n"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Compute primary fragment color (diffuse lighting) function
 | ||||
|  | @ -633,16 +642,16 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| )"; | ||||
| 
 | ||||
|     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 | ||||
|     if (state.alpha_test_func == Regs::CompareFunc::Never) { | ||||
|     if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) { | ||||
|         out += "discard; }"; | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     // Append the scissor test
 | ||||
|     if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { | ||||
|     if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) { | ||||
|         out += "if ("; | ||||
|         // 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 += "(gl_FragCoord.x >= scissor_x1 && " | ||||
|                "gl_FragCoord.y >= scissor_y1 && " | ||||
|  | @ -652,7 +661,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 
 | ||||
|     out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\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"; | ||||
|     } | ||||
| 
 | ||||
|  | @ -666,14 +675,14 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
|     for (size_t index = 0; index < state.tev_stages.size(); ++index) | ||||
|         WriteTevStage(out, config, (unsigned)index); | ||||
| 
 | ||||
|     if (state.alpha_test_func != Regs::CompareFunc::Always) { | ||||
|     if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) { | ||||
|         out += "if ("; | ||||
|         AppendAlphaTestCondition(out, state.alpha_test_func); | ||||
|         out += ") discard;\n"; | ||||
|     } | ||||
| 
 | ||||
|     // Append fog combiner
 | ||||
|     if (state.fog_mode == Regs::FogMode::Fog) { | ||||
|     if (state.fog_mode == Pica::TexturingRegs::FogMode::Fog) { | ||||
|         // Get index into fog LUT
 | ||||
|         if (state.fog_flip) { | ||||
|             out += "float fog_index = (1.0 - depth) * 128.0;\n"; | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs.h" | ||||
| 
 | ||||
| using GLvec2 = std::array<GLfloat, 2>; | ||||
| using GLvec3 = std::array<GLfloat, 3>; | ||||
|  | @ -20,7 +20,7 @@ using GLvec4 = std::array<GLfloat, 4>; | |||
| 
 | ||||
| namespace PicaToGL { | ||||
| 
 | ||||
| inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { | ||||
| inline GLenum TextureFilterMode(Pica::TexturingRegs::TextureConfig::TextureFilter mode) { | ||||
|     static const GLenum filter_mode_table[] = { | ||||
|         GL_NEAREST, // TextureFilter::Nearest
 | ||||
|         GL_LINEAR,  // TextureFilter::Linear
 | ||||
|  | @ -47,7 +47,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { | |||
|     return gl_mode; | ||||
| } | ||||
| 
 | ||||
| inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { | ||||
| inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) { | ||||
|     static const GLenum wrap_mode_table[] = { | ||||
|         GL_CLAMP_TO_EDGE,   // WrapMode::ClampToEdge
 | ||||
|         GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
 | ||||
|  | @ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { | |||
|     return gl_mode; | ||||
| } | ||||
| 
 | ||||
| inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | ||||
| inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) { | ||||
|     static const GLenum blend_equation_table[] = { | ||||
|         GL_FUNC_ADD,              // BlendEquation::Add
 | ||||
|         GL_FUNC_SUBTRACT,         // BlendEquation::Subtract
 | ||||
|  | @ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | |||
|     return blend_equation_table[(unsigned)equation]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | ||||
| inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) { | ||||
|     static const GLenum blend_func_table[] = { | ||||
|         GL_ZERO,                     // BlendFactor::Zero
 | ||||
|         GL_ONE,                      // BlendFactor::One
 | ||||
|  | @ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
|     return blend_func_table[(unsigned)factor]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum LogicOp(Pica::Regs::LogicOp op) { | ||||
| inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) { | ||||
|     static const GLenum logic_op_table[] = { | ||||
|         GL_CLEAR,         // Clear
 | ||||
|         GL_AND,           // And
 | ||||
|  | @ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) { | |||
|     return logic_op_table[(unsigned)op]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | ||||
| inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) { | ||||
|     static const GLenum compare_func_table[] = { | ||||
|         GL_NEVER,    // CompareFunc::Never
 | ||||
|         GL_ALWAYS,   // CompareFunc::Always
 | ||||
|  | @ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | |||
|     return compare_func_table[(unsigned)func]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum StencilOp(Pica::Regs::StencilAction action) { | ||||
| inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) { | ||||
|     static const GLenum stencil_op_table[] = { | ||||
|         GL_KEEP,      // StencilAction::Keep
 | ||||
|         GL_ZERO,      // StencilAction::Zero
 | ||||
|  | @ -210,7 +210,7 @@ inline GLvec4 ColorRGBA8(const u32 color) { | |||
|     }}; | ||||
| } | ||||
| 
 | ||||
| inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { | ||||
| inline std::array<GLfloat, 3> LightColor(const Pica::LightingRegs::LightColor& color) { | ||||
|     return {{ | ||||
|         color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, | ||||
|     }}; | ||||
|  |  | |||
|  | @ -7,8 +7,8 @@ | |||
| #include "common/bit_set.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/microprofile.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/regs.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/shader/shader_interpreter.h" | ||||
| #ifdef ARCHITECTURE_x86_64 | ||||
|  | @ -20,7 +20,7 @@ namespace Pica { | |||
| 
 | ||||
| namespace Shader { | ||||
| 
 | ||||
| OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) { | ||||
| OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) { | ||||
|     // Setup output data
 | ||||
|     union { | ||||
|         OutputVertex ret{}; | ||||
|  | @ -33,16 +33,16 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer | |||
|     for (unsigned int i = 0; i < num_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_w}; | ||||
| 
 | ||||
|         for (unsigned comp = 0; comp < 4; ++comp) { | ||||
|             Regs::VSOutputAttributes::Semantic semantic = semantics[comp]; | ||||
|             RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp]; | ||||
|             float24* out = &vertex_slots[semantic]; | ||||
|             if (semantic < vertex_slots.size()) { | ||||
|                 *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); | ||||
|             } | ||||
|         } | ||||
|  | @ -66,7 +66,7 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) { | ||||
| void UnitState::LoadInput(const ShaderRegs& config, const AttributeBuffer& input) { | ||||
|     const unsigned max_attribute = config.max_input_attribute_index; | ||||
| 
 | ||||
|     for (unsigned attr = 0; attr <= max_attribute; ++attr) { | ||||
|  | @ -75,7 +75,7 @@ void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffe | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void UnitState::WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output) { | ||||
| void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) { | ||||
|     unsigned int output_i = 0; | ||||
|     for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) { | ||||
|         output.attr[output_i++] = registers.output[reg]; | ||||
|  |  | |||
|  | @ -12,8 +12,8 @@ | |||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/regs.h" | ||||
| 
 | ||||
| using nihstro::RegisterType; | ||||
| using nihstro::SourceRegister; | ||||
|  | @ -39,19 +39,19 @@ struct OutputVertex { | |||
|     INSERT_PADDING_WORDS(1); | ||||
|     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)                                                                       \ | ||||
|     static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong "       \ | ||||
|                                                                         "offset.") | ||||
| ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X); | ||||
| ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X); | ||||
| ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R); | ||||
| ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U); | ||||
| ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U); | ||||
| ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W); | ||||
| ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X); | ||||
| ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U); | ||||
| ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X); | ||||
| ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X); | ||||
| ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R); | ||||
| ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U); | ||||
| ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U); | ||||
| ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W); | ||||
| ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X); | ||||
| ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U); | ||||
| #undef ASSERT_POS | ||||
| static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); | ||||
| static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); | ||||
|  | @ -116,9 +116,9 @@ struct UnitState { | |||
|      * @param config Shader configuration registers corresponding to the unit. | ||||
|      * @param input Attribute buffer to load into the input registers. | ||||
|      */ | ||||
|     void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input); | ||||
|     void LoadInput(const ShaderRegs& config, const AttributeBuffer& input); | ||||
| 
 | ||||
|     void WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output); | ||||
|     void WriteOutput(const ShaderRegs& config, AttributeBuffer& output); | ||||
| }; | ||||
| 
 | ||||
| struct ShaderSetup { | ||||
|  |  | |||
|  | @ -669,7 +669,7 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const { | |||
| 
 | ||||
| DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup, | ||||
|                                                     const AttributeBuffer& input, | ||||
|                                                     const Regs::ShaderConfig& config) const { | ||||
|                                                     const ShaderRegs& config) const { | ||||
|     UnitState state; | ||||
|     DebugData<true> debug_data; | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ public: | |||
|      * @return Debug information for this shader with regards to the given vertex | ||||
|      */ | ||||
|     DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input, | ||||
|                                      const Regs::ShaderConfig& config) const; | ||||
|                                      const ShaderRegs& config) const; | ||||
| }; | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
|  | @ -10,12 +10,12 @@ | |||
| #include "common/math_util.h" | ||||
| #include "common/swap.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| #include "video_core/texture/etc1.h" | ||||
| #include "video_core/texture/texture_decode.h" | ||||
| #include "video_core/utils.h" | ||||
| 
 | ||||
| using TextureFormat = Pica::Regs::TextureFormat; | ||||
| using TextureFormat = Pica::TexturingRegs::TextureFormat; | ||||
| 
 | ||||
| namespace Pica { | ||||
| namespace Texture { | ||||
|  | @ -82,32 +82,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|     using VideoCore::MortonInterleave; | ||||
| 
 | ||||
|     switch (info.format) { | ||||
|     case Regs::TextureFormat::RGBA8: { | ||||
|     case TextureFormat::RGBA8: { | ||||
|         auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4); | ||||
|         return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::RGB8: { | ||||
|     case TextureFormat::RGB8: { | ||||
|         auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3); | ||||
|         return {res.r(), res.g(), res.b(), 255}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::RGB5A1: { | ||||
|     case TextureFormat::RGB5A1: { | ||||
|         auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2); | ||||
|         return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::RGB565: { | ||||
|     case TextureFormat::RGB565: { | ||||
|         auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2); | ||||
|         return {res.r(), res.g(), res.b(), 255}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::RGBA4: { | ||||
|     case TextureFormat::RGBA4: { | ||||
|         auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2); | ||||
|         return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::IA8: { | ||||
|     case TextureFormat::IA8: { | ||||
|         const u8* source_ptr = source + MortonInterleave(x, y) * 2; | ||||
| 
 | ||||
|         if (disable_alpha) { | ||||
|  | @ -118,17 +118,17 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::RG8: { | ||||
|     case TextureFormat::RG8: { | ||||
|         auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2); | ||||
|         return {res.r(), res.g(), 0, 255}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::I8: { | ||||
|     case TextureFormat::I8: { | ||||
|         const u8* source_ptr = source + MortonInterleave(x, y); | ||||
|         return {*source_ptr, *source_ptr, *source_ptr, 255}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::A8: { | ||||
|     case TextureFormat::A8: { | ||||
|         const u8* source_ptr = source + MortonInterleave(x, y); | ||||
| 
 | ||||
|         if (disable_alpha) { | ||||
|  | @ -138,7 +138,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::IA4: { | ||||
|     case TextureFormat::IA4: { | ||||
|         const u8* source_ptr = source + MortonInterleave(x, y); | ||||
| 
 | ||||
|         u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); | ||||
|  | @ -152,7 +152,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::I4: { | ||||
|     case TextureFormat::I4: { | ||||
|         u32 morton_offset = MortonInterleave(x, y); | ||||
|         const u8* source_ptr = source + morton_offset / 2; | ||||
| 
 | ||||
|  | @ -162,7 +162,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|         return {i, i, i, 255}; | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::A4: { | ||||
|     case TextureFormat::A4: { | ||||
|         u32 morton_offset = MortonInterleave(x, y); | ||||
|         const u8* source_ptr = source + morton_offset / 2; | ||||
| 
 | ||||
|  | @ -176,9 +176,9 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     case Regs::TextureFormat::ETC1: | ||||
|     case Regs::TextureFormat::ETC1A4: { | ||||
|         bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); | ||||
|     case TextureFormat::ETC1: | ||||
|     case TextureFormat::ETC1A4: { | ||||
|         bool has_alpha = (info.format == TextureFormat::ETC1A4); | ||||
|         size_t subtile_size = has_alpha ? 16 : 8; | ||||
| 
 | ||||
|         // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
 | ||||
|  | @ -214,8 +214,8 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int | |||
|     } | ||||
| } | ||||
| 
 | ||||
| TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, | ||||
|                                           const Regs::TextureFormat& format) { | ||||
| TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& config, | ||||
|                                           const TexturingRegs::TextureFormat& format) { | ||||
|     TextureInfo info; | ||||
|     info.physical_address = config.GetPhysicalAddress(); | ||||
|     info.width = config.width; | ||||
|  |  | |||
|  | @ -6,27 +6,27 @@ | |||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| namespace Texture { | ||||
| 
 | ||||
| /// Returns the byte size of a 8*8 tile of the specified texture format.
 | ||||
| size_t CalculateTileSize(Pica::Regs::TextureFormat format); | ||||
| size_t CalculateTileSize(TexturingRegs::TextureFormat format); | ||||
| 
 | ||||
| struct TextureInfo { | ||||
|     PAddr physical_address; | ||||
|     unsigned int width; | ||||
|     unsigned int height; | ||||
|     ptrdiff_t stride; | ||||
|     Pica::Regs::TextureFormat format; | ||||
|     TexturingRegs::TextureFormat format; | ||||
| 
 | ||||
|     static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config, | ||||
|                                         const Pica::Regs::TextureFormat& format); | ||||
|     static TextureInfo FromPicaRegister(const TexturingRegs::TextureConfig& config, | ||||
|                                         const TexturingRegs::TextureFormat& format); | ||||
| 
 | ||||
|     /// Calculates stride from format and width, assuming that the entire texture is contiguous.
 | ||||
|     void SetDefaultStride() { | ||||
|         stride = Pica::Texture::CalculateTileSize(format) * (width / 8); | ||||
|         stride = CalculateTileSize(format) * (width / 8); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,15 +8,15 @@ | |||
| #include "common/vector_math.h" | ||||
| #include "core/memory.h" | ||||
| #include "video_core/debug_utils/debug_utils.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/pica_state.h" | ||||
| #include "video_core/pica_types.h" | ||||
| #include "video_core/regs_pipeline.h" | ||||
| #include "video_core/shader/shader.h" | ||||
| #include "video_core/vertex_loader.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| void VertexLoader::Setup(const Pica::Regs& regs) { | ||||
| void VertexLoader::Setup(const PipelineRegs& regs) { | ||||
|     ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once."); | ||||
| 
 | ||||
|     const auto& attribute_config = regs.vertex_attributes; | ||||
|  | @ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, | |||
|                 memory_accesses.AddAccess( | ||||
|                     source_addr, | ||||
|                     vertex_attribute_elements[i] * | ||||
|                         ((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) | ||||
|                         ((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT) | ||||
|                              ? 4 | ||||
|                              : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) | ||||
|                              : (vertex_attribute_formats[i] == | ||||
|                                 PipelineRegs::VertexAttributeFormat::SHORT) | ||||
|                                    ? 2 | ||||
|                                    : 1)); | ||||
|             } | ||||
| 
 | ||||
|             switch (vertex_attribute_formats[i]) { | ||||
|             case Regs::VertexAttributeFormat::BYTE: { | ||||
|             case PipelineRegs::VertexAttributeFormat::BYTE: { | ||||
|                 const s8* srcdata = | ||||
|                     reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr)); | ||||
|                 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | ||||
|  | @ -101,7 +102,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, | |||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             case Regs::VertexAttributeFormat::UBYTE: { | ||||
|             case PipelineRegs::VertexAttributeFormat::UBYTE: { | ||||
|                 const u8* srcdata = | ||||
|                     reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr)); | ||||
|                 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | ||||
|  | @ -109,7 +110,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, | |||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             case Regs::VertexAttributeFormat::SHORT: { | ||||
|             case PipelineRegs::VertexAttributeFormat::SHORT: { | ||||
|                 const s16* srcdata = | ||||
|                     reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr)); | ||||
|                 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | ||||
|  | @ -117,7 +118,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, | |||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             case Regs::VertexAttributeFormat::FLOAT: { | ||||
|             case PipelineRegs::VertexAttributeFormat::FLOAT: { | ||||
|                 const float* srcdata = | ||||
|                     reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr)); | ||||
|                 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| #include <array> | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/pica.h" | ||||
| #include "video_core/regs_pipeline.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
|  | @ -17,11 +17,11 @@ struct AttributeBuffer; | |||
| class VertexLoader { | ||||
| public: | ||||
|     VertexLoader() = default; | ||||
|     explicit VertexLoader(const Pica::Regs& regs) { | ||||
|     explicit VertexLoader(const PipelineRegs& regs) { | ||||
|         Setup(regs); | ||||
|     } | ||||
| 
 | ||||
|     void Setup(const Pica::Regs& regs); | ||||
|     void Setup(const PipelineRegs& regs); | ||||
|     void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, | ||||
|                     DebugUtils::MemoryAccessTracker& memory_accesses); | ||||
| 
 | ||||
|  | @ -32,7 +32,7 @@ public: | |||
| private: | ||||
|     std::array<u32, 16> vertex_attribute_sources; | ||||
|     std::array<u32, 16> vertex_attribute_strides{}; | ||||
|     std::array<Regs::VertexAttributeFormat, 16> vertex_attribute_formats; | ||||
|     std::array<PipelineRegs::VertexAttributeFormat, 16> vertex_attribute_formats; | ||||
|     std::array<u32, 16> vertex_attribute_elements{}; | ||||
|     std::array<bool, 16> vertex_attribute_is_default; | ||||
|     int num_total_attributes = 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue