mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	VideoCore: Split texturing regs from Regs struct
This commit is contained in:
		
							parent
							
								
									000e78144c
								
							
						
					
					
						commit
						9017093f58
					
				
					 17 changed files with 548 additions and 507 deletions
				
			
		|  | @ -123,15 +123,16 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& | |||
| void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | ||||
|     const unsigned int command_id = | ||||
|         list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | ||||
|     if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || | ||||
|         COMMAND_IN_RANGE(command_id, texture2)) { | ||||
|     if (COMMAND_IN_RANGE(command_id, texturing.texture0) || | ||||
|         COMMAND_IN_RANGE(command_id, texturing.texture1) || | ||||
|         COMMAND_IN_RANGE(command_id, texturing.texture2)) { | ||||
| 
 | ||||
|         unsigned texture_index; | ||||
|         if (COMMAND_IN_RANGE(command_id, texture0)) { | ||||
|         if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { | ||||
|             texture_index = 0; | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texture1)) { | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { | ||||
|             texture_index = 1; | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texture2)) { | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texturing.texture2)) { | ||||
|             texture_index = 2; | ||||
|         } else { | ||||
|             UNREACHABLE_MSG("Unknown texture command"); | ||||
|  | @ -146,19 +147,20 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { | |||
| 
 | ||||
|     const unsigned int command_id = | ||||
|         list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); | ||||
|     if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || | ||||
|         COMMAND_IN_RANGE(command_id, texture2)) { | ||||
|     if (COMMAND_IN_RANGE(command_id, texturing.texture0) || | ||||
|         COMMAND_IN_RANGE(command_id, texturing.texture1) || | ||||
|         COMMAND_IN_RANGE(command_id, texturing.texture2)) { | ||||
| 
 | ||||
|         unsigned texture_index; | ||||
|         if (COMMAND_IN_RANGE(command_id, texture0)) { | ||||
|         if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { | ||||
|             texture_index = 0; | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texture1)) { | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { | ||||
|             texture_index = 1; | ||||
|         } else { | ||||
|             texture_index = 2; | ||||
|         } | ||||
| 
 | ||||
|         const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; | ||||
|         const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index]; | ||||
|         const auto config = texture.config; | ||||
|         const auto format = texture.format; | ||||
| 
 | ||||
|  |  | |||
|  | @ -512,7 +512,7 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; | ||||
|         const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index]; | ||||
|         auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format); | ||||
| 
 | ||||
|         surface_address = info.physical_address; | ||||
|  | @ -574,7 +574,7 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
|         info.physical_address = surface_address; | ||||
|         info.width = surface_width; | ||||
|         info.height = surface_height; | ||||
|         info.format = static_cast<Pica::Regs::TextureFormat>(surface_format); | ||||
|         info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface_format); | ||||
|         info.SetDefaultStride(); | ||||
| 
 | ||||
