VideoCore: Split texturing regs from Regs struct
This commit is contained in:
parent
000e78144c
commit
9017093f58
|
@ -123,15 +123,16 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
|
||||||
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
|
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
|
||||||
const unsigned int command_id =
|
const unsigned int command_id =
|
||||||
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
|
||||||
COMMAND_IN_RANGE(command_id, texture2)) {
|
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
|
||||||
|
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
|
|
||||||
unsigned texture_index;
|
unsigned texture_index;
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0)) {
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
|
||||||
texture_index = 0;
|
texture_index = 0;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
|
||||||
texture_index = 1;
|
texture_index = 1;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture2)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
texture_index = 2;
|
texture_index = 2;
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE_MSG("Unknown texture command");
|
UNREACHABLE_MSG("Unknown texture command");
|
||||||
|
@ -146,19 +147,20 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
|
||||||
|
|
||||||
const unsigned int command_id =
|
const unsigned int command_id =
|
||||||
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
|
||||||
COMMAND_IN_RANGE(command_id, texture2)) {
|
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
|
||||||
|
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
|
|
||||||
unsigned texture_index;
|
unsigned texture_index;
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0)) {
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
|
||||||
texture_index = 0;
|
texture_index = 0;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
|
||||||
texture_index = 1;
|
texture_index = 1;
|
||||||
} else {
|
} else {
|
||||||
texture_index = 2;
|
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 config = texture.config;
|
||||||
const auto format = texture.format;
|
const auto format = texture.format;
|
||||||
|
|
||||||
|
|
|
@ -512,7 +512,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
break;
|
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);
|
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
||||||
|
|
||||||
surface_address = info.physical_address;
|
surface_address = info.physical_address;
|
||||||
|
@ -574,7 +574,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
info.physical_address = surface_address;
|
info.physical_address = surface_address;
|
||||||
info.width = surface_width;
|
info.width = surface_width;
|
||||||
info.height = surface_height;
|
info.height = surface_height;
|
||||||
info.format = static_cast<Pica::Regs::TextureFormat>(surface_format);
|
info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface_format);
|
||||||
info.SetDefaultStride();
|
info.SetDefaultStride();
|
||||||
|
|
||||||
for (unsigned int y = 0; y < surface_height; ++y) {
|
for (unsigned int y = 0; y < surface_height; ++y) {
|
||||||
|
@ -689,7 +689,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
||||||
|
|
||||||
unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
|
unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
|
||||||
if (format <= Format::MaxTextureFormat) {
|
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) {
|
switch (format) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ set(HEADERS
|
||||||
rasterizer.h
|
rasterizer.h
|
||||||
rasterizer_interface.h
|
rasterizer_interface.h
|
||||||
regs_rasterizer.h
|
regs_rasterizer.h
|
||||||
|
regs_texturing.h
|
||||||
renderer_base.h
|
renderer_base.h
|
||||||
renderer_opengl/gl_rasterizer.h
|
renderer_opengl/gl_rasterizer.h
|
||||||
renderer_opengl/gl_rasterizer_cache.h
|
renderer_opengl/gl_rasterizer_cache.h
|
||||||
|
|
|
@ -225,13 +225,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
|
|
||||||
if (g_debug_context && g_debug_context->recorder) {
|
if (g_debug_context && g_debug_context->recorder) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
const auto texture = regs.GetTextures()[i];
|
const auto texture = regs.texturing.GetTextures()[i];
|
||||||
if (!texture.enabled)
|
if (!texture.enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
||||||
g_debug_context->recorder->MemoryAccessed(
|
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.width / 2 * texture.config.height,
|
||||||
texture.config.GetPhysicalAddress());
|
texture.config.GetPhysicalAddress());
|
||||||
}
|
}
|
||||||
|
@ -438,16 +438,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): {
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): {
|
||||||
g_state.fog.lut[regs.fog_lut_offset % 128].raw = value;
|
g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value;
|
||||||
regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1);
|
regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ static void FlushIOFile(png_structp png_ptr) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data) {
|
||||||
#ifndef HAVE_PNG
|
#ifndef HAVE_PNG
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
|
@ -396,7 +396,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
||||||
info.width = texture_config.width;
|
info.width = texture_config.width;
|
||||||
info.height = texture_config.height;
|
info.height = texture_config.height;
|
||||||
info.stride = row_stride;
|
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);
|
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] = texture_color.r();
|
||||||
buf[3 * x + y * row_stride + 1] = texture_color.g();
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) {
|
static std::string GetTevStageConfigSourceString(
|
||||||
using Source = Pica::Regs::TevStageConfig::Source;
|
const TexturingRegs::TevStageConfig::Source& source) {
|
||||||
|
|
||||||
|
using Source = TexturingRegs::TevStageConfig::Source;
|
||||||
static const std::map<Source, std::string> source_map = {
|
static const std::map<Source, std::string> source_map = {
|
||||||
{Source::PrimaryColor, "PrimaryColor"},
|
{Source::PrimaryColor, "PrimaryColor"},
|
||||||
{Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
|
{Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
|
||||||
|
@ -457,9 +459,10 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigColorSourceString(
|
static std::string GetTevStageConfigColorSourceString(
|
||||||
const Pica::Regs::TevStageConfig::Source& source,
|
const TexturingRegs::TevStageConfig::Source& source,
|
||||||
const Pica::Regs::TevStageConfig::ColorModifier modifier) {
|
const TexturingRegs::TevStageConfig::ColorModifier modifier) {
|
||||||
using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
|
|
||||||
|
using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
|
||||||
static const std::map<ColorModifier, std::string> color_modifier_map = {
|
static const std::map<ColorModifier, std::string> color_modifier_map = {
|
||||||
{ColorModifier::SourceColor, "%source.rgb"},
|
{ColorModifier::SourceColor, "%source.rgb"},
|
||||||
{ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
|
{ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
|
||||||
|
@ -483,9 +486,10 @@ static std::string GetTevStageConfigColorSourceString(
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigAlphaSourceString(
|
static std::string GetTevStageConfigAlphaSourceString(
|
||||||
const Pica::Regs::TevStageConfig::Source& source,
|
const TexturingRegs::TevStageConfig::Source& source,
|
||||||
const Pica::Regs::TevStageConfig::AlphaModifier modifier) {
|
const TexturingRegs::TevStageConfig::AlphaModifier modifier) {
|
||||||
using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
|
|
||||||
|
using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
|
||||||
static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
|
static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
|
||||||
{AlphaModifier::SourceAlpha, "%source.a"},
|
{AlphaModifier::SourceAlpha, "%source.a"},
|
||||||
{AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
|
{AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
|
||||||
|
@ -507,8 +511,9 @@ static std::string GetTevStageConfigAlphaSourceString(
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigOperationString(
|
static std::string GetTevStageConfigOperationString(
|
||||||
const Pica::Regs::TevStageConfig::Operation& operation) {
|
const TexturingRegs::TevStageConfig::Operation& operation) {
|
||||||
using Operation = Pica::Regs::TevStageConfig::Operation;
|
|
||||||
|
using Operation = TexturingRegs::TevStageConfig::Operation;
|
||||||
static const std::map<Operation, std::string> combiner_map = {
|
static const std::map<Operation, std::string> combiner_map = {
|
||||||
{Operation::Replace, "%source1"},
|
{Operation::Replace, "%source1"},
|
||||||
{Operation::Modulate, "(%source1 * %source2)"},
|
{Operation::Modulate, "(%source1 * %source2)"},
|
||||||
|
@ -528,7 +533,7 @@ static std::string GetTevStageConfigOperationString(
|
||||||
return op_it->second;
|
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);
|
auto op_str = GetTevStageConfigOperationString(tev_stage.color_op);
|
||||||
op_str = ReplacePattern(
|
op_str = ReplacePattern(
|
||||||
op_str, "%source1",
|
op_str, "%source1",
|
||||||
|
@ -541,7 +546,7 @@ std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfi
|
||||||
GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3));
|
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);
|
auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op);
|
||||||
op_str = ReplacePattern(
|
op_str = ReplacePattern(
|
||||||
op_str, "%source1",
|
op_str, "%source1",
|
||||||
|
@ -554,7 +559,7 @@ std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfi
|
||||||
GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3));
|
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";
|
std::string stage_info = "Tev setup:\n";
|
||||||
for (size_t index = 0; index < stages.size(); ++index) {
|
for (size_t index = 0; index < stages.size(); ++index) {
|
||||||
const auto& tev_stage = stages[index];
|
const auto& tev_stage = stages[index];
|
||||||
|
|
|
@ -205,13 +205,13 @@ inline bool IsPicaTracing() {
|
||||||
void OnPicaRegWrite(PicaTrace::Write write);
|
void OnPicaRegWrite(PicaTrace::Write write);
|
||||||
std::unique_ptr<PicaTrace> FinishPicaTracing();
|
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 GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
|
||||||
std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage);
|
std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
|
||||||
|
|
||||||
/// Dumps the Tev stage config to log at trace level
|
/// 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.
|
* 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/logging/log.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/regs_rasterizer.h"
|
#include "video_core/regs_rasterizer.h"
|
||||||
|
#include "video_core/regs_texturing.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
|
@ -49,81 +50,7 @@ struct Regs {
|
||||||
u32 trigger_irq;
|
u32 trigger_irq;
|
||||||
INSERT_PADDING_WORDS(0x2f);
|
INSERT_PADDING_WORDS(0x2f);
|
||||||
RasterizerRegs rasterizer;
|
RasterizerRegs rasterizer;
|
||||||
|
TexturingRegs texturing;
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class LogicOp : u32 {
|
enum class LogicOp : u32 {
|
||||||
Clear = 0,
|
Clear = 0,
|
||||||
|
@ -144,239 +71,6 @@ struct Regs {
|
||||||
OrInverted = 15,
|
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 {
|
enum class BlendEquation : u32 {
|
||||||
Add = 0,
|
Add = 0,
|
||||||
Subtract = 1,
|
Subtract = 1,
|
||||||
|
@ -1241,26 +935,28 @@ ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65);
|
||||||
ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68);
|
ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68);
|
||||||
ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D);
|
ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D);
|
||||||
|
|
||||||
ASSERT_REG_POSITION(texture0_enable, 0x80);
|
ASSERT_REG_POSITION(texturing, 0x80);
|
||||||
ASSERT_REG_POSITION(texture0, 0x81);
|
ASSERT_REG_POSITION(texturing.texture0_enable, 0x80);
|
||||||
ASSERT_REG_POSITION(texture0_format, 0x8e);
|
ASSERT_REG_POSITION(texturing.texture0, 0x81);
|
||||||
ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f);
|
ASSERT_REG_POSITION(texturing.texture0_format, 0x8e);
|
||||||
ASSERT_REG_POSITION(texture1, 0x91);
|
ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f);
|
||||||
ASSERT_REG_POSITION(texture1_format, 0x96);
|
ASSERT_REG_POSITION(texturing.texture1, 0x91);
|
||||||
ASSERT_REG_POSITION(texture2, 0x99);
|
ASSERT_REG_POSITION(texturing.texture1_format, 0x96);
|
||||||
ASSERT_REG_POSITION(texture2_format, 0x9e);
|
ASSERT_REG_POSITION(texturing.texture2, 0x99);
|
||||||
ASSERT_REG_POSITION(tev_stage0, 0xc0);
|
ASSERT_REG_POSITION(texturing.texture2_format, 0x9e);
|
||||||
ASSERT_REG_POSITION(tev_stage1, 0xc8);
|
ASSERT_REG_POSITION(texturing.tev_stage0, 0xc0);
|
||||||
ASSERT_REG_POSITION(tev_stage2, 0xd0);
|
ASSERT_REG_POSITION(texturing.tev_stage1, 0xc8);
|
||||||
ASSERT_REG_POSITION(tev_stage3, 0xd8);
|
ASSERT_REG_POSITION(texturing.tev_stage2, 0xd0);
|
||||||
ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
|
ASSERT_REG_POSITION(texturing.tev_stage3, 0xd8);
|
||||||
ASSERT_REG_POSITION(fog_mode, 0xe0);
|
ASSERT_REG_POSITION(texturing.tev_combiner_buffer_input, 0xe0);
|
||||||
ASSERT_REG_POSITION(fog_color, 0xe1);
|
ASSERT_REG_POSITION(texturing.fog_mode, 0xe0);
|
||||||
ASSERT_REG_POSITION(fog_lut_offset, 0xe6);
|
ASSERT_REG_POSITION(texturing.fog_color, 0xe1);
|
||||||
ASSERT_REG_POSITION(fog_lut_data, 0xe8);
|
ASSERT_REG_POSITION(texturing.fog_lut_offset, 0xe6);
|
||||||
ASSERT_REG_POSITION(tev_stage4, 0xf0);
|
ASSERT_REG_POSITION(texturing.fog_lut_data, 0xe8);
|
||||||
ASSERT_REG_POSITION(tev_stage5, 0xf8);
|
ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0);
|
||||||
ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
|
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(output_merger, 0x100);
|
||||||
ASSERT_REG_POSITION(framebuffer, 0x110);
|
ASSERT_REG_POSITION(framebuffer, 0x110);
|
||||||
ASSERT_REG_POSITION(lighting, 0x140);
|
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 w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
|
||||||
|
|
||||||
auto textures = regs.GetTextures();
|
auto textures = regs.texturing.GetTextures();
|
||||||
auto tev_stages = regs.GetTevStages();
|
auto tev_stages = regs.texturing.GetTevStages();
|
||||||
|
|
||||||
bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable &&
|
bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable &&
|
||||||
g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
|
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
|
// TODO: Refactor so cubemaps and shadowmaps can be handled
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
switch (texture.config.type) {
|
switch (texture.config.type) {
|
||||||
case Regs::TextureConfig::Texture2D:
|
case TexturingRegs::TextureConfig::Texture2D:
|
||||||
break;
|
break;
|
||||||
case Regs::TextureConfig::Projection2D: {
|
case TexturingRegs::TextureConfig::Projection2D: {
|
||||||
auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
||||||
u /= tc0_w;
|
u /= tc0_w;
|
||||||
v /= 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)))
|
int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
|
||||||
.ToFloat32();
|
.ToFloat32();
|
||||||
|
|
||||||
static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val,
|
static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
|
||||||
unsigned size) {
|
int val, unsigned size) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Regs::TextureConfig::ClampToEdge:
|
case TexturingRegs::TextureConfig::ClampToEdge:
|
||||||
val = std::max(val, 0);
|
val = std::max(val, 0);
|
||||||
val = std::min(val, (int)size - 1);
|
val = std::min(val, (int)size - 1);
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
case Regs::TextureConfig::ClampToBorder:
|
case TexturingRegs::TextureConfig::ClampToBorder:
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
case Regs::TextureConfig::Repeat:
|
case TexturingRegs::TextureConfig::Repeat:
|
||||||
return (int)((unsigned)val % size);
|
return (int)((unsigned)val % size);
|
||||||
|
|
||||||
case Regs::TextureConfig::MirroredRepeat: {
|
case TexturingRegs::TextureConfig::MirroredRepeat: {
|
||||||
unsigned int coord = ((unsigned)val % (2 * size));
|
unsigned int coord = ((unsigned)val % (2 * size));
|
||||||
if (coord >= size)
|
if (coord >= size)
|
||||||
coord = 2 * size - 1 - coord;
|
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)) ||
|
(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))) {
|
(t < 0 || static_cast<u32>(t) >= texture.config.height))) {
|
||||||
auto border_color = texture.config.border_color;
|
auto border_color = texture.config.border_color;
|
||||||
texture_color[i] = {border_color.r, border_color.g, border_color.b,
|
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_output;
|
||||||
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
||||||
Math::Vec4<u8> next_combiner_buffer = {
|
Math::Vec4<u8> next_combiner_buffer = {
|
||||||
regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g,
|
regs.texturing.tev_combiner_buffer_color.r,
|
||||||
regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a,
|
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();
|
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
|
||||||
++tev_stage_index) {
|
++tev_stage_index) {
|
||||||
const auto& tev_stage = tev_stages[tev_stage_index];
|
const auto& tev_stage = tev_stages[tev_stage_index];
|
||||||
using Source = Regs::TevStageConfig::Source;
|
using Source = TexturingRegs::TevStageConfig::Source;
|
||||||
using ColorModifier = Regs::TevStageConfig::ColorModifier;
|
using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
|
||||||
using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
|
using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
|
||||||
using Operation = Regs::TevStageConfig::Operation;
|
using Operation = TexturingRegs::TevStageConfig::Operation;
|
||||||
|
|
||||||
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
|
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
|
||||||
switch (source) {
|
switch (source) {
|
||||||
|
@ -864,14 +866,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
|
|
||||||
combiner_buffer = next_combiner_buffer;
|
combiner_buffer = next_combiner_buffer;
|
||||||
|
|
||||||
if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
|
if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
|
||||||
tev_stage_index)) {
|
tev_stage_index)) {
|
||||||
next_combiner_buffer.r() = combiner_output.r();
|
next_combiner_buffer.r() = combiner_output.r();
|
||||||
next_combiner_buffer.g() = combiner_output.g();
|
next_combiner_buffer.g() = combiner_output.g();
|
||||||
next_combiner_buffer.b() = combiner_output.b();
|
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)) {
|
tev_stage_index)) {
|
||||||
next_combiner_buffer.a() = combiner_output.a();
|
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
|
// 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
|
// store the depth etc. Using float for now until we know more
|
||||||
// about Pica datatypes
|
// about Pica datatypes
|
||||||
if (regs.fog_mode == Regs::FogMode::Fog) {
|
if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
|
||||||
const Math::Vec3<u8> fog_color = {
|
const Math::Vec3<u8> fog_color = {
|
||||||
static_cast<u8>(regs.fog_color.r.Value()),
|
static_cast<u8>(regs.texturing.fog_color.r.Value()),
|
||||||
static_cast<u8>(regs.fog_color.g.Value()),
|
static_cast<u8>(regs.texturing.fog_color.g.Value()),
|
||||||
static_cast<u8>(regs.fog_color.b.Value()),
|
static_cast<u8>(regs.texturing.fog_color.b.Value()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get index into fog LUT
|
// Get index into fog LUT
|
||||||
float fog_index;
|
float fog_index;
|
||||||
if (g_state.regs.fog_flip) {
|
if (g_state.regs.texturing.fog_flip) {
|
||||||
fog_index = (1.0f - depth) * 128.0f;
|
fog_index = (1.0f - depth) * 128.0f;
|
||||||
} else {
|
} else {
|
||||||
fog_index = depth * 128.0f;
|
fog_index = depth * 128.0f;
|
||||||
|
|
|
@ -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_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
|
||||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
|
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
|
||||||
|
|
||||||
static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
|
static bool IsPassThroughTevStage(const Pica::TexturingRegs::TevStageConfig& stage) {
|
||||||
return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
|
||||||
stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
|
||||||
stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
||||||
stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
stage.alpha_op == TevStageConfig::Operation::Replace &&
|
||||||
stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
|
stage.color_source1 == TevStageConfig::Source::Previous &&
|
||||||
stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
|
stage.alpha_source1 == TevStageConfig::Source::Previous &&
|
||||||
|
stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
|
||||||
|
stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
|
||||||
stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
|
stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +244,7 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync and bind the texture surfaces
|
// 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) {
|
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||||
const auto& texture = pica_textures[texture_index];
|
const auto& texture = pica_textures[texture_index];
|
||||||
|
|
||||||
|
@ -348,17 +350,17 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Fog state
|
// Fog state
|
||||||
case PICA_REG_INDEX(fog_color):
|
case PICA_REG_INDEX(texturing.fog_color):
|
||||||
SyncFogColor();
|
SyncFogColor();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef):
|
||||||
uniform_block_data.fog_lut_dirty = true;
|
uniform_block_data.fog_lut_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -411,60 +413,60 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Texture 0 type
|
// Texture 0 type
|
||||||
case PICA_REG_INDEX(texture0.type):
|
case PICA_REG_INDEX(texturing.texture0.type):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV stages
|
// TEV stages
|
||||||
// (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
|
// (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(texturing.tev_stage0.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_scale):
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_input):
|
case PICA_REG_INDEX(texturing.tev_combiner_buffer_input):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage0.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage0.const_r):
|
||||||
SyncTevConstColor(0, regs.tev_stage0);
|
SyncTevConstColor(0, regs.texturing.tev_stage0);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage1.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage1.const_r):
|
||||||
SyncTevConstColor(1, regs.tev_stage1);
|
SyncTevConstColor(1, regs.texturing.tev_stage1);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage2.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage2.const_r):
|
||||||
SyncTevConstColor(2, regs.tev_stage2);
|
SyncTevConstColor(2, regs.texturing.tev_stage2);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage3.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage3.const_r):
|
||||||
SyncTevConstColor(3, regs.tev_stage3);
|
SyncTevConstColor(3, regs.texturing.tev_stage3);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage4.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage4.const_r):
|
||||||
SyncTevConstColor(4, regs.tev_stage4);
|
SyncTevConstColor(4, regs.texturing.tev_stage4);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage5.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage5.const_r):
|
||||||
SyncTevConstColor(5, regs.tev_stage5);
|
SyncTevConstColor(5, regs.texturing.tev_stage5);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV combiner buffer color
|
// TEV combiner buffer color
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
case PICA_REG_INDEX(texturing.tev_combiner_buffer_color):
|
||||||
SyncCombinerColor();
|
SyncCombinerColor();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -979,7 +981,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
|
||||||
// Other attributes have correct defaults
|
// 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;
|
GLuint s = sampler.handle;
|
||||||
|
|
||||||
if (mag_filter != config.mag_filter) {
|
if (mag_filter != config.mag_filter) {
|
||||||
|
@ -1091,7 +1095,7 @@ void RasterizerOpenGL::SetShader() {
|
||||||
SyncDepthOffset();
|
SyncDepthOffset();
|
||||||
SyncAlphaTest();
|
SyncAlphaTest();
|
||||||
SyncCombinerColor();
|
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)
|
for (int index = 0; index < tev_stages.size(); ++index)
|
||||||
SyncTevConstColor(index, tev_stages[index]);
|
SyncTevConstColor(index, tev_stages[index]);
|
||||||
|
|
||||||
|
@ -1182,8 +1186,8 @@ void RasterizerOpenGL::SyncBlendColor() {
|
||||||
void RasterizerOpenGL::SyncFogColor() {
|
void RasterizerOpenGL::SyncFogColor() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
uniform_block_data.data.fog_color = {
|
uniform_block_data.data.fog_color = {
|
||||||
regs.fog_color.r.Value() / 255.0f, regs.fog_color.g.Value() / 255.0f,
|
regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f,
|
||||||
regs.fog_color.b.Value() / 255.0f,
|
regs.texturing.fog_color.b.Value() / 255.0f,
|
||||||
};
|
};
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1271,8 @@ void RasterizerOpenGL::SyncDepthTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCombinerColor() {
|
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) {
|
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
|
||||||
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
|
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
|
@ -1275,7 +1280,7 @@ void RasterizerOpenGL::SyncCombinerColor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevConstColor(int stage_index,
|
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);
|
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
|
||||||
if (const_color != uniform_block_data.data.const_color[stage_index]) {
|
if (const_color != uniform_block_data.data.const_color[stage_index]) {
|
||||||
uniform_block_data.data.const_color[stage_index] = const_color;
|
uniform_block_data.data.const_color[stage_index] = const_color;
|
||||||
|
|
|
@ -60,12 +60,12 @@ union PicaShaderConfig {
|
||||||
? regs.output_merger.alpha_test.func.Value()
|
? regs.output_merger.alpha_test.func.Value()
|
||||||
: Pica::Regs::CompareFunc::Always;
|
: Pica::Regs::CompareFunc::Always;
|
||||||
|
|
||||||
state.texture0_type = regs.texture0.type;
|
state.texture0_type = regs.texturing.texture0.type;
|
||||||
|
|
||||||
// Copy relevant tev stages fields.
|
// Copy relevant tev stages fields.
|
||||||
// We don't sync const_color here because of the high variance, it is a
|
// We don't sync const_color here because of the high variance, it is a
|
||||||
// shader uniform instead.
|
// 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());
|
DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size());
|
||||||
for (size_t i = 0; i < tev_stages.size(); i++) {
|
for (size_t i = 0; i < tev_stages.size(); i++) {
|
||||||
const auto& tev_stage = tev_stages[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.tev_stages[i].scales_raw = tev_stage.scales_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.fog_mode = regs.fog_mode;
|
state.fog_mode = regs.texturing.fog_mode;
|
||||||
state.fog_flip = regs.fog_flip != 0;
|
state.fog_flip = regs.texturing.fog_flip != 0;
|
||||||
|
|
||||||
state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
state.combiner_buffer_input =
|
||||||
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
||||||
|
regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
||||||
|
|
||||||
// Fragment lighting
|
// Fragment lighting
|
||||||
|
|
||||||
|
@ -159,8 +160,8 @@ union PicaShaderConfig {
|
||||||
u32 modifiers_raw;
|
u32 modifiers_raw;
|
||||||
u32 ops_raw;
|
u32 ops_raw;
|
||||||
u32 scales_raw;
|
u32 scales_raw;
|
||||||
explicit operator Pica::Regs::TevStageConfig() const noexcept {
|
explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept {
|
||||||
Pica::Regs::TevStageConfig stage;
|
Pica::TexturingRegs::TevStageConfig stage;
|
||||||
stage.sources_raw = sources_raw;
|
stage.sources_raw = sources_raw;
|
||||||
stage.modifiers_raw = modifiers_raw;
|
stage.modifiers_raw = modifiers_raw;
|
||||||
stage.ops_raw = ops_raw;
|
stage.ops_raw = ops_raw;
|
||||||
|
@ -173,12 +174,12 @@ union PicaShaderConfig {
|
||||||
struct State {
|
struct State {
|
||||||
Pica::Regs::CompareFunc alpha_test_func;
|
Pica::Regs::CompareFunc alpha_test_func;
|
||||||
Pica::RasterizerRegs::ScissorMode scissor_test_mode;
|
Pica::RasterizerRegs::ScissorMode scissor_test_mode;
|
||||||
Pica::Regs::TextureConfig::TextureType texture0_type;
|
Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
|
||||||
std::array<TevStageConfigRaw, 6> tev_stages;
|
std::array<TevStageConfigRaw, 6> tev_stages;
|
||||||
u8 combiner_buffer_input;
|
u8 combiner_buffer_input;
|
||||||
|
|
||||||
Pica::RasterizerRegs::DepthBuffering depthmap_enable;
|
Pica::RasterizerRegs::DepthBuffering depthmap_enable;
|
||||||
Pica::Regs::FogMode fog_mode;
|
Pica::TexturingRegs::FogMode fog_mode;
|
||||||
bool fog_flip;
|
bool fog_flip;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -251,7 +252,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SamplerInfo {
|
struct SamplerInfo {
|
||||||
using TextureConfig = Pica::Regs::TextureConfig;
|
using TextureConfig = Pica::TexturingRegs::TextureConfig;
|
||||||
|
|
||||||
OGLSampler sampler;
|
OGLSampler sampler;
|
||||||
|
|
||||||
|
@ -398,7 +399,7 @@ private:
|
||||||
void SyncCombinerColor();
|
void SyncCombinerColor();
|
||||||
|
|
||||||
/// Syncs the TEV constant color to match the PICA register
|
/// 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
|
/// Syncs the lighting global ambient color to match the PICA register
|
||||||
void SyncGlobalAmbient();
|
void SyncGlobalAmbient();
|
||||||
|
|
|
@ -342,7 +342,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
|
||||||
Pica::Texture::TextureInfo tex_info;
|
Pica::Texture::TextureInfo tex_info;
|
||||||
tex_info.width = params.width;
|
tex_info.width = params.width;
|
||||||
tex_info.height = params.height;
|
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.SetDefaultStride();
|
||||||
tex_info.physical_address = params.addr;
|
tex_info.physical_address = params.addr;
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
|
CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
|
||||||
const Pica::Regs::FullTextureConfig& config) {
|
const Pica::TexturingRegs::FullTextureConfig& config) {
|
||||||
|
|
||||||
Pica::Texture::TextureInfo info =
|
Pica::Texture::TextureInfo info =
|
||||||
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
||||||
|
|
|
@ -96,7 +96,7 @@ struct CachedSurface {
|
||||||
return bpp_table[(unsigned int)format];
|
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;
|
return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ public:
|
||||||
bool load_if_create, MathUtil::Rectangle<int>& out_rect);
|
bool load_if_create, MathUtil::Rectangle<int>& out_rect);
|
||||||
|
|
||||||
/// Gets a surface based on the texture configuration
|
/// 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
|
/// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
|
||||||
/// configuration
|
/// configuration
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
using Pica::Regs;
|
using Pica::Regs;
|
||||||
using Pica::RasterizerRegs;
|
using Pica::RasterizerRegs;
|
||||||
using TevStageConfig = Regs::TevStageConfig;
|
using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
|
||||||
|
|
||||||
namespace GLShader {
|
namespace GLShader {
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config,
|
||||||
case Source::Texture0:
|
case Source::Texture0:
|
||||||
// Only unit 0 respects the texturing type (according to 3DBrew)
|
// Only unit 0 respects the texturing type (according to 3DBrew)
|
||||||
switch (state.texture0_type) {
|
switch (state.texture0_type) {
|
||||||
case Pica::Regs::TextureConfig::Texture2D:
|
case Pica::TexturingRegs::TextureConfig::Texture2D:
|
||||||
out += "texture(tex[0], texcoord[0])";
|
out += "texture(tex[0], texcoord[0])";
|
||||||
break;
|
break;
|
||||||
case Pica::Regs::TextureConfig::Projection2D:
|
case Pica::TexturingRegs::TextureConfig::Projection2D:
|
||||||
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -308,7 +308,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
||||||
/// Writes the code to emulate the specified TEV stage
|
/// Writes the code to emulate the specified TEV stage
|
||||||
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
||||||
const auto stage =
|
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)) {
|
if (!IsPassThroughTevStage(stage)) {
|
||||||
std::string index_name = std::to_string(index);
|
std::string index_name = std::to_string(index);
|
||||||
|
|
||||||
|
@ -674,7 +674,7 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append fog combiner
|
// Append fog combiner
|
||||||
if (state.fog_mode == Regs::FogMode::Fog) {
|
if (state.fog_mode == Pica::TexturingRegs::FogMode::Fog) {
|
||||||
// Get index into fog LUT
|
// Get index into fog LUT
|
||||||
if (state.fog_flip) {
|
if (state.fog_flip) {
|
||||||
out += "float fog_index = (1.0 - depth) * 128.0;\n";
|
out += "float fog_index = (1.0 - depth) * 128.0;\n";
|
||||||
|
|
|
@ -20,7 +20,7 @@ using GLvec4 = std::array<GLfloat, 4>;
|
||||||
|
|
||||||
namespace PicaToGL {
|
namespace PicaToGL {
|
||||||
|
|
||||||
inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
|
inline GLenum TextureFilterMode(Pica::TexturingRegs::TextureConfig::TextureFilter mode) {
|
||||||
static const GLenum filter_mode_table[] = {
|
static const GLenum filter_mode_table[] = {
|
||||||
GL_NEAREST, // TextureFilter::Nearest
|
GL_NEAREST, // TextureFilter::Nearest
|
||||||
GL_LINEAR, // TextureFilter::Linear
|
GL_LINEAR, // TextureFilter::Linear
|
||||||
|
@ -47,7 +47,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
|
||||||
return gl_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[] = {
|
static const GLenum wrap_mode_table[] = {
|
||||||
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
|
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
|
||||||
GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
|
GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "common/vector_math.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/etc1.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
|
||||||
using TextureFormat = Pica::Regs::TextureFormat;
|
using TextureFormat = Pica::TexturingRegs::TextureFormat;
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Texture {
|
namespace Texture {
|
||||||
|
@ -82,32 +82,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
|
||||||
using VideoCore::MortonInterleave;
|
using VideoCore::MortonInterleave;
|
||||||
|
|
||||||
switch (info.format) {
|
switch (info.format) {
|
||||||
case Regs::TextureFormat::RGBA8: {
|
case TextureFormat::RGBA8: {
|
||||||
auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
|
auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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);
|
auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3);
|
||||||
return {res.r(), res.g(), res.b(), 255};
|
return {res.r(), res.g(), res.b(), 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::RGB5A1: {
|
case TextureFormat::RGB5A1: {
|
||||||
auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
|
auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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);
|
auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), 255};
|
return {res.r(), res.g(), res.b(), 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::RGBA4: {
|
case TextureFormat::RGBA4: {
|
||||||
auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
|
auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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;
|
const u8* source_ptr = source + MortonInterleave(x, y) * 2;
|
||||||
|
|
||||||
if (disable_alpha) {
|
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);
|
auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), 0, 255};
|
return {res.r(), res.g(), 0, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::I8: {
|
case TextureFormat::I8: {
|
||||||
const u8* source_ptr = source + MortonInterleave(x, y);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
return {*source_ptr, *source_ptr, *source_ptr, 255};
|
return {*source_ptr, *source_ptr, *source_ptr, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::A8: {
|
case TextureFormat::A8: {
|
||||||
const u8* source_ptr = source + MortonInterleave(x, y);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
|
|
||||||
if (disable_alpha) {
|
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);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
|
|
||||||
u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
|
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);
|
u32 morton_offset = MortonInterleave(x, y);
|
||||||
const u8* source_ptr = source + morton_offset / 2;
|
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};
|
return {i, i, i, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::A4: {
|
case TextureFormat::A4: {
|
||||||
u32 morton_offset = MortonInterleave(x, y);
|
u32 morton_offset = MortonInterleave(x, y);
|
||||||
const u8* source_ptr = source + morton_offset / 2;
|
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 TextureFormat::ETC1:
|
||||||
case Regs::TextureFormat::ETC1A4: {
|
case TextureFormat::ETC1A4: {
|
||||||
bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
|
bool has_alpha = (info.format == TextureFormat::ETC1A4);
|
||||||
size_t subtile_size = has_alpha ? 16 : 8;
|
size_t subtile_size = has_alpha ? 16 : 8;
|
||||||
|
|
||||||
// ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
|
// 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,
|
TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& config,
|
||||||
const Regs::TextureFormat& format) {
|
const TexturingRegs::TextureFormat& format) {
|
||||||
TextureInfo info;
|
TextureInfo info;
|
||||||
info.physical_address = config.GetPhysicalAddress();
|
info.physical_address = config.GetPhysicalAddress();
|
||||||
info.width = config.width;
|
info.width = config.width;
|
||||||
|
|
|
@ -6,27 +6,27 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs_texturing.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Texture {
|
namespace Texture {
|
||||||
|
|
||||||
/// Returns the byte size of a 8*8 tile of the specified texture format.
|
/// 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 {
|
struct TextureInfo {
|
||||||
PAddr physical_address;
|
PAddr physical_address;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
ptrdiff_t stride;
|
ptrdiff_t stride;
|
||||||
Pica::Regs::TextureFormat format;
|
TexturingRegs::TextureFormat format;
|
||||||
|
|
||||||
static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config,
|
static TextureInfo FromPicaRegister(const TexturingRegs::TextureConfig& config,
|
||||||
const Pica::Regs::TextureFormat& format);
|
const TexturingRegs::TextureFormat& format);
|
||||||
|
|
||||||
/// Calculates stride from format and width, assuming that the entire texture is contiguous.
|
/// Calculates stride from format and width, assuming that the entire texture is contiguous.
|
||||||
void SetDefaultStride() {
|
void SetDefaultStride() {
|
||||||
stride = Pica::Texture::CalculateTileSize(format) * (width / 8);
|
stride = CalculateTileSize(format) * (width / 8);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Reference in New Issue