|         for (unsigned int y = 0; y < surface_height; ++y) { | ||||
|  | @ -689,7 +689,8 @@ void GraphicsSurfaceWidget::SaveSurface() { | |||
| 
 | ||||
| unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) { | ||||
|     if (format <= Format::MaxTextureFormat) { | ||||
|         return Pica::Regs::NibblesPerPixel(static_cast<Pica::Regs::TextureFormat>(format)); | ||||
|         return Pica::TexturingRegs::NibblesPerPixel( | ||||
|             static_cast<Pica::TexturingRegs::TextureFormat>(format)); | ||||
|     } | ||||
| 
 | ||||
|     switch (format) { | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ set(HEADERS | |||
|             rasterizer.h | ||||
|             rasterizer_interface.h | ||||
|             regs_rasterizer.h | ||||
|             regs_texturing.h | ||||
|             renderer_base.h | ||||
|             renderer_opengl/gl_rasterizer.h | ||||
|             renderer_opengl/gl_rasterizer_cache.h | ||||
|  |  | |||
|  | @ -225,13 +225,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()); | ||||
|             } | ||||
|  | @ -438,16 +438,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; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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]; | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/regs_rasterizer.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
|  | @ -49,81 +50,7 @@ struct Regs { | |||
|     u32 trigger_irq; | ||||
|     INSERT_PADDING_WORDS(0x2f); | ||||
|     RasterizerRegs rasterizer; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         u32 GetPhysicalAddress() const { | ||||
|             return DecodeAddressRegister(address); | ||||
|         } | ||||
| 
 | ||||
|         // 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
 | ||||
|     }; | ||||
|     TexturingRegs texturing; | ||||
| 
 | ||||
|     enum class LogicOp : u32 { | ||||
|         Clear = 0, | ||||
|  | @ -144,239 +71,6 @@ struct Regs { | |||
|         OrInverted = 15, | ||||
|     }; | ||||
| 
 | ||||
|     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: | ||||
|             return 2; | ||||
| 
 | ||||
|         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<Regs::TevStageConfig, 6> GetTevStages() const { | ||||
|         return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}}; | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendEquation : u32 { | ||||
|         Add = 0, | ||||
|         Subtract = 1, | ||||
|  | @ -1241,26 +935,28 @@ ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65); | |||
| ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68); | ||||
| ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(texture0_enable, 0x80); | ||||
| ASSERT_REG_POSITION(texture0, 0x81); | ||||
| ASSERT_REG_POSITION(texture0_format, 0x8e); | ||||
| ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f); | ||||
| ASSERT_REG_POSITION(texture1, 0x91); | ||||
| ASSERT_REG_POSITION(texture1_format, 0x96); | ||||
| ASSERT_REG_POSITION(texture2, 0x99); | ||||
| ASSERT_REG_POSITION(texture2_format, 0x9e); | ||||
| ASSERT_REG_POSITION(tev_stage0, 0xc0); | ||||
| ASSERT_REG_POSITION(tev_stage1, 0xc8); | ||||
| ASSERT_REG_POSITION(tev_stage2, 0xd0); | ||||
| ASSERT_REG_POSITION(tev_stage3, 0xd8); | ||||
| ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0); | ||||
| ASSERT_REG_POSITION(fog_mode, 0xe0); | ||||
| ASSERT_REG_POSITION(fog_color, 0xe1); | ||||
| ASSERT_REG_POSITION(fog_lut_offset, 0xe6); | ||||
| ASSERT_REG_POSITION(fog_lut_data, 0xe8); | ||||
| ASSERT_REG_POSITION(tev_stage4, 0xf0); | ||||
| ASSERT_REG_POSITION(tev_stage5, 0xf8); | ||||
| ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd); | ||||
| 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(output_merger, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer, 0x110); | ||||
| ASSERT_REG_POSITION(lighting, 0x140); | ||||
|  |  | |||
|  | @ -397,8 +397,8 @@ 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; | ||||
|  | @ -515,9 +515,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; | ||||
|  | @ -536,21 +536,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; | ||||
|  | @ -564,9 +564,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, | ||||
|  | @ -602,17 +602,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) { | ||||
|  | @ -864,14 +866,14 @@ 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(); | ||||
|                 } | ||||
|  | @ -924,16 +926,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; | ||||
|  |  | |||
							
								
								
									
										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
 | ||||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
|  | @ -242,7 +244,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]; | ||||
| 
 | ||||
|  | @ -348,17 +350,17 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         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; | ||||
| 
 | ||||
|  | @ -411,60 +413,60 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         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; | ||||
| 
 | ||||
|  | @ -979,7 +981,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) { | ||||
|  | @ -1091,7 +1095,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]); | ||||
| 
 | ||||
|  | @ -1182,8 +1186,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; | ||||
| } | ||||
|  | @ -1267,7 +1271,8 @@ void RasterizerOpenGL::SyncDepthTest() { | |||
| } | ||||
| 
 | ||||
| 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; | ||||
|  | @ -1275,7 +1280,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; | ||||
|  |  | |||
|  | @ -60,12 +60,12 @@ union PicaShaderConfig { | |||
|                                     ? regs.output_merger.alpha_test.func.Value() | ||||
|                                     : Pica::Regs::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; | ||||
|  | @ -173,12 +174,12 @@ union PicaShaderConfig { | |||
|     struct State { | ||||
|         Pica::Regs::CompareFunc alpha_test_func; | ||||
|         Pica::RasterizerRegs::ScissorMode scissor_test_mode; | ||||
|         Pica::Regs::TextureConfig::TextureType texture0_type; | ||||
|         Pica::TexturingRegs::TextureConfig::TextureType texture0_type; | ||||
|         std::array<TevStageConfigRaw, 6> tev_stages; | ||||
|         u8 combiner_buffer_input; | ||||
| 
 | ||||
|         Pica::RasterizerRegs::DepthBuffering depthmap_enable; | ||||
|         Pica::Regs::FogMode fog_mode; | ||||
|         Pica::TexturingRegs::FogMode fog_mode; | ||||
|         bool fog_flip; | ||||
| 
 | ||||
|         struct { | ||||
|  | @ -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); | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ 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; | ||||
|     } | ||||
| 
 | ||||
|  | @ -212,7 +212,7 @@ 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
 | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
| 
 | ||||
| using Pica::Regs; | ||||
| using Pica::RasterizerRegs; | ||||
| using TevStageConfig = Regs::TevStageConfig; | ||||
| using TevStageConfig = Pica::TexturingRegs::TevStageConfig; | ||||
| 
 | ||||
| namespace GLShader { | ||||
| 
 | ||||
|  | @ -47,10 +47,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: | ||||
|  | @ -308,7 +308,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); | ||||
| 
 | ||||
|  | @ -674,7 +674,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
|     } | ||||
| 
 | ||||
|     // 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"; | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue