mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
Merge branch 'master' into Texture2DArray
This commit is contained in:
commit
cb8e4a4633
27 changed files with 1480 additions and 1069 deletions
|
@ -153,6 +153,7 @@ struct VisitorInterface : NonCopyable {
|
||||||
|
|
||||||
/// Completion method, called once all fields have been visited
|
/// Completion method, called once all fields have been visited
|
||||||
virtual void Complete() = 0;
|
virtual void Complete() = 0;
|
||||||
|
virtual bool SubmitTestcase() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -178,6 +179,9 @@ struct NullVisitor : public VisitorInterface {
|
||||||
void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
|
void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
|
||||||
|
|
||||||
void Complete() override {}
|
void Complete() override {}
|
||||||
|
bool SubmitTestcase() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Appends build-specific information to the given FieldCollection,
|
/// Appends build-specific information to the given FieldCollection,
|
||||||
|
|
|
@ -57,7 +57,8 @@ struct UUID {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||||
|
|
||||||
using ProfileUsername = std::array<u8, 0x20>;
|
constexpr std::size_t profile_username_size = 32;
|
||||||
|
using ProfileUsername = std::array<u8, profile_username_size>;
|
||||||
using ProfileData = std::array<u8, MAX_DATA>;
|
using ProfileData = std::array<u8, MAX_DATA>;
|
||||||
using UserIDArray = std::array<UUID, MAX_USERS>;
|
using UserIDArray = std::array<UUID, MAX_USERS>;
|
||||||
|
|
||||||
|
|
|
@ -132,11 +132,11 @@ public:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "BindNoticeEvent"},
|
{0, nullptr, "BindNoticeEvent"},
|
||||||
{1, nullptr, "Unknown1"},
|
{1, nullptr, "UnbindNoticeEvent"},
|
||||||
{2, nullptr, "GetStatus"},
|
{2, nullptr, "GetStatus"},
|
||||||
{3, nullptr, "GetNotice"},
|
{3, nullptr, "GetNotice"},
|
||||||
{4, nullptr, "Unknown2"},
|
{4, nullptr, "EnablePowerRequestNotice"},
|
||||||
{5, nullptr, "Unknown3"},
|
{5, nullptr, "DisablePowerRequestNotice"},
|
||||||
{6, nullptr, "ReplyPowerRequest"},
|
{6, nullptr, "ReplyPowerRequest"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() {
|
||||||
backend = nullptr;
|
backend = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TelemetrySession::SubmitTestcase() {
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
field_collection.Accept(*backend);
|
||||||
|
return backend->SubmitTestcase();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -31,6 +31,12 @@ public:
|
||||||
field_collection.AddField(type, name, std::move(value));
|
field_collection.AddField(type, name, std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits a Testcase.
|
||||||
|
* @returns A bool indicating whether the submission succeeded
|
||||||
|
*/
|
||||||
|
bool SubmitTestcase();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
|
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
|
||||||
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
|
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
|
||||||
|
|
|
@ -53,6 +53,8 @@ add_library(video_core STATIC
|
||||||
renderer_opengl/renderer_opengl.h
|
renderer_opengl/renderer_opengl.h
|
||||||
renderer_opengl/utils.cpp
|
renderer_opengl/utils.cpp
|
||||||
renderer_opengl/utils.h
|
renderer_opengl/utils.h
|
||||||
|
surface.cpp
|
||||||
|
surface.h
|
||||||
textures/astc.cpp
|
textures/astc.cpp
|
||||||
textures/astc.h
|
textures/astc.h
|
||||||
textures/decoders.cpp
|
textures/decoders.cpp
|
||||||
|
|
|
@ -43,15 +43,17 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
|
||||||
// Reset the current macro.
|
// Reset the current macro.
|
||||||
executing_macro = 0;
|
executing_macro = 0;
|
||||||
|
|
||||||
// The requested macro must have been uploaded already.
|
// Lookup the macro offset
|
||||||
auto macro_code = uploaded_macros.find(method);
|
const u32 entry{(method - MacroRegistersStart) >> 1};
|
||||||
if (macro_code == uploaded_macros.end()) {
|
const auto& search{macro_offsets.find(entry)};
|
||||||
LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method);
|
if (search == macro_offsets.end()) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "macro not found for method 0x{:X}!", method);
|
||||||
|
UNREACHABLE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the current macro.
|
// Execute the current macro.
|
||||||
macro_interpreter.Execute(macro_code->second, std::move(parameters));
|
macro_interpreter.Execute(search->second, std::move(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||||
|
@ -97,6 +99,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||||
ProcessMacroUpload(value);
|
ProcessMacroUpload(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MAXWELL3D_REG_INDEX(macros.bind): {
|
||||||
|
ProcessMacroBind(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
||||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
||||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
||||||
|
@ -158,9 +164,13 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
||||||
// Store the uploaded macro code to interpret them when they're called.
|
ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
|
||||||
auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart];
|
"upload_address exceeded macro_memory size!");
|
||||||
macro.push_back(data);
|
macro_memory[regs.macros.upload_address++] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Maxwell3D::ProcessMacroBind(u32 data) {
|
||||||
|
macro_offsets[regs.macros.entry] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessQueryGet() {
|
void Maxwell3D::ProcessQueryGet() {
|
||||||
|
|
|
@ -475,12 +475,13 @@ public:
|
||||||
INSERT_PADDING_WORDS(0x45);
|
INSERT_PADDING_WORDS(0x45);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
INSERT_PADDING_WORDS(1);
|
u32 upload_address;
|
||||||
u32 data;
|
u32 data;
|
||||||
u32 entry;
|
u32 entry;
|
||||||
|
u32 bind;
|
||||||
} macros;
|
} macros;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x189);
|
INSERT_PADDING_WORDS(0x188);
|
||||||
|
|
||||||
u32 tfb_enabled;
|
u32 tfb_enabled;
|
||||||
|
|
||||||
|
@ -994,12 +995,25 @@ public:
|
||||||
/// Returns the texture information for a specific texture in a specific shader stage.
|
/// Returns the texture information for a specific texture in a specific shader stage.
|
||||||
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
|
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
|
||||||
|
|
||||||
|
/// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
|
||||||
|
/// we've seen used.
|
||||||
|
using MacroMemory = std::array<u32, 0x40000>;
|
||||||
|
|
||||||
|
/// Gets a reference to macro memory.
|
||||||
|
const MacroMemory& GetMacroMemory() const {
|
||||||
|
return macro_memory;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeRegisterDefaults();
|
void InitializeRegisterDefaults();
|
||||||
|
|
||||||
VideoCore::RasterizerInterface& rasterizer;
|
VideoCore::RasterizerInterface& rasterizer;
|
||||||
|
|
||||||
std::unordered_map<u32, std::vector<u32>> uploaded_macros;
|
/// Start offsets of each macro in macro_memory
|
||||||
|
std::unordered_map<u32, u32> macro_offsets;
|
||||||
|
|
||||||
|
/// Memory for macro code
|
||||||
|
MacroMemory macro_memory;
|
||||||
|
|
||||||
/// Macro method that is currently being executed / being fed parameters.
|
/// Macro method that is currently being executed / being fed parameters.
|
||||||
u32 executing_macro = 0;
|
u32 executing_macro = 0;
|
||||||
|
@ -1022,9 +1036,12 @@ private:
|
||||||
*/
|
*/
|
||||||
void CallMacroMethod(u32 method, std::vector<u32> parameters);
|
void CallMacroMethod(u32 method, std::vector<u32> parameters);
|
||||||
|
|
||||||
/// Handles writes to the macro uploading registers.
|
/// Handles writes to the macro uploading register.
|
||||||
void ProcessMacroUpload(u32 data);
|
void ProcessMacroUpload(u32 data);
|
||||||
|
|
||||||
|
/// Handles writes to the macro bind register.
|
||||||
|
void ProcessMacroBind(u32 data);
|
||||||
|
|
||||||
/// Handles a write to the CLEAR_BUFFERS register.
|
/// Handles a write to the CLEAR_BUFFERS register.
|
||||||
void ProcessClearBuffers();
|
void ProcessClearBuffers();
|
||||||
|
|
||||||
|
|
|
@ -577,6 +577,10 @@ union Instruction {
|
||||||
BitField<55, 1, u64> saturate;
|
BitField<55, 1, u64> saturate;
|
||||||
} fmul32;
|
} fmul32;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<52, 1, u64> generates_cc;
|
||||||
|
} op_32;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<48, 1, u64> is_signed;
|
BitField<48, 1, u64> is_signed;
|
||||||
} shift;
|
} shift;
|
||||||
|
@ -1231,6 +1235,7 @@ union Instruction {
|
||||||
BitField<60, 1, u64> is_b_gpr;
|
BitField<60, 1, u64> is_b_gpr;
|
||||||
BitField<59, 1, u64> is_c_gpr;
|
BitField<59, 1, u64> is_c_gpr;
|
||||||
BitField<20, 24, s64> smem_imm;
|
BitField<20, 24, s64> smem_imm;
|
||||||
|
BitField<0, 5, ControlCode> flow_control_code;
|
||||||
|
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
Sampler sampler;
|
Sampler sampler;
|
||||||
|
@ -1658,4 +1663,4 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Tegra::Shader
|
} // namespace Tegra::Shader
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Tegra {
|
||||||
|
|
||||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
||||||
|
|
||||||
void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) {
|
void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
|
||||||
Reset();
|
Reset();
|
||||||
registers[1] = parameters[0];
|
registers[1] = parameters[0];
|
||||||
this->parameters = std::move(parameters);
|
this->parameters = std::move(parameters);
|
||||||
|
@ -19,7 +19,7 @@ void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> pa
|
||||||
// Execute the code until we hit an exit condition.
|
// Execute the code until we hit an exit condition.
|
||||||
bool keep_executing = true;
|
bool keep_executing = true;
|
||||||
while (keep_executing) {
|
while (keep_executing) {
|
||||||
keep_executing = Step(code, false);
|
keep_executing = Step(offset, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert the the macro used all the input parameters
|
// Assert the the macro used all the input parameters
|
||||||
|
@ -37,10 +37,10 @@ void MacroInterpreter::Reset() {
|
||||||
next_parameter_index = 1;
|
next_parameter_index = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
|
bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||||
u32 base_address = pc;
|
u32 base_address = pc;
|
||||||
|
|
||||||
Opcode opcode = GetOpcode(code);
|
Opcode opcode = GetOpcode(offset);
|
||||||
pc += 4;
|
pc += 4;
|
||||||
|
|
||||||
// Update the program counter if we were delayed
|
// Update the program counter if we were delayed
|
||||||
|
@ -108,7 +108,7 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
|
||||||
|
|
||||||
delayed_pc = base_address + opcode.GetBranchTarget();
|
delayed_pc = base_address + opcode.GetBranchTarget();
|
||||||
// Execute one more instruction due to the delay slot.
|
// Execute one more instruction due to the delay slot.
|
||||||
return Step(code, true);
|
return Step(offset, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -121,17 +121,18 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
|
||||||
// Exit has a delay slot, execute the next instruction
|
// Exit has a delay slot, execute the next instruction
|
||||||
// Note: Executing an exit during a branch delay slot will cause the instruction at the
|
// Note: Executing an exit during a branch delay slot will cause the instruction at the
|
||||||
// branch target to be executed before exiting.
|
// branch target to be executed before exiting.
|
||||||
Step(code, true);
|
Step(offset, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const {
|
MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
|
||||||
|
const auto& macro_memory{maxwell3d.GetMacroMemory()};
|
||||||
ASSERT((pc % sizeof(u32)) == 0);
|
ASSERT((pc % sizeof(u32)) == 0);
|
||||||
ASSERT(pc < code.size() * sizeof(u32));
|
ASSERT((pc + offset) < macro_memory.size() * sizeof(u32));
|
||||||
return {code[pc / sizeof(u32)]};
|
return {macro_memory[offset + pc / sizeof(u32)]};
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
|
u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
|
||||||
|
|
|
@ -22,10 +22,10 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the macro code with the specified input parameters.
|
* Executes the macro code with the specified input parameters.
|
||||||
* @param code The macro byte code to execute
|
* @param offset Offset to start execution at.
|
||||||
* @param parameters The parameters of the macro
|
* @param parameters The parameters of the macro.
|
||||||
*/
|
*/
|
||||||
void Execute(const std::vector<u32>& code, std::vector<u32> parameters);
|
void Execute(u32 offset, std::vector<u32> parameters);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Operation : u32 {
|
enum class Operation : u32 {
|
||||||
|
@ -110,11 +110,11 @@ private:
|
||||||
/**
|
/**
|
||||||
* Executes a single macro instruction located at the current program counter. Returns whether
|
* Executes a single macro instruction located at the current program counter. Returns whether
|
||||||
* the interpreter should keep running.
|
* the interpreter should keep running.
|
||||||
* @param code The macro code to execute.
|
* @param offset Offset to start execution at.
|
||||||
* @param is_delay_slot Whether the current step is being executed due to a delay slot in a
|
* @param is_delay_slot Whether the current step is being executed due to a delay slot in a
|
||||||
* previous instruction.
|
* previous instruction.
|
||||||
*/
|
*/
|
||||||
bool Step(const std::vector<u32>& code, bool is_delay_slot);
|
bool Step(u32 offset, bool is_delay_slot);
|
||||||
|
|
||||||
/// Calculates the result of an ALU operation. src_a OP src_b;
|
/// Calculates the result of an ALU operation. src_a OP src_b;
|
||||||
u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
|
u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
|
||||||
|
@ -127,7 +127,7 @@ private:
|
||||||
bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
|
bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
|
||||||
|
|
||||||
/// Reads an opcode at the current program counter location.
|
/// Reads an opcode at the current program counter location.
|
||||||
Opcode GetOpcode(const std::vector<u32>& code) const;
|
Opcode GetOpcode(u32 offset) const;
|
||||||
|
|
||||||
/// Returns the specified register's value. Register 0 is hardcoded to always return 0.
|
/// Returns the specified register's value. Register 0 is hardcoded to always return 0.
|
||||||
u32 GetRegister(u32 register_id) const;
|
u32 GetRegister(u32 register_id) const;
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
using PixelFormat = SurfaceParams::PixelFormat;
|
using PixelFormat = VideoCore::Surface::PixelFormat;
|
||||||
using SurfaceType = SurfaceParams::SurfaceType;
|
using SurfaceType = VideoCore::Surface::SurfaceType;
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
|
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
|
||||||
MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
|
MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
|
||||||
|
@ -104,7 +104,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
|
ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
|
||||||
|
OpenGLState::ApplyDefaultState();
|
||||||
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
|
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
|
||||||
state.clip_distance[0] = true;
|
state.clip_distance[0] = true;
|
||||||
|
|
||||||
|
@ -115,8 +115,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||||
state.draw.shader_program = 0;
|
state.draw.shader_program = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
|
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
||||||
|
|
||||||
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
|
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
|
||||||
|
@ -703,7 +701,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||||
|
|
||||||
// Verify that the cached surface is the same size and format as the requested framebuffer
|
// Verify that the cached surface is the same size and format as the requested framebuffer
|
||||||
const auto& params{surface->GetSurfaceParams()};
|
const auto& params{surface->GetSurfaceParams()};
|
||||||
const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)};
|
const auto& pixel_format{
|
||||||
|
VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
|
||||||
ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
|
ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
|
||||||
ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
|
ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
|
||||||
ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
|
ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
|
||||||
|
|
|
@ -17,15 +17,20 @@
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
#include "video_core/textures/astc.h"
|
#include "video_core/textures/astc.h"
|
||||||
#include "video_core/textures/decoders.h"
|
#include "video_core/textures/decoders.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using SurfaceType = SurfaceParams::SurfaceType;
|
using VideoCore::Surface::ComponentTypeFromDepthFormat;
|
||||||
using PixelFormat = SurfaceParams::PixelFormat;
|
using VideoCore::Surface::ComponentTypeFromRenderTarget;
|
||||||
using ComponentType = SurfaceParams::ComponentType;
|
using VideoCore::Surface::ComponentTypeFromTexture;
|
||||||
|
using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||||
|
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||||
|
using VideoCore::Surface::PixelFormatFromTextureFormat;
|
||||||
|
using VideoCore::Surface::SurfaceTargetFromTextureType;
|
||||||
|
|
||||||
struct FormatTuple {
|
struct FormatTuple {
|
||||||
GLint internal_format;
|
GLint internal_format;
|
||||||
|
@ -35,46 +40,6 @@ struct FormatTuple {
|
||||||
bool compressed;
|
bool compressed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool IsPixelFormatASTC(PixelFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::ASTC_2D_4X4:
|
|
||||||
case PixelFormat::ASTC_2D_5X4:
|
|
||||||
case PixelFormat::ASTC_2D_8X8:
|
|
||||||
case PixelFormat::ASTC_2D_8X5:
|
|
||||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
|
||||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::ASTC_2D_4X4:
|
|
||||||
return {4, 4};
|
|
||||||
case PixelFormat::ASTC_2D_5X4:
|
|
||||||
return {5, 4};
|
|
||||||
case PixelFormat::ASTC_2D_8X8:
|
|
||||||
return {8, 8};
|
|
||||||
case PixelFormat::ASTC_2D_8X5:
|
|
||||||
return {8, 5};
|
|
||||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
|
||||||
return {4, 4};
|
|
||||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
|
||||||
return {5, 4};
|
|
||||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
|
||||||
return {8, 8};
|
|
||||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
|
||||||
return {8, 5};
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
|
void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
|
||||||
auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
|
auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
|
||||||
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
|
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
|
||||||
|
@ -267,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
|
static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
|
||||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
|
||||||
{GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
|
{GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
|
||||||
{GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
|
{GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
|
||||||
|
@ -355,19 +320,19 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
|
||||||
ComponentType::Float, false}, // Z32FS8
|
ComponentType::Float, false}, // Z32FS8
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
|
static GLenum SurfaceTargetToGL(SurfaceTarget target) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
return GL_TEXTURE_1D;
|
return GL_TEXTURE_1D;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
return GL_TEXTURE_2D;
|
return GL_TEXTURE_2D;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
return GL_TEXTURE_3D;
|
return GL_TEXTURE_3D;
|
||||||
case SurfaceParams::SurfaceTarget::Texture1DArray:
|
case SurfaceTarget::Texture1DArray:
|
||||||
return GL_TEXTURE_1D_ARRAY;
|
return GL_TEXTURE_1D_ARRAY;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
return GL_TEXTURE_2D_ARRAY;
|
return GL_TEXTURE_2D_ARRAY;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceTarget::TextureCubemap:
|
||||||
return GL_TEXTURE_CUBE_MAP;
|
return GL_TEXTURE_CUBE_MAP;
|
||||||
}
|
}
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
||||||
|
@ -392,31 +357,10 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
|
||||||
return {0, actual_height, MipWidth(mip_level), 0};
|
return {0, actual_height, MipWidth(mip_level), 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
|
|
||||||
static bool IsFormatBCn(PixelFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::DXT1:
|
|
||||||
case PixelFormat::DXT23:
|
|
||||||
case PixelFormat::DXT45:
|
|
||||||
case PixelFormat::DXN1:
|
|
||||||
case PixelFormat::DXN2SNORM:
|
|
||||||
case PixelFormat::DXN2UNORM:
|
|
||||||
case PixelFormat::BC7U:
|
|
||||||
case PixelFormat::BC6H_UF16:
|
|
||||||
case PixelFormat::BC6H_SF16:
|
|
||||||
case PixelFormat::DXT1_SRGB:
|
|
||||||
case PixelFormat::DXT23_SRGB:
|
|
||||||
case PixelFormat::DXT45_SRGB:
|
|
||||||
case PixelFormat::BC7U_SRGB:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool morton_to_gl, PixelFormat format>
|
template <bool morton_to_gl, PixelFormat format>
|
||||||
void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
|
void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
|
||||||
std::size_t gl_buffer_size, VAddr addr) {
|
std::size_t gl_buffer_size, VAddr addr) {
|
||||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format);
|
constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
|
||||||
|
|
||||||
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
|
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
|
||||||
// pixel values.
|
// pixel values.
|
||||||
|
@ -435,7 +379,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
|
||||||
}
|
}
|
||||||
|
|
||||||
using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
|
using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
|
||||||
SurfaceParams::MaxPixelFormat>;
|
VideoCore::Surface::MaxPixelFormat>;
|
||||||
|
|
||||||
static constexpr GLConversionArray morton_to_gl_fns = {
|
static constexpr GLConversionArray morton_to_gl_fns = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -575,7 +519,7 @@ static constexpr GLConversionArray gl_to_morton_fns = {
|
||||||
void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
|
void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
|
||||||
std::vector<u8>& gl_buffer, u32 mip_level) {
|
std::vector<u8>& gl_buffer, u32 mip_level) {
|
||||||
u32 depth = params.MipDepth(mip_level);
|
u32 depth = params.MipDepth(mip_level);
|
||||||
if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
|
if (params.target == SurfaceTarget::Texture2D) {
|
||||||
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
|
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
|
||||||
depth = 1U;
|
depth = 1U;
|
||||||
}
|
}
|
||||||
|
@ -622,13 +566,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
|
|
||||||
if (src_params.type == SurfaceType::ColorTexture) {
|
if (src_params.type == SurfaceType::ColorTexture) {
|
||||||
switch (src_params.target) {
|
switch (src_params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||||
GL_TEXTURE_2D, src_surface->Texture().handle, 0);
|
GL_TEXTURE_2D, src_surface->Texture().handle, 0);
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
0, 0);
|
0, 0);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceTarget::TextureCubemap:
|
||||||
glFramebufferTexture2D(
|
glFramebufferTexture2D(
|
||||||
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
||||||
|
@ -637,12 +581,12 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||||
src_surface->Texture().handle, 0, 0);
|
src_surface->Texture().handle, 0, 0);
|
||||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||||
SurfaceTargetToGL(src_params.target),
|
SurfaceTargetToGL(src_params.target),
|
||||||
src_surface->Texture().handle, 0, 0);
|
src_surface->Texture().handle, 0, 0);
|
||||||
|
@ -658,13 +602,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dst_params.target) {
|
switch (dst_params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||||
GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
|
GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
0, 0);
|
0, 0);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceTarget::TextureCubemap:
|
||||||
glFramebufferTexture2D(
|
glFramebufferTexture2D(
|
||||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
||||||
|
@ -673,13 +617,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||||
dst_surface->Texture().handle, 0, 0);
|
dst_surface->Texture().handle, 0, 0);
|
||||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||||
SurfaceTargetToGL(dst_params.target),
|
SurfaceTargetToGL(dst_params.target),
|
||||||
dst_surface->Texture().handle, 0, 0);
|
dst_surface->Texture().handle, 0, 0);
|
||||||
|
@ -800,21 +744,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
} else {
|
} else {
|
||||||
switch (dst_params.target) {
|
switch (dst_params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
|
glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
|
||||||
dest_format.type, nullptr);
|
dest_format.type, nullptr);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
|
glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
|
||||||
dest_format.format, dest_format.type, nullptr);
|
dest_format.format, dest_format.type, nullptr);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
|
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
|
||||||
static_cast<GLsizei>(dst_params.depth), dest_format.format,
|
static_cast<GLsizei>(dst_params.depth), dest_format.format,
|
||||||
dest_format.type, nullptr);
|
dest_format.type, nullptr);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceTarget::TextureCubemap:
|
||||||
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
|
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
|
||||||
static_cast<GLint>(cubemap_face), width, height, 1,
|
static_cast<GLint>(cubemap_face), width, height, 1,
|
||||||
dest_format.format, dest_format.type, nullptr);
|
dest_format.format, dest_format.type, nullptr);
|
||||||
|
@ -851,17 +795,17 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||||
if (!format_tuple.compressed) {
|
if (!format_tuple.compressed) {
|
||||||
// Only pre-create the texture for non-compressed textures.
|
// Only pre-create the texture for non-compressed textures.
|
||||||
switch (params.target) {
|
switch (params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||||
format_tuple.internal_format, rect.GetWidth());
|
format_tuple.internal_format, rect.GetWidth());
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceTarget::TextureCubemap:
|
||||||
glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
|
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
|
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
|
||||||
params.depth);
|
params.depth);
|
||||||
|
@ -916,7 +860,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
|
||||||
|
|
||||||
S8Z24 s8z24_pixel{};
|
S8Z24 s8z24_pixel{};
|
||||||
Z24S8 z24s8_pixel{};
|
Z24S8 z24s8_pixel{};
|
||||||
constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)};
|
constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
|
||||||
for (std::size_t y = 0; y < height; ++y) {
|
for (std::size_t y = 0; y < height; ++y) {
|
||||||
for (std::size_t x = 0; x < width; ++x) {
|
for (std::size_t x = 0; x < width; ++x) {
|
||||||
const std::size_t offset{bpp * (y * width + x)};
|
const std::size_t offset{bpp * (y * width + x)};
|
||||||
|
@ -936,7 +880,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
|
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
|
||||||
constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)};
|
constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
|
||||||
for (std::size_t y = 0; y < height; ++y) {
|
for (std::size_t y = 0; y < height; ++y) {
|
||||||
for (std::size_t x = 0; x < width; ++x) {
|
for (std::size_t x = 0; x < width; ++x) {
|
||||||
const std::size_t offset{bpp * (y * width + x)};
|
const std::size_t offset{bpp * (y * width + x)};
|
||||||
|
@ -1042,7 +986,7 @@ void CachedSurface::FlushGLBuffer() {
|
||||||
|
|
||||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||||
ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
|
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
|
||||||
ASSERT(!tuple.compressed);
|
ASSERT(!tuple.compressed);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||||
|
@ -1074,7 +1018,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
std::size_t buffer_offset =
|
std::size_t buffer_offset =
|
||||||
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
|
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
|
||||||
static_cast<std::size_t>(x0)) *
|
static_cast<std::size_t>(x0)) *
|
||||||
SurfaceParams::GetBytesPerPixel(params.pixel_format);
|
GetBytesPerPixel(params.pixel_format);
|
||||||
|
|
||||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
const GLuint target_tex = texture.handle;
|
const GLuint target_tex = texture.handle;
|
||||||
|
@ -1090,35 +1034,34 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||||
ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 ==
|
ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||||
0);
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
|
||||||
|
|
||||||
GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
|
GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
if (tuple.compressed) {
|
if (tuple.compressed) {
|
||||||
switch (params.target) {
|
switch (params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
|
static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
|
static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
||||||
static_cast<GLsizei>(params.depth), 0, image_size,
|
static_cast<GLsizei>(params.depth), 0, image_size,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap: {
|
case SurfaceTarget::TextureCubemap: {
|
||||||
GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
|
GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
|
||||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||||
glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
|
glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
|
||||||
|
@ -1143,30 +1086,30 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
switch (params.target) {
|
switch (params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
|
glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
|
static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
|
glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||||
&gl_buffer[mip_map][buffer_offset]);
|
&gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceTarget::Texture3D:
|
||||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
|
static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
|
||||||
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceTarget::Texture2DArray:
|
||||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
||||||
static_cast<GLsizei>(rect.GetWidth()),
|
static_cast<GLsizei>(rect.GetWidth()),
|
||||||
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
||||||
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||||
break;
|
break;
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap: {
|
case SurfaceTarget::TextureCubemap: {
|
||||||
std::size_t start = buffer_offset;
|
std::size_t start = buffer_offset;
|
||||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||||
glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
|
glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
|
||||||
|
@ -1341,8 +1284,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||||
// For compatible surfaces, we can just do fast glCopyImageSubData based copy
|
// For compatible surfaces, we can just do fast glCopyImageSubData based copy
|
||||||
if (old_params.target == new_params.target && old_params.type == new_params.type &&
|
if (old_params.target == new_params.target && old_params.type == new_params.type &&
|
||||||
old_params.depth == new_params.depth && old_params.depth == 1 &&
|
old_params.depth == new_params.depth && old_params.depth == 1 &&
|
||||||
SurfaceParams::GetFormatBpp(old_params.pixel_format) ==
|
GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) {
|
||||||
SurfaceParams::GetFormatBpp(new_params.pixel_format)) {
|
|
||||||
FastCopySurface(old_surface, new_surface);
|
FastCopySurface(old_surface, new_surface);
|
||||||
return new_surface;
|
return new_surface;
|
||||||
}
|
}
|
||||||
|
@ -1355,13 +1297,14 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||||
const bool is_blit{old_params.pixel_format == new_params.pixel_format};
|
const bool is_blit{old_params.pixel_format == new_params.pixel_format};
|
||||||
|
|
||||||
switch (new_params.target) {
|
switch (new_params.target) {
|
||||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
case SurfaceTarget::Texture2D:
|
||||||
if (is_blit) {
|
if (is_blit) {
|
||||||
BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
|
BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
|
||||||
} else {
|
} else {
|
||||||
CopySurface(old_surface, new_surface, copy_pbo.handle);
|
CopySurface(old_surface, new_surface, copy_pbo.handle);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
@ -1374,7 +1317,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_surface;
|
return new_surface;
|
||||||
} // namespace OpenGL
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
|
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
|
||||||
return TryGet(addr);
|
return TryGet(addr);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include "video_core/rasterizer_cache.h"
|
#include "video_core/rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
#include "video_core/textures/decoders.h"
|
#include "video_core/textures/decoders.h"
|
||||||
#include "video_core/textures/texture.h"
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
@ -27,135 +29,12 @@ class CachedSurface;
|
||||||
using Surface = std::shared_ptr<CachedSurface>;
|
using Surface = std::shared_ptr<CachedSurface>;
|
||||||
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
|
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
|
||||||
|
|
||||||
|
using SurfaceTarget = VideoCore::Surface::SurfaceTarget;
|
||||||
|
using SurfaceType = VideoCore::Surface::SurfaceType;
|
||||||
|
using PixelFormat = VideoCore::Surface::PixelFormat;
|
||||||
|
using ComponentType = VideoCore::Surface::ComponentType;
|
||||||
|
|
||||||
struct SurfaceParams {
|
struct SurfaceParams {
|
||||||
enum class PixelFormat {
|
|
||||||
ABGR8U = 0,
|
|
||||||
ABGR8S = 1,
|
|
||||||
ABGR8UI = 2,
|
|
||||||
B5G6R5U = 3,
|
|
||||||
A2B10G10R10U = 4,
|
|
||||||
A1B5G5R5U = 5,
|
|
||||||
R8U = 6,
|
|
||||||
R8UI = 7,
|
|
||||||
RGBA16F = 8,
|
|
||||||
RGBA16U = 9,
|
|
||||||
RGBA16UI = 10,
|
|
||||||
R11FG11FB10F = 11,
|
|
||||||
RGBA32UI = 12,
|
|
||||||
DXT1 = 13,
|
|
||||||
DXT23 = 14,
|
|
||||||
DXT45 = 15,
|
|
||||||
DXN1 = 16, // This is also known as BC4
|
|
||||||
DXN2UNORM = 17,
|
|
||||||
DXN2SNORM = 18,
|
|
||||||
BC7U = 19,
|
|
||||||
BC6H_UF16 = 20,
|
|
||||||
BC6H_SF16 = 21,
|
|
||||||
ASTC_2D_4X4 = 22,
|
|
||||||
G8R8U = 23,
|
|
||||||
G8R8S = 24,
|
|
||||||
BGRA8 = 25,
|
|
||||||
RGBA32F = 26,
|
|
||||||
RG32F = 27,
|
|
||||||
R32F = 28,
|
|
||||||
R16F = 29,
|
|
||||||
R16U = 30,
|
|
||||||
R16S = 31,
|
|
||||||
R16UI = 32,
|
|
||||||
R16I = 33,
|
|
||||||
RG16 = 34,
|
|
||||||
RG16F = 35,
|
|
||||||
RG16UI = 36,
|
|
||||||
RG16I = 37,
|
|
||||||
RG16S = 38,
|
|
||||||
RGB32F = 39,
|
|
||||||
RGBA8_SRGB = 40,
|
|
||||||
RG8U = 41,
|
|
||||||
RG8S = 42,
|
|
||||||
RG32UI = 43,
|
|
||||||
R32UI = 44,
|
|
||||||
ASTC_2D_8X8 = 45,
|
|
||||||
ASTC_2D_8X5 = 46,
|
|
||||||
ASTC_2D_5X4 = 47,
|
|
||||||
BGRA8_SRGB = 48,
|
|
||||||
DXT1_SRGB = 49,
|
|
||||||
DXT23_SRGB = 50,
|
|
||||||
DXT45_SRGB = 51,
|
|
||||||
BC7U_SRGB = 52,
|
|
||||||
ASTC_2D_4X4_SRGB = 53,
|
|
||||||
ASTC_2D_8X8_SRGB = 54,
|
|
||||||
ASTC_2D_8X5_SRGB = 55,
|
|
||||||
ASTC_2D_5X4_SRGB = 56,
|
|
||||||
|
|
||||||
MaxColorFormat,
|
|
||||||
|
|
||||||
// Depth formats
|
|
||||||
Z32F = 57,
|
|
||||||
Z16 = 58,
|
|
||||||
|
|
||||||
MaxDepthFormat,
|
|
||||||
|
|
||||||
// DepthStencil formats
|
|
||||||
Z24S8 = 59,
|
|
||||||
S8Z24 = 60,
|
|
||||||
Z32FS8 = 61,
|
|
||||||
|
|
||||||
MaxDepthStencilFormat,
|
|
||||||
|
|
||||||
Max = MaxDepthStencilFormat,
|
|
||||||
Invalid = 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
|
|
||||||
|
|
||||||
enum class ComponentType {
|
|
||||||
Invalid = 0,
|
|
||||||
SNorm = 1,
|
|
||||||
UNorm = 2,
|
|
||||||
SInt = 3,
|
|
||||||
UInt = 4,
|
|
||||||
Float = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SurfaceType {
|
|
||||||
ColorTexture = 0,
|
|
||||||
Depth = 1,
|
|
||||||
DepthStencil = 2,
|
|
||||||
Fill = 3,
|
|
||||||
Invalid = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SurfaceTarget {
|
|
||||||
Texture1D,
|
|
||||||
Texture2D,
|
|
||||||
Texture3D,
|
|
||||||
Texture1DArray,
|
|
||||||
Texture2DArray,
|
|
||||||
TextureCubemap,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
|
|
||||||
switch (texture_type) {
|
|
||||||
case Tegra::Texture::TextureType::Texture1D:
|
|
||||||
return SurfaceTarget::Texture1D;
|
|
||||||
case Tegra::Texture::TextureType::Texture2D:
|
|
||||||
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
|
||||||
return SurfaceTarget::Texture2D;
|
|
||||||
case Tegra::Texture::TextureType::Texture3D:
|
|
||||||
return SurfaceTarget::Texture3D;
|
|
||||||
case Tegra::Texture::TextureType::TextureCubemap:
|
|
||||||
return SurfaceTarget::TextureCubemap;
|
|
||||||
case Tegra::Texture::TextureType::Texture1DArray:
|
|
||||||
return SurfaceTarget::Texture1DArray;
|
|
||||||
case Tegra::Texture::TextureType::Texture2DArray:
|
|
||||||
return SurfaceTarget::Texture2DArray;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
return SurfaceTarget::Texture2D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string SurfaceTargetName(SurfaceTarget target) {
|
static std::string SurfaceTargetName(SurfaceTarget target) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SurfaceTarget::Texture1D:
|
case SurfaceTarget::Texture1D:
|
||||||
|
@ -177,660 +56,8 @@ struct SurfaceParams {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SurfaceTargetIsLayered(SurfaceTarget target) {
|
|
||||||
switch (target) {
|
|
||||||
case SurfaceTarget::Texture1D:
|
|
||||||
case SurfaceTarget::Texture2D:
|
|
||||||
case SurfaceTarget::Texture3D:
|
|
||||||
return false;
|
|
||||||
case SurfaceTarget::Texture1DArray:
|
|
||||||
case SurfaceTarget::Texture2DArray:
|
|
||||||
case SurfaceTarget::TextureCubemap:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
|
||||||
UNREACHABLE();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
|
||||||
* "compressed width" and "compressed height", not the overall compression factor of a
|
|
||||||
* compressed image. This is used for maintaining proper surface sizes for compressed
|
|
||||||
* texture formats.
|
|
||||||
*/
|
|
||||||
static constexpr u32 GetCompressionFactor(PixelFormat format) {
|
|
||||||
if (format == PixelFormat::Invalid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
|
|
||||||
1, // ABGR8U
|
|
||||||
1, // ABGR8S
|
|
||||||
1, // ABGR8UI
|
|
||||||
1, // B5G6R5U
|
|
||||||
1, // A2B10G10R10U
|
|
||||||
1, // A1B5G5R5U
|
|
||||||
1, // R8U
|
|
||||||
1, // R8UI
|
|
||||||
1, // RGBA16F
|
|
||||||
1, // RGBA16U
|
|
||||||
1, // RGBA16UI
|
|
||||||
1, // R11FG11FB10F
|
|
||||||
1, // RGBA32UI
|
|
||||||
4, // DXT1
|
|
||||||
4, // DXT23
|
|
||||||
4, // DXT45
|
|
||||||
4, // DXN1
|
|
||||||
4, // DXN2UNORM
|
|
||||||
4, // DXN2SNORM
|
|
||||||
4, // BC7U
|
|
||||||
4, // BC6H_UF16
|
|
||||||
4, // BC6H_SF16
|
|
||||||
4, // ASTC_2D_4X4
|
|
||||||
1, // G8R8U
|
|
||||||
1, // G8R8S
|
|
||||||
1, // BGRA8
|
|
||||||
1, // RGBA32F
|
|
||||||
1, // RG32F
|
|
||||||
1, // R32F
|
|
||||||
1, // R16F
|
|
||||||
1, // R16U
|
|
||||||
1, // R16S
|
|
||||||
1, // R16UI
|
|
||||||
1, // R16I
|
|
||||||
1, // RG16
|
|
||||||
1, // RG16F
|
|
||||||
1, // RG16UI
|
|
||||||
1, // RG16I
|
|
||||||
1, // RG16S
|
|
||||||
1, // RGB32F
|
|
||||||
1, // RGBA8_SRGB
|
|
||||||
1, // RG8U
|
|
||||||
1, // RG8S
|
|
||||||
1, // RG32UI
|
|
||||||
1, // R32UI
|
|
||||||
4, // ASTC_2D_8X8
|
|
||||||
4, // ASTC_2D_8X5
|
|
||||||
4, // ASTC_2D_5X4
|
|
||||||
1, // BGRA8_SRGB
|
|
||||||
4, // DXT1_SRGB
|
|
||||||
4, // DXT23_SRGB
|
|
||||||
4, // DXT45_SRGB
|
|
||||||
4, // BC7U_SRGB
|
|
||||||
4, // ASTC_2D_4X4_SRGB
|
|
||||||
4, // ASTC_2D_8X8_SRGB
|
|
||||||
4, // ASTC_2D_8X5_SRGB
|
|
||||||
4, // ASTC_2D_5X4_SRGB
|
|
||||||
1, // Z32F
|
|
||||||
1, // Z16
|
|
||||||
1, // Z24S8
|
|
||||||
1, // S8Z24
|
|
||||||
1, // Z32FS8
|
|
||||||
}};
|
|
||||||
|
|
||||||
ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
|
|
||||||
return compression_factor_table[static_cast<std::size_t>(format)];
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
|
|
||||||
if (format == PixelFormat::Invalid)
|
|
||||||
return 0;
|
|
||||||
constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
|
|
||||||
1, // ABGR8U
|
|
||||||
1, // ABGR8S
|
|
||||||
1, // ABGR8UI
|
|
||||||
1, // B5G6R5U
|
|
||||||
1, // A2B10G10R10U
|
|
||||||
1, // A1B5G5R5U
|
|
||||||
1, // R8U
|
|
||||||
1, // R8UI
|
|
||||||
1, // RGBA16F
|
|
||||||
1, // RGBA16U
|
|
||||||
1, // RGBA16UI
|
|
||||||
1, // R11FG11FB10F
|
|
||||||
1, // RGBA32UI
|
|
||||||
4, // DXT1
|
|
||||||
4, // DXT23
|
|
||||||
4, // DXT45
|
|
||||||
4, // DXN1
|
|
||||||
4, // DXN2UNORM
|
|
||||||
4, // DXN2SNORM
|
|
||||||
4, // BC7U
|
|
||||||
4, // BC6H_UF16
|
|
||||||
4, // BC6H_SF16
|
|
||||||
4, // ASTC_2D_4X4
|
|
||||||
1, // G8R8U
|
|
||||||
1, // G8R8S
|
|
||||||
1, // BGRA8
|
|
||||||
1, // RGBA32F
|
|
||||||
1, // RG32F
|
|
||||||
1, // R32F
|
|
||||||
1, // R16F
|
|
||||||
1, // R16U
|
|
||||||
1, // R16S
|
|
||||||
1, // R16UI
|
|
||||||
1, // R16I
|
|
||||||
1, // RG16
|
|
||||||
1, // RG16F
|
|
||||||
1, // RG16UI
|
|
||||||
1, // RG16I
|
|
||||||
1, // RG16S
|
|
||||||
1, // RGB32F
|
|
||||||
1, // RGBA8_SRGB
|
|
||||||
1, // RG8U
|
|
||||||
1, // RG8S
|
|
||||||
1, // RG32UI
|
|
||||||
1, // R32UI
|
|
||||||
8, // ASTC_2D_8X8
|
|
||||||
5, // ASTC_2D_8X5
|
|
||||||
4, // ASTC_2D_5X4
|
|
||||||
1, // BGRA8_SRGB
|
|
||||||
4, // DXT1_SRGB
|
|
||||||
4, // DXT23_SRGB
|
|
||||||
4, // DXT45_SRGB
|
|
||||||
4, // BC7U_SRGB
|
|
||||||
4, // ASTC_2D_4X4_SRGB
|
|
||||||
8, // ASTC_2D_8X8_SRGB
|
|
||||||
5, // ASTC_2D_8X5_SRGB
|
|
||||||
4, // ASTC_2D_5X4_SRGB
|
|
||||||
1, // Z32F
|
|
||||||
1, // Z16
|
|
||||||
1, // Z24S8
|
|
||||||
1, // S8Z24
|
|
||||||
1, // Z32FS8
|
|
||||||
}};
|
|
||||||
ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
|
|
||||||
return block_height_table[static_cast<std::size_t>(format)];
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr u32 GetFormatBpp(PixelFormat format) {
|
|
||||||
if (format == PixelFormat::Invalid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
|
|
||||||
32, // ABGR8U
|
|
||||||
32, // ABGR8S
|
|
||||||
32, // ABGR8UI
|
|
||||||
16, // B5G6R5U
|
|
||||||
32, // A2B10G10R10U
|
|
||||||
16, // A1B5G5R5U
|
|
||||||
8, // R8U
|
|
||||||
8, // R8UI
|
|
||||||
64, // RGBA16F
|
|
||||||
64, // RGBA16U
|
|
||||||
64, // RGBA16UI
|
|
||||||
32, // R11FG11FB10F
|
|
||||||
128, // RGBA32UI
|
|
||||||
64, // DXT1
|
|
||||||
128, // DXT23
|
|
||||||
128, // DXT45
|
|
||||||
64, // DXN1
|
|
||||||
128, // DXN2UNORM
|
|
||||||
128, // DXN2SNORM
|
|
||||||
128, // BC7U
|
|
||||||
128, // BC6H_UF16
|
|
||||||
128, // BC6H_SF16
|
|
||||||
32, // ASTC_2D_4X4
|
|
||||||
16, // G8R8U
|
|
||||||
16, // G8R8S
|
|
||||||
32, // BGRA8
|
|
||||||
128, // RGBA32F
|
|
||||||
64, // RG32F
|
|
||||||
32, // R32F
|
|
||||||
16, // R16F
|
|
||||||
16, // R16U
|
|
||||||
16, // R16S
|
|
||||||
16, // R16UI
|
|
||||||
16, // R16I
|
|
||||||
32, // RG16
|
|
||||||
32, // RG16F
|
|
||||||
32, // RG16UI
|
|
||||||
32, // RG16I
|
|
||||||
32, // RG16S
|
|
||||||
96, // RGB32F
|
|
||||||
32, // RGBA8_SRGB
|
|
||||||
16, // RG8U
|
|
||||||
16, // RG8S
|
|
||||||
64, // RG32UI
|
|
||||||
32, // R32UI
|
|
||||||
16, // ASTC_2D_8X8
|
|
||||||
16, // ASTC_2D_8X5
|
|
||||||
32, // ASTC_2D_5X4
|
|
||||||
32, // BGRA8_SRGB
|
|
||||||
64, // DXT1_SRGB
|
|
||||||
128, // DXT23_SRGB
|
|
||||||
128, // DXT45_SRGB
|
|
||||||
128, // BC7U
|
|
||||||
32, // ASTC_2D_4X4_SRGB
|
|
||||||
16, // ASTC_2D_8X8_SRGB
|
|
||||||
16, // ASTC_2D_8X5_SRGB
|
|
||||||
32, // ASTC_2D_5X4_SRGB
|
|
||||||
32, // Z32F
|
|
||||||
16, // Z16
|
|
||||||
32, // Z24S8
|
|
||||||
32, // S8Z24
|
|
||||||
64, // Z32FS8
|
|
||||||
}};
|
|
||||||
|
|
||||||
ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
|
|
||||||
return bpp_table[static_cast<std::size_t>(format)];
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFormatBpp() const {
|
u32 GetFormatBpp() const {
|
||||||
return GetFormatBpp(pixel_format);
|
return VideoCore::Surface::GetFormatBpp(pixel_format);
|
||||||
}
|
|
||||||
|
|
||||||
static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
|
||||||
return PixelFormat::S8Z24;
|
|
||||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
|
||||||
return PixelFormat::Z24S8;
|
|
||||||
case Tegra::DepthFormat::Z32_FLOAT:
|
|
||||||
return PixelFormat::Z32F;
|
|
||||||
case Tegra::DepthFormat::Z16_UNORM:
|
|
||||||
return PixelFormat::Z16;
|
|
||||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
|
||||||
return PixelFormat::Z32FS8;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
// TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
|
|
||||||
// gamma.
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
|
||||||
return PixelFormat::RGBA8_SRGB;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
|
||||||
return PixelFormat::ABGR8U;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
|
||||||
return PixelFormat::ABGR8S;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
|
||||||
return PixelFormat::ABGR8UI;
|
|
||||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
|
||||||
return PixelFormat::BGRA8_SRGB;
|
|
||||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
|
||||||
return PixelFormat::BGRA8;
|
|
||||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
|
||||||
return PixelFormat::A2B10G10R10U;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
|
||||||
return PixelFormat::RGBA16F;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
|
||||||
return PixelFormat::RGBA16U;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
|
||||||
return PixelFormat::RGBA16UI;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
|
||||||
return PixelFormat::RGBA32F;
|
|
||||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
|
||||||
return PixelFormat::RG32F;
|
|
||||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
|
||||||
return PixelFormat::R11FG11FB10F;
|
|
||||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
|
||||||
return PixelFormat::B5G6R5U;
|
|
||||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
|
||||||
return PixelFormat::A1B5G5R5U;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
|
||||||
return PixelFormat::RGBA32UI;
|
|
||||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
|
||||||
return PixelFormat::R8U;
|
|
||||||
case Tegra::RenderTargetFormat::R8_UINT:
|
|
||||||
return PixelFormat::R8UI;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
|
||||||
return PixelFormat::RG16F;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
|
||||||
return PixelFormat::RG16UI;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
|
||||||
return PixelFormat::RG16I;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
|
||||||
return PixelFormat::RG16;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
|
||||||
return PixelFormat::RG16S;
|
|
||||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
|
||||||
return PixelFormat::RG8U;
|
|
||||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
|
||||||
return PixelFormat::RG8S;
|
|
||||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
|
||||||
return PixelFormat::R16F;
|
|
||||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
|
||||||
return PixelFormat::R16U;
|
|
||||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
|
||||||
return PixelFormat::R16S;
|
|
||||||
case Tegra::RenderTargetFormat::R16_UINT:
|
|
||||||
return PixelFormat::R16UI;
|
|
||||||
case Tegra::RenderTargetFormat::R16_SINT:
|
|
||||||
return PixelFormat::R16I;
|
|
||||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
|
||||||
return PixelFormat::R32F;
|
|
||||||
case Tegra::RenderTargetFormat::R32_UINT:
|
|
||||||
return PixelFormat::R32UI;
|
|
||||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
|
||||||
return PixelFormat::RG32UI;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
|
||||||
Tegra::Texture::ComponentType component_type,
|
|
||||||
bool is_srgb) {
|
|
||||||
// TODO(Subv): Properly implement this
|
|
||||||
switch (format) {
|
|
||||||
case Tegra::Texture::TextureFormat::A8R8G8B8:
|
|
||||||
if (is_srgb) {
|
|
||||||
return PixelFormat::RGBA8_SRGB;
|
|
||||||
}
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::ABGR8U;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return PixelFormat::ABGR8S;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::ABGR8UI;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::B5G6R5:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::B5G6R5U;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::A2B10G10R10:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::A2B10G10R10U;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::A1B5G5R5U;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R8:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::R8U;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::R8UI;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::G8R8:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::G8R8U;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return PixelFormat::G8R8S;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::RGBA16U;
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::RGBA16F;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::BF10GF11RF11:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::R11FG11FB10F;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::RGBA32F;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::RGBA32UI;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R32_G32:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::RG32F;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::RG32UI;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R32_G32_B32:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::RGB32F;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R16:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::R16F;
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::R16U;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return PixelFormat::R16S;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::R16UI;
|
|
||||||
case Tegra::Texture::ComponentType::SINT:
|
|
||||||
return PixelFormat::R16I;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::R32:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::R32F;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::R32UI;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::ZF32:
|
|
||||||
return PixelFormat::Z32F;
|
|
||||||
case Tegra::Texture::TextureFormat::Z16:
|
|
||||||
return PixelFormat::Z16;
|
|
||||||
case Tegra::Texture::TextureFormat::Z24S8:
|
|
||||||
return PixelFormat::Z24S8;
|
|
||||||
case Tegra::Texture::TextureFormat::DXT1:
|
|
||||||
return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
|
|
||||||
case Tegra::Texture::TextureFormat::DXT23:
|
|
||||||
return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
|
|
||||||
case Tegra::Texture::TextureFormat::DXT45:
|
|
||||||
return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
|
|
||||||
case Tegra::Texture::TextureFormat::DXN1:
|
|
||||||
return PixelFormat::DXN1;
|
|
||||||
case Tegra::Texture::TextureFormat::DXN2:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::DXN2UNORM;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return PixelFormat::DXN2SNORM;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
case Tegra::Texture::TextureFormat::BC7U:
|
|
||||||
return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
|
|
||||||
case Tegra::Texture::TextureFormat::BC6H_UF16:
|
|
||||||
return PixelFormat::BC6H_UF16;
|
|
||||||
case Tegra::Texture::TextureFormat::BC6H_SF16:
|
|
||||||
return PixelFormat::BC6H_SF16;
|
|
||||||
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
|
|
||||||
return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
|
|
||||||
case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
|
|
||||||
return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
|
|
||||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
|
|
||||||
return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
|
|
||||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
|
|
||||||
return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
|
|
||||||
case Tegra::Texture::TextureFormat::R16_G16:
|
|
||||||
switch (component_type) {
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return PixelFormat::RG16F;
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return PixelFormat::RG16;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return PixelFormat::RG16S;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return PixelFormat::RG16UI;
|
|
||||||
case Tegra::Texture::ComponentType::SINT:
|
|
||||||
return PixelFormat::RG16I;
|
|
||||||
}
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
|
||||||
static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}",
|
|
||||||
static_cast<u32>(format), static_cast<u32>(component_type));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
|
|
||||||
// TODO(Subv): Implement more component types
|
|
||||||
switch (type) {
|
|
||||||
case Tegra::Texture::ComponentType::UNORM:
|
|
||||||
return ComponentType::UNorm;
|
|
||||||
case Tegra::Texture::ComponentType::FLOAT:
|
|
||||||
return ComponentType::Float;
|
|
||||||
case Tegra::Texture::ComponentType::SNORM:
|
|
||||||
return ComponentType::SNorm;
|
|
||||||
case Tegra::Texture::ComponentType::UINT:
|
|
||||||
return ComponentType::UInt;
|
|
||||||
case Tegra::Texture::ComponentType::SINT:
|
|
||||||
return ComponentType::SInt;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
|
|
||||||
// TODO(Subv): Implement more render targets
|
|
||||||
switch (format) {
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
|
||||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
|
||||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
|
||||||
return ComponentType::UNorm;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
|
||||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
|
||||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
|
||||||
return ComponentType::SNorm;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
|
||||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
|
||||||
return ComponentType::Float;
|
|
||||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::R8_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::R16_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::R32_UINT:
|
|
||||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
|
||||||
return ComponentType::UInt;
|
|
||||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
|
||||||
case Tegra::RenderTargetFormat::R16_SINT:
|
|
||||||
return ComponentType::SInt;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
|
||||||
return PixelFormat::ABGR8U;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case Tegra::DepthFormat::Z16_UNORM:
|
|
||||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
|
||||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
|
||||||
return ComponentType::UNorm;
|
|
||||||
case Tegra::DepthFormat::Z32_FLOAT:
|
|
||||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
|
||||||
return ComponentType::Float;
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static SurfaceType GetFormatType(PixelFormat pixel_format) {
|
|
||||||
if (static_cast<std::size_t>(pixel_format) <
|
|
||||||
static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
|
|
||||||
return SurfaceType::ColorTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<std::size_t>(pixel_format) <
|
|
||||||
static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
|
|
||||||
return SurfaceType::Depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<std::size_t>(pixel_format) <
|
|
||||||
static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
|
|
||||||
return SurfaceType::DepthStencil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(Subv): Implement the other formats
|
|
||||||
ASSERT(false);
|
|
||||||
|
|
||||||
return SurfaceType::Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the sizer in bytes of the specified pixel format
|
|
||||||
static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
|
|
||||||
if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return GetFormatBpp(pixel_format) / CHAR_BIT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the rectangle corresponding to this surface
|
/// Returns the rectangle corresponding to this surface
|
||||||
|
|
|
@ -373,6 +373,7 @@ public:
|
||||||
if (sets_cc) {
|
if (sets_cc) {
|
||||||
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
||||||
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
||||||
|
LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1525,6 +1526,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
|
||||||
instr.alu.saturate_d, 0, true);
|
instr.alu.saturate_d, 0, true);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::FADD_C:
|
case OpCode::Id::FADD_C:
|
||||||
|
@ -1535,6 +1540,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
|
||||||
instr.alu.saturate_d, 0, true);
|
instr.alu.saturate_d, 0, true);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::MUFU: {
|
case OpCode::Id::MUFU: {
|
||||||
|
@ -1588,6 +1597,10 @@ private:
|
||||||
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
||||||
parameters + ')',
|
parameters + ')',
|
||||||
1, 1, false, 0, true);
|
1, 1, false, 0, true);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::RRO_C:
|
case OpCode::Id::RRO_C:
|
||||||
|
@ -1618,6 +1631,10 @@ private:
|
||||||
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
|
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
|
||||||
GetImmediate32(instr),
|
GetImmediate32(instr),
|
||||||
1, 1, instr.fmul32.saturate, 0, true);
|
1, 1, instr.fmul32.saturate, 0, true);
|
||||||
|
if (instr.op_32.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::FADD32I: {
|
case OpCode::Id::FADD32I: {
|
||||||
|
@ -1641,6 +1658,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
|
||||||
|
if (instr.op_32.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1661,6 +1682,10 @@ private:
|
||||||
std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
|
std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -1698,12 +1723,20 @@ private:
|
||||||
// Cast to int is superfluous for arithmetic shift, it's only for a logical shift
|
// Cast to int is superfluous for arithmetic shift, it's only for a logical shift
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
|
||||||
1, 1);
|
1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::SHL_C:
|
case OpCode::Id::SHL_C:
|
||||||
case OpCode::Id::SHL_R:
|
case OpCode::Id::SHL_R:
|
||||||
case OpCode::Id::SHL_IMM:
|
case OpCode::Id::SHL_IMM:
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
|
LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
|
||||||
|
@ -1723,6 +1756,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
||||||
instr.iadd32i.saturate != 0);
|
instr.iadd32i.saturate != 0);
|
||||||
|
if (instr.op_32.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OpCode::Id::LOP32I: {
|
case OpCode::Id::LOP32I: {
|
||||||
if (instr.alu.lop32i.invert_a)
|
if (instr.alu.lop32i.invert_a)
|
||||||
|
@ -1734,6 +1771,10 @@ private:
|
||||||
WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
|
WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
|
||||||
Tegra::Shader::PredicateResultMode::None,
|
Tegra::Shader::PredicateResultMode::None,
|
||||||
Tegra::Shader::Pred::UnusedIndex);
|
Tegra::Shader::Pred::UnusedIndex);
|
||||||
|
if (instr.op_32.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -1770,6 +1811,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
||||||
instr.alu.saturate_d);
|
instr.alu.saturate_d);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::IADD3_C:
|
case OpCode::Id::IADD3_C:
|
||||||
|
@ -1831,6 +1876,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
|
regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
|
||||||
|
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::ISCADD_C:
|
case OpCode::Id::ISCADD_C:
|
||||||
|
@ -1846,6 +1896,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, true, 0,
|
regs.SetRegisterToInteger(instr.gpr0, true, 0,
|
||||||
"((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
|
"((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::POPC_C:
|
case OpCode::Id::POPC_C:
|
||||||
|
@ -1877,6 +1931,10 @@ private:
|
||||||
|
|
||||||
WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
|
WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
|
||||||
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
|
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::LOP3_C:
|
case OpCode::Id::LOP3_C:
|
||||||
|
@ -1892,6 +1950,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
|
WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::IMNMX_C:
|
case OpCode::Id::IMNMX_C:
|
||||||
|
@ -1906,6 +1968,10 @@ private:
|
||||||
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
||||||
parameters + ')',
|
parameters + ')',
|
||||||
1, 1);
|
1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::LEA_R2:
|
case OpCode::Id::LEA_R2:
|
||||||
|
@ -2107,6 +2173,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
|
regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
|
||||||
1, 1, instr.alu.saturate_d, 0, true);
|
1, 1, instr.alu.saturate_d, 0, true);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2212,6 +2282,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
|
||||||
|
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::F2F_R: {
|
case OpCode::Id::F2F_R: {
|
||||||
|
@ -2250,6 +2325,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
|
||||||
|
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::F2I_R:
|
case OpCode::Id::F2I_R:
|
||||||
|
@ -2299,6 +2379,10 @@ private:
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
|
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
|
||||||
1, false, 0, instr.conversion.dest_size);
|
1, false, 0, instr.conversion.dest_size);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -3107,6 +3191,11 @@ private:
|
||||||
regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
|
regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Type::PredicateSetPredicate: {
|
case OpCode::Type::PredicateSetPredicate: {
|
||||||
|
@ -3372,6 +3461,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
|
regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -3381,6 +3474,12 @@ private:
|
||||||
EmitFragmentOutputsWrite();
|
EmitFragmentOutputsWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||||
|
if (cc != Tegra::Shader::ControlCode::T) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
switch (instr.flow.cond) {
|
switch (instr.flow.cond) {
|
||||||
case Tegra::Shader::FlowCondition::Always:
|
case Tegra::Shader::FlowCondition::Always:
|
||||||
shader.AddLine("return true;");
|
shader.AddLine("return true;");
|
||||||
|
@ -3410,6 +3509,11 @@ private:
|
||||||
|
|
||||||
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
|
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
|
||||||
// about unexecuted instructions that may follow this.
|
// about unexecuted instructions that may follow this.
|
||||||
|
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||||
|
if (cc != Tegra::Shader::ControlCode::T) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
shader.AddLine("if (true) {");
|
shader.AddLine("if (true) {");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
shader.AddLine("discard;");
|
shader.AddLine("discard;");
|
||||||
|
@ -3467,6 +3571,11 @@ private:
|
||||||
case OpCode::Id::BRA: {
|
case OpCode::Id::BRA: {
|
||||||
ASSERT_MSG(instr.bra.constant_buffer == 0,
|
ASSERT_MSG(instr.bra.constant_buffer == 0,
|
||||||
"BRA with constant buffers are not implemented");
|
"BRA with constant buffers are not implemented");
|
||||||
|
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||||
|
if (cc != Tegra::Shader::ControlCode::T) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
const u32 target = offset + instr.bra.GetBranchTarget();
|
const u32 target = offset + instr.bra.GetBranchTarget();
|
||||||
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
|
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
|
||||||
break;
|
break;
|
||||||
|
@ -3507,13 +3616,21 @@ private:
|
||||||
}
|
}
|
||||||
case OpCode::Id::SYNC: {
|
case OpCode::Id::SYNC: {
|
||||||
// The SYNC opcode jumps to the address previously set by the SSY opcode
|
// The SYNC opcode jumps to the address previously set by the SSY opcode
|
||||||
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||||
|
if (cc != Tegra::Shader::ControlCode::T) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
EmitPopFromFlowStack();
|
EmitPopFromFlowStack();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::BRK: {
|
case OpCode::Id::BRK: {
|
||||||
// The BRK opcode jumps to the address previously set by the PBK opcode
|
// The BRK opcode jumps to the address previously set by the PBK opcode
|
||||||
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||||
|
if (cc != Tegra::Shader::ControlCode::T) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
EmitPopFromFlowStack();
|
EmitPopFromFlowStack();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3543,6 +3660,11 @@ private:
|
||||||
regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
|
regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
|
||||||
instr.vmad.saturate == 1, 0, Register::Size::Word,
|
instr.vmad.saturate == 1, 0, Register::Size::Word,
|
||||||
instr.vmad.cc);
|
instr.vmad.cc);
|
||||||
|
if (instr.generates_cc) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::VSETP: {
|
case OpCode::Id::VSETP: {
|
||||||
|
|
|
@ -89,7 +89,18 @@ OpenGLState::OpenGLState() {
|
||||||
point.size = 1;
|
point.size = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::Apply() const {
|
void OpenGLState::ApplyDefaultState() {
|
||||||
|
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_PRIMITIVE_RESTART);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplySRgb() const {
|
||||||
// sRGB
|
// sRGB
|
||||||
if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
|
if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
|
||||||
if (framebuffer_srgb.enabled) {
|
if (framebuffer_srgb.enabled) {
|
||||||
|
@ -100,96 +111,122 @@ void OpenGLState::Apply() const {
|
||||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplyCulling() const {
|
||||||
// Culling
|
// Culling
|
||||||
if (cull.enabled != cur_state.cull.enabled) {
|
const bool cull_changed = cull.enabled != cur_state.cull.enabled;
|
||||||
|
if (cull_changed) {
|
||||||
if (cull.enabled) {
|
if (cull.enabled) {
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cull.enabled) {
|
||||||
|
if (cull_changed || cull.mode != cur_state.cull.mode) {
|
||||||
|
glCullFace(cull.mode);
|
||||||
|
}
|
||||||
|
|
||||||
if (cull.mode != cur_state.cull.mode) {
|
if (cull_changed || cull.front_face != cur_state.cull.front_face) {
|
||||||
glCullFace(cull.mode);
|
glFrontFace(cull.front_face);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cull.front_face != cur_state.cull.front_face) {
|
|
||||||
glFrontFace(cull.front_face);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplyDepth() const {
|
||||||
// Depth test
|
// Depth test
|
||||||
if (depth.test_enabled != cur_state.depth.test_enabled) {
|
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
|
||||||
|
if (depth_test_changed) {
|
||||||
if (depth.test_enabled) {
|
if (depth.test_enabled) {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (depth.test_enabled &&
|
||||||
if (depth.test_func != cur_state.depth.test_func) {
|
(depth_test_changed || depth.test_func != cur_state.depth.test_func)) {
|
||||||
glDepthFunc(depth.test_func);
|
glDepthFunc(depth.test_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth mask
|
// Depth mask
|
||||||
if (depth.write_mask != cur_state.depth.write_mask) {
|
if (depth.write_mask != cur_state.depth.write_mask) {
|
||||||
glDepthMask(depth.write_mask);
|
glDepthMask(depth.write_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth range
|
// Depth range
|
||||||
if (depth.depth_range_near != cur_state.depth.depth_range_near ||
|
if (depth.depth_range_near != cur_state.depth.depth_range_near ||
|
||||||
depth.depth_range_far != cur_state.depth.depth_range_far) {
|
depth.depth_range_far != cur_state.depth.depth_range_far) {
|
||||||
glDepthRange(depth.depth_range_near, depth.depth_range_far);
|
glDepthRange(depth.depth_range_near, depth.depth_range_far);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Primitive restart
|
void OpenGLState::ApplyPrimitiveRestart() const {
|
||||||
if (primitive_restart.enabled != cur_state.primitive_restart.enabled) {
|
const bool primitive_restart_changed =
|
||||||
|
primitive_restart.enabled != cur_state.primitive_restart.enabled;
|
||||||
|
if (primitive_restart_changed) {
|
||||||
if (primitive_restart.enabled) {
|
if (primitive_restart.enabled) {
|
||||||
glEnable(GL_PRIMITIVE_RESTART);
|
glEnable(GL_PRIMITIVE_RESTART);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_PRIMITIVE_RESTART);
|
glDisable(GL_PRIMITIVE_RESTART);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (primitive_restart.index != cur_state.primitive_restart.index) {
|
if (primitive_restart_changed ||
|
||||||
|
(primitive_restart.enabled &&
|
||||||
|
primitive_restart.index != cur_state.primitive_restart.index)) {
|
||||||
glPrimitiveRestartIndex(primitive_restart.index);
|
glPrimitiveRestartIndex(primitive_restart.index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Color mask
|
void OpenGLState::ApplyStencilTest() const {
|
||||||
if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
|
const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled;
|
||||||
color_mask.green_enabled != cur_state.color_mask.green_enabled ||
|
if (stencil_test_changed) {
|
||||||
color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
|
|
||||||
color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
|
|
||||||
glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
|
|
||||||
color_mask.alpha_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stencil test
|
|
||||||
if (stencil.test_enabled != cur_state.stencil.test_enabled) {
|
|
||||||
if (stencil.test_enabled) {
|
if (stencil.test_enabled) {
|
||||||
glEnable(GL_STENCIL_TEST);
|
glEnable(GL_STENCIL_TEST);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) {
|
if (stencil.test_enabled) {
|
||||||
if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
|
auto config_stencil = [stencil_test_changed](GLenum face, const auto& config,
|
||||||
config.test_mask != prev_config.test_mask) {
|
const auto& prev_config) {
|
||||||
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
|
if (stencil_test_changed || config.test_func != prev_config.test_func ||
|
||||||
}
|
config.test_ref != prev_config.test_ref ||
|
||||||
if (config.action_depth_fail != prev_config.action_depth_fail ||
|
config.test_mask != prev_config.test_mask) {
|
||||||
config.action_depth_pass != prev_config.action_depth_pass ||
|
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
|
||||||
config.action_stencil_fail != prev_config.action_stencil_fail) {
|
}
|
||||||
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
|
if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail ||
|
||||||
config.action_depth_pass);
|
config.action_depth_pass != prev_config.action_depth_pass ||
|
||||||
}
|
config.action_stencil_fail != prev_config.action_stencil_fail) {
|
||||||
if (config.write_mask != prev_config.write_mask) {
|
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
|
||||||
glStencilMaskSeparate(face, config.write_mask);
|
config.action_depth_pass);
|
||||||
}
|
}
|
||||||
};
|
if (config.write_mask != prev_config.write_mask) {
|
||||||
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
|
glStencilMaskSeparate(face, config.write_mask);
|
||||||
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
}
|
||||||
|
};
|
||||||
|
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
|
||||||
|
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Blending
|
void OpenGLState::ApplyScissorTest() const {
|
||||||
if (blend.enabled != cur_state.blend.enabled) {
|
const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
|
||||||
|
if (scissor_changed) {
|
||||||
|
if (scissor.enabled) {
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
} else {
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x ||
|
||||||
|
scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width ||
|
||||||
|
scissor.height != cur_state.scissor.height) {
|
||||||
|
glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplyBlending() const {
|
||||||
|
const bool blend_changed = blend.enabled != cur_state.blend.enabled;
|
||||||
|
if (blend_changed) {
|
||||||
if (blend.enabled) {
|
if (blend.enabled) {
|
||||||
ASSERT(!logic_op.enabled);
|
ASSERT(!logic_op.enabled);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
@ -197,29 +234,32 @@ void OpenGLState::Apply() const {
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (blend.enabled) {
|
||||||
|
if (blend_changed || blend.color.red != cur_state.blend.color.red ||
|
||||||
|
blend.color.green != cur_state.blend.color.green ||
|
||||||
|
blend.color.blue != cur_state.blend.color.blue ||
|
||||||
|
blend.color.alpha != cur_state.blend.color.alpha) {
|
||||||
|
glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
|
||||||
|
}
|
||||||
|
|
||||||
if (blend.color.red != cur_state.blend.color.red ||
|
if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func ||
|
||||||
blend.color.green != cur_state.blend.color.green ||
|
blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
|
||||||
blend.color.blue != cur_state.blend.color.blue ||
|
blend.src_a_func != cur_state.blend.src_a_func ||
|
||||||
blend.color.alpha != cur_state.blend.color.alpha) {
|
blend.dst_a_func != cur_state.blend.dst_a_func) {
|
||||||
glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
|
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
|
||||||
|
blend.dst_a_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation ||
|
||||||
|
blend.a_equation != cur_state.blend.a_equation) {
|
||||||
|
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
|
void OpenGLState::ApplyLogicOp() const {
|
||||||
blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
|
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
|
||||||
blend.src_a_func != cur_state.blend.src_a_func ||
|
if (logic_op_changed) {
|
||||||
blend.dst_a_func != cur_state.blend.dst_a_func) {
|
|
||||||
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
|
|
||||||
blend.dst_a_func);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blend.rgb_equation != cur_state.blend.rgb_equation ||
|
|
||||||
blend.a_equation != cur_state.blend.a_equation) {
|
|
||||||
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logic Operation
|
|
||||||
if (logic_op.enabled != cur_state.logic_op.enabled) {
|
|
||||||
if (logic_op.enabled) {
|
if (logic_op.enabled) {
|
||||||
ASSERT(!blend.enabled);
|
ASSERT(!blend.enabled);
|
||||||
glEnable(GL_COLOR_LOGIC_OP);
|
glEnable(GL_COLOR_LOGIC_OP);
|
||||||
|
@ -228,11 +268,13 @@ void OpenGLState::Apply() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logic_op.operation != cur_state.logic_op.operation) {
|
if (logic_op.enabled &&
|
||||||
|
(logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
|
||||||
glLogicOp(logic_op.operation);
|
glLogicOp(logic_op.operation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Textures
|
void OpenGLState::ApplyTextures() const {
|
||||||
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
||||||
const auto& texture_unit = texture_units[i];
|
const auto& texture_unit = texture_units[i];
|
||||||
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
||||||
|
@ -251,28 +293,29 @@ void OpenGLState::Apply() const {
|
||||||
glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Samplers
|
void OpenGLState::ApplySamplers() const {
|
||||||
{
|
bool has_delta{};
|
||||||
bool has_delta{};
|
std::size_t first{}, last{};
|
||||||
std::size_t first{}, last{};
|
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
||||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
||||||
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
samplers[i] = texture_units[i].sampler;
|
||||||
samplers[i] = texture_units[i].sampler;
|
if (samplers[i] != cur_state.texture_units[i].sampler) {
|
||||||
if (samplers[i] != cur_state.texture_units[i].sampler) {
|
if (!has_delta) {
|
||||||
if (!has_delta) {
|
first = i;
|
||||||
first = i;
|
has_delta = true;
|
||||||
has_delta = true;
|
|
||||||
}
|
|
||||||
last = i;
|
|
||||||
}
|
}
|
||||||
}
|
last = i;
|
||||||
if (has_delta) {
|
|
||||||
glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
|
|
||||||
samplers.data());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (has_delta) {
|
||||||
|
glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
|
||||||
|
samplers.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLState::Apply() const {
|
||||||
// Framebuffer
|
// Framebuffer
|
||||||
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
|
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
|
||||||
|
@ -305,27 +348,12 @@ void OpenGLState::Apply() const {
|
||||||
if (draw.program_pipeline != cur_state.draw.program_pipeline) {
|
if (draw.program_pipeline != cur_state.draw.program_pipeline) {
|
||||||
glBindProgramPipeline(draw.program_pipeline);
|
glBindProgramPipeline(draw.program_pipeline);
|
||||||
}
|
}
|
||||||
|
// Viewport
|
||||||
// Scissor test
|
|
||||||
if (scissor.enabled != cur_state.scissor.enabled) {
|
|
||||||
if (scissor.enabled) {
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
} else {
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
|
|
||||||
scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) {
|
|
||||||
glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
|
if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
|
||||||
viewport.width != cur_state.viewport.width ||
|
viewport.width != cur_state.viewport.width ||
|
||||||
viewport.height != cur_state.viewport.height) {
|
viewport.height != cur_state.viewport.height) {
|
||||||
glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clip distance
|
// Clip distance
|
||||||
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
|
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
|
||||||
if (clip_distance[i] != cur_state.clip_distance[i]) {
|
if (clip_distance[i] != cur_state.clip_distance[i]) {
|
||||||
|
@ -336,12 +364,28 @@ void OpenGLState::Apply() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Color mask
|
||||||
|
if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
|
||||||
|
color_mask.green_enabled != cur_state.color_mask.green_enabled ||
|
||||||
|
color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
|
||||||
|
color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
|
||||||
|
glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
|
||||||
|
color_mask.alpha_enabled);
|
||||||
|
}
|
||||||
// Point
|
// Point
|
||||||
if (point.size != cur_state.point.size) {
|
if (point.size != cur_state.point.size) {
|
||||||
glPointSize(point.size);
|
glPointSize(point.size);
|
||||||
}
|
}
|
||||||
|
ApplyScissorTest();
|
||||||
|
ApplyStencilTest();
|
||||||
|
ApplySRgb();
|
||||||
|
ApplyCulling();
|
||||||
|
ApplyDepth();
|
||||||
|
ApplyPrimitiveRestart();
|
||||||
|
ApplyBlending();
|
||||||
|
ApplyLogicOp();
|
||||||
|
ApplyTextures();
|
||||||
|
ApplySamplers();
|
||||||
cur_state = *this;
|
cur_state = *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,8 @@ public:
|
||||||
}
|
}
|
||||||
/// Apply this state as the current OpenGL state
|
/// Apply this state as the current OpenGL state
|
||||||
void Apply() const;
|
void Apply() const;
|
||||||
|
/// Set the initial OpenGL state
|
||||||
|
static void ApplyDefaultState();
|
||||||
/// Resets any references to the given resource
|
/// Resets any references to the given resource
|
||||||
OpenGLState& UnbindTexture(GLuint handle);
|
OpenGLState& UnbindTexture(GLuint handle);
|
||||||
OpenGLState& ResetSampler(GLuint handle);
|
OpenGLState& ResetSampler(GLuint handle);
|
||||||
|
@ -188,6 +189,16 @@ private:
|
||||||
// Workaround for sRGB problems caused by
|
// Workaround for sRGB problems caused by
|
||||||
// QT not supporting srgb output
|
// QT not supporting srgb output
|
||||||
static bool s_rgb_used;
|
static bool s_rgb_used;
|
||||||
|
void ApplySRgb() const;
|
||||||
|
void ApplyCulling() const;
|
||||||
|
void ApplyDepth() const;
|
||||||
|
void ApplyPrimitiveRestart() const;
|
||||||
|
void ApplyStencilTest() const;
|
||||||
|
void ApplyScissorTest() const;
|
||||||
|
void ApplyBlending() const;
|
||||||
|
void ApplyLogicOp() const;
|
||||||
|
void ApplyTextures() const;
|
||||||
|
void ApplySamplers() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
499
src/video_core/surface.cpp
Normal file
499
src/video_core/surface.cpp
Normal file
|
@ -0,0 +1,499 @@
|
||||||
|
// Copyright 2014 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/math_util.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
|
|
||||||
|
namespace VideoCore::Surface {
|
||||||
|
|
||||||
|
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
|
||||||
|
switch (texture_type) {
|
||||||
|
case Tegra::Texture::TextureType::Texture1D:
|
||||||
|
return SurfaceTarget::Texture1D;
|
||||||
|
case Tegra::Texture::TextureType::Texture2D:
|
||||||
|
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
||||||
|
return SurfaceTarget::Texture2D;
|
||||||
|
case Tegra::Texture::TextureType::Texture3D:
|
||||||
|
return SurfaceTarget::Texture3D;
|
||||||
|
case Tegra::Texture::TextureType::TextureCubemap:
|
||||||
|
return SurfaceTarget::TextureCubemap;
|
||||||
|
case Tegra::Texture::TextureType::Texture1DArray:
|
||||||
|
return SurfaceTarget::Texture1DArray;
|
||||||
|
case Tegra::Texture::TextureType::Texture2DArray:
|
||||||
|
return SurfaceTarget::Texture2DArray;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
return SurfaceTarget::Texture2D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceTargetIsLayered(SurfaceTarget target) {
|
||||||
|
switch (target) {
|
||||||
|
case SurfaceTarget::Texture1D:
|
||||||
|
case SurfaceTarget::Texture2D:
|
||||||
|
case SurfaceTarget::Texture3D:
|
||||||
|
return false;
|
||||||
|
case SurfaceTarget::Texture1DArray:
|
||||||
|
case SurfaceTarget::Texture2DArray:
|
||||||
|
case SurfaceTarget::TextureCubemap:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
||||||
|
UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||||
|
return PixelFormat::S8Z24;
|
||||||
|
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||||
|
return PixelFormat::Z24S8;
|
||||||
|
case Tegra::DepthFormat::Z32_FLOAT:
|
||||||
|
return PixelFormat::Z32F;
|
||||||
|
case Tegra::DepthFormat::Z16_UNORM:
|
||||||
|
return PixelFormat::Z16;
|
||||||
|
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||||
|
return PixelFormat::Z32FS8;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
// TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
|
||||||
|
// gamma.
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||||
|
return PixelFormat::RGBA8_SRGB;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||||
|
return PixelFormat::ABGR8U;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||||
|
return PixelFormat::ABGR8S;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||||
|
return PixelFormat::ABGR8UI;
|
||||||
|
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||||
|
return PixelFormat::BGRA8_SRGB;
|
||||||
|
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||||
|
return PixelFormat::BGRA8;
|
||||||
|
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||||
|
return PixelFormat::A2B10G10R10U;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||||
|
return PixelFormat::RGBA16F;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||||
|
return PixelFormat::RGBA16U;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||||
|
return PixelFormat::RGBA16UI;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||||
|
return PixelFormat::RGBA32F;
|
||||||
|
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||||
|
return PixelFormat::RG32F;
|
||||||
|
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||||
|
return PixelFormat::R11FG11FB10F;
|
||||||
|
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||||
|
return PixelFormat::B5G6R5U;
|
||||||
|
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||||
|
return PixelFormat::A1B5G5R5U;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||||
|
return PixelFormat::RGBA32UI;
|
||||||
|
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||||
|
return PixelFormat::R8U;
|
||||||
|
case Tegra::RenderTargetFormat::R8_UINT:
|
||||||
|
return PixelFormat::R8UI;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||||
|
return PixelFormat::RG16F;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||||
|
return PixelFormat::RG16UI;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||||
|
return PixelFormat::RG16I;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||||
|
return PixelFormat::RG16;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||||
|
return PixelFormat::RG16S;
|
||||||
|
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||||
|
return PixelFormat::RG8U;
|
||||||
|
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||||
|
return PixelFormat::RG8S;
|
||||||
|
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||||
|
return PixelFormat::R16F;
|
||||||
|
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||||
|
return PixelFormat::R16U;
|
||||||
|
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||||
|
return PixelFormat::R16S;
|
||||||
|
case Tegra::RenderTargetFormat::R16_UINT:
|
||||||
|
return PixelFormat::R16UI;
|
||||||
|
case Tegra::RenderTargetFormat::R16_SINT:
|
||||||
|
return PixelFormat::R16I;
|
||||||
|
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||||
|
return PixelFormat::R32F;
|
||||||
|
case Tegra::RenderTargetFormat::R32_UINT:
|
||||||
|
return PixelFormat::R32UI;
|
||||||
|
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||||
|
return PixelFormat::RG32UI;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||||
|
Tegra::Texture::ComponentType component_type,
|
||||||
|
bool is_srgb) {
|
||||||
|
// TODO(Subv): Properly implement this
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::Texture::TextureFormat::A8R8G8B8:
|
||||||
|
if (is_srgb) {
|
||||||
|
return PixelFormat::RGBA8_SRGB;
|
||||||
|
}
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::ABGR8U;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return PixelFormat::ABGR8S;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::ABGR8UI;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::B5G6R5:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::B5G6R5U;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::A2B10G10R10:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::A2B10G10R10U;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::A1B5G5R5U;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R8:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::R8U;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::R8UI;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::G8R8:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::G8R8U;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return PixelFormat::G8R8S;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::RGBA16U;
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::RGBA16F;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::BF10GF11RF11:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::R11FG11FB10F;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::RGBA32F;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::RGBA32UI;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R32_G32:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::RG32F;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::RG32UI;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R32_G32_B32:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::RGB32F;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R16:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::R16F;
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::R16U;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return PixelFormat::R16S;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::R16UI;
|
||||||
|
case Tegra::Texture::ComponentType::SINT:
|
||||||
|
return PixelFormat::R16I;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::R32:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::R32F;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::R32UI;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::ZF32:
|
||||||
|
return PixelFormat::Z32F;
|
||||||
|
case Tegra::Texture::TextureFormat::Z16:
|
||||||
|
return PixelFormat::Z16;
|
||||||
|
case Tegra::Texture::TextureFormat::Z24S8:
|
||||||
|
return PixelFormat::Z24S8;
|
||||||
|
case Tegra::Texture::TextureFormat::DXT1:
|
||||||
|
return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
|
||||||
|
case Tegra::Texture::TextureFormat::DXT23:
|
||||||
|
return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
|
||||||
|
case Tegra::Texture::TextureFormat::DXT45:
|
||||||
|
return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
|
||||||
|
case Tegra::Texture::TextureFormat::DXN1:
|
||||||
|
return PixelFormat::DXN1;
|
||||||
|
case Tegra::Texture::TextureFormat::DXN2:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::DXN2UNORM;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return PixelFormat::DXN2SNORM;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
case Tegra::Texture::TextureFormat::BC7U:
|
||||||
|
return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
|
||||||
|
case Tegra::Texture::TextureFormat::BC6H_UF16:
|
||||||
|
return PixelFormat::BC6H_UF16;
|
||||||
|
case Tegra::Texture::TextureFormat::BC6H_SF16:
|
||||||
|
return PixelFormat::BC6H_SF16;
|
||||||
|
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
|
||||||
|
return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
|
||||||
|
case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
|
||||||
|
return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
|
||||||
|
case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
|
||||||
|
return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
|
||||||
|
case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
|
||||||
|
return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
|
||||||
|
case Tegra::Texture::TextureFormat::R16_G16:
|
||||||
|
switch (component_type) {
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return PixelFormat::RG16F;
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return PixelFormat::RG16;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return PixelFormat::RG16S;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return PixelFormat::RG16UI;
|
||||||
|
case Tegra::Texture::ComponentType::SINT:
|
||||||
|
return PixelFormat::RG16I;
|
||||||
|
}
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format),
|
||||||
|
static_cast<u32>(component_type));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
|
||||||
|
// TODO(Subv): Implement more component types
|
||||||
|
switch (type) {
|
||||||
|
case Tegra::Texture::ComponentType::UNORM:
|
||||||
|
return ComponentType::UNorm;
|
||||||
|
case Tegra::Texture::ComponentType::FLOAT:
|
||||||
|
return ComponentType::Float;
|
||||||
|
case Tegra::Texture::ComponentType::SNORM:
|
||||||
|
return ComponentType::SNorm;
|
||||||
|
case Tegra::Texture::ComponentType::UINT:
|
||||||
|
return ComponentType::UInt;
|
||||||
|
case Tegra::Texture::ComponentType::SINT:
|
||||||
|
return ComponentType::SInt;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
|
||||||
|
// TODO(Subv): Implement more render targets
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||||
|
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||||
|
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||||
|
return ComponentType::UNorm;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||||
|
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||||
|
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||||
|
return ComponentType::SNorm;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||||
|
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||||
|
return ComponentType::Float;
|
||||||
|
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::R8_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::R16_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::R32_UINT:
|
||||||
|
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||||
|
return ComponentType::UInt;
|
||||||
|
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||||
|
case Tegra::RenderTargetFormat::R16_SINT:
|
||||||
|
return ComponentType::SInt;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||||
|
return PixelFormat::ABGR8U;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::DepthFormat::Z16_UNORM:
|
||||||
|
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||||
|
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||||
|
return ComponentType::UNorm;
|
||||||
|
case Tegra::DepthFormat::Z32_FLOAT:
|
||||||
|
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||||
|
return ComponentType::Float;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||||
|
if (static_cast<std::size_t>(pixel_format) <
|
||||||
|
static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
|
||||||
|
return SurfaceType::ColorTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<std::size_t>(pixel_format) <
|
||||||
|
static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
|
||||||
|
return SurfaceType::Depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<std::size_t>(pixel_format) <
|
||||||
|
static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
|
||||||
|
return SurfaceType::DepthStencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Subv): Implement the other formats
|
||||||
|
ASSERT(false);
|
||||||
|
|
||||||
|
return SurfaceType::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPixelFormatASTC(PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::ASTC_2D_4X4:
|
||||||
|
case PixelFormat::ASTC_2D_5X4:
|
||||||
|
case PixelFormat::ASTC_2D_8X8:
|
||||||
|
case PixelFormat::ASTC_2D_8X5:
|
||||||
|
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||||
|
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::ASTC_2D_4X4:
|
||||||
|
return {4, 4};
|
||||||
|
case PixelFormat::ASTC_2D_5X4:
|
||||||
|
return {5, 4};
|
||||||
|
case PixelFormat::ASTC_2D_8X8:
|
||||||
|
return {8, 8};
|
||||||
|
case PixelFormat::ASTC_2D_8X5:
|
||||||
|
return {8, 5};
|
||||||
|
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||||
|
return {4, 4};
|
||||||
|
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||||
|
return {5, 4};
|
||||||
|
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||||
|
return {8, 8};
|
||||||
|
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||||
|
return {8, 5};
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFormatBCn(PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::DXT1:
|
||||||
|
case PixelFormat::DXT23:
|
||||||
|
case PixelFormat::DXT45:
|
||||||
|
case PixelFormat::DXN1:
|
||||||
|
case PixelFormat::DXN2SNORM:
|
||||||
|
case PixelFormat::DXN2UNORM:
|
||||||
|
case PixelFormat::BC7U:
|
||||||
|
case PixelFormat::BC6H_UF16:
|
||||||
|
case PixelFormat::BC6H_SF16:
|
||||||
|
case PixelFormat::DXT1_SRGB:
|
||||||
|
case PixelFormat::DXT23_SRGB:
|
||||||
|
case PixelFormat::DXT45_SRGB:
|
||||||
|
case PixelFormat::BC7U_SRGB:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VideoCore::Surface
|
385
src/video_core/surface.h
Normal file
385
src/video_core/surface.h
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
// Copyright 2014 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <utility>
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "video_core/gpu.h"
|
||||||
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
namespace VideoCore::Surface {
|
||||||
|
|
||||||
|
enum class PixelFormat {
|
||||||
|
ABGR8U = 0,
|
||||||
|
ABGR8S = 1,
|
||||||
|
ABGR8UI = 2,
|
||||||
|
B5G6R5U = 3,
|
||||||
|
A2B10G10R10U = 4,
|
||||||
|
A1B5G5R5U = 5,
|
||||||
|
R8U = 6,
|
||||||
|
R8UI = 7,
|
||||||
|
RGBA16F = 8,
|
||||||
|
RGBA16U = 9,
|
||||||
|
RGBA16UI = 10,
|
||||||
|
R11FG11FB10F = 11,
|
||||||
|
RGBA32UI = 12,
|
||||||
|
DXT1 = 13,
|
||||||
|
DXT23 = 14,
|
||||||
|
DXT45 = 15,
|
||||||
|
DXN1 = 16, // This is also known as BC4
|
||||||
|
DXN2UNORM = 17,
|
||||||
|
DXN2SNORM = 18,
|
||||||
|
BC7U = 19,
|
||||||
|
BC6H_UF16 = 20,
|
||||||
|
BC6H_SF16 = 21,
|
||||||
|
ASTC_2D_4X4 = 22,
|
||||||
|
G8R8U = 23,
|
||||||
|
G8R8S = 24,
|
||||||
|
BGRA8 = 25,
|
||||||
|
RGBA32F = 26,
|
||||||
|
RG32F = 27,
|
||||||
|
R32F = 28,
|
||||||
|
R16F = 29,
|
||||||
|
R16U = 30,
|
||||||
|
R16S = 31,
|
||||||
|
R16UI = 32,
|
||||||
|
R16I = 33,
|
||||||
|
RG16 = 34,
|
||||||
|
RG16F = 35,
|
||||||
|
RG16UI = 36,
|
||||||
|
RG16I = 37,
|
||||||
|
RG16S = 38,
|
||||||
|
RGB32F = 39,
|
||||||
|
RGBA8_SRGB = 40,
|
||||||
|
RG8U = 41,
|
||||||
|
RG8S = 42,
|
||||||
|
RG32UI = 43,
|
||||||
|
R32UI = 44,
|
||||||
|
ASTC_2D_8X8 = 45,
|
||||||
|
ASTC_2D_8X5 = 46,
|
||||||
|
ASTC_2D_5X4 = 47,
|
||||||
|
BGRA8_SRGB = 48,
|
||||||
|
DXT1_SRGB = 49,
|
||||||
|
DXT23_SRGB = 50,
|
||||||
|
DXT45_SRGB = 51,
|
||||||
|
BC7U_SRGB = 52,
|
||||||
|
ASTC_2D_4X4_SRGB = 53,
|
||||||
|
ASTC_2D_8X8_SRGB = 54,
|
||||||
|
ASTC_2D_8X5_SRGB = 55,
|
||||||
|
ASTC_2D_5X4_SRGB = 56,
|
||||||
|
|
||||||
|
MaxColorFormat,
|
||||||
|
|
||||||
|
// Depth formats
|
||||||
|
Z32F = 57,
|
||||||
|
Z16 = 58,
|
||||||
|
|
||||||
|
MaxDepthFormat,
|
||||||
|
|
||||||
|
// DepthStencil formats
|
||||||
|
Z24S8 = 59,
|
||||||
|
S8Z24 = 60,
|
||||||
|
Z32FS8 = 61,
|
||||||
|
|
||||||
|
MaxDepthStencilFormat,
|
||||||
|
|
||||||
|
Max = MaxDepthStencilFormat,
|
||||||
|
Invalid = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
|
||||||
|
|
||||||
|
enum class ComponentType {
|
||||||
|
Invalid = 0,
|
||||||
|
SNorm = 1,
|
||||||
|
UNorm = 2,
|
||||||
|
SInt = 3,
|
||||||
|
UInt = 4,
|
||||||
|
Float = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SurfaceType {
|
||||||
|
ColorTexture = 0,
|
||||||
|
Depth = 1,
|
||||||
|
DepthStencil = 2,
|
||||||
|
Fill = 3,
|
||||||
|
Invalid = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SurfaceTarget {
|
||||||
|
Texture1D,
|
||||||
|
Texture2D,
|
||||||
|
Texture3D,
|
||||||
|
Texture1DArray,
|
||||||
|
Texture2DArray,
|
||||||
|
TextureCubemap,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
||||||
|
* "compressed width" and "compressed height", not the overall compression factor of a
|
||||||
|
* compressed image. This is used for maintaining proper surface sizes for compressed
|
||||||
|
* texture formats.
|
||||||
|
*/
|
||||||
|
static constexpr u32 GetCompressionFactor(PixelFormat format) {
|
||||||
|
if (format == PixelFormat::Invalid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
|
||||||
|
1, // ABGR8U
|
||||||
|
1, // ABGR8S
|
||||||
|
1, // ABGR8UI
|
||||||
|
1, // B5G6R5U
|
||||||
|
1, // A2B10G10R10U
|
||||||
|
1, // A1B5G5R5U
|
||||||
|
1, // R8U
|
||||||
|
1, // R8UI
|
||||||
|
1, // RGBA16F
|
||||||
|
1, // RGBA16U
|
||||||
|
1, // RGBA16UI
|
||||||
|
1, // R11FG11FB10F
|
||||||
|
1, // RGBA32UI
|
||||||
|
4, // DXT1
|
||||||
|
4, // DXT23
|
||||||
|
4, // DXT45
|
||||||
|
4, // DXN1
|
||||||
|
4, // DXN2UNORM
|
||||||
|
4, // DXN2SNORM
|
||||||
|
4, // BC7U
|
||||||
|
4, // BC6H_UF16
|
||||||
|
4, // BC6H_SF16
|
||||||
|
4, // ASTC_2D_4X4
|
||||||
|
1, // G8R8U
|
||||||
|
1, // G8R8S
|
||||||
|
1, // BGRA8
|
||||||
|
1, // RGBA32F
|
||||||
|
1, // RG32F
|
||||||
|
1, // R32F
|
||||||
|
1, // R16F
|
||||||
|
1, // R16U
|
||||||
|
1, // R16S
|
||||||
|
1, // R16UI
|
||||||
|
1, // R16I
|
||||||
|
1, // RG16
|
||||||
|
1, // RG16F
|
||||||
|
1, // RG16UI
|
||||||
|
1, // RG16I
|
||||||
|
1, // RG16S
|
||||||
|
1, // RGB32F
|
||||||
|
1, // RGBA8_SRGB
|
||||||
|
1, // RG8U
|
||||||
|
1, // RG8S
|
||||||
|
1, // RG32UI
|
||||||
|
1, // R32UI
|
||||||
|
4, // ASTC_2D_8X8
|
||||||
|
4, // ASTC_2D_8X5
|
||||||
|
4, // ASTC_2D_5X4
|
||||||
|
1, // BGRA8_SRGB
|
||||||
|
4, // DXT1_SRGB
|
||||||
|
4, // DXT23_SRGB
|
||||||
|
4, // DXT45_SRGB
|
||||||
|
4, // BC7U_SRGB
|
||||||
|
4, // ASTC_2D_4X4_SRGB
|
||||||
|
4, // ASTC_2D_8X8_SRGB
|
||||||
|
4, // ASTC_2D_8X5_SRGB
|
||||||
|
4, // ASTC_2D_5X4_SRGB
|
||||||
|
1, // Z32F
|
||||||
|
1, // Z16
|
||||||
|
1, // Z24S8
|
||||||
|
1, // S8Z24
|
||||||
|
1, // Z32FS8
|
||||||
|
}};
|
||||||
|
|
||||||
|
ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
|
||||||
|
return compression_factor_table[static_cast<std::size_t>(format)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
|
||||||
|
if (format == PixelFormat::Invalid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
|
||||||
|
1, // ABGR8U
|
||||||
|
1, // ABGR8S
|
||||||
|
1, // ABGR8UI
|
||||||
|
1, // B5G6R5U
|
||||||
|
1, // A2B10G10R10U
|
||||||
|
1, // A1B5G5R5U
|
||||||
|
1, // R8U
|
||||||
|
1, // R8UI
|
||||||
|
1, // RGBA16F
|
||||||
|
1, // RGBA16U
|
||||||
|
1, // RGBA16UI
|
||||||
|
1, // R11FG11FB10F
|
||||||
|
1, // RGBA32UI
|
||||||
|
4, // DXT1
|
||||||
|
4, // DXT23
|
||||||
|
4, // DXT45
|
||||||
|
4, // DXN1
|
||||||
|
4, // DXN2UNORM
|
||||||
|
4, // DXN2SNORM
|
||||||
|
4, // BC7U
|
||||||
|
4, // BC6H_UF16
|
||||||
|
4, // BC6H_SF16
|
||||||
|
4, // ASTC_2D_4X4
|
||||||
|
1, // G8R8U
|
||||||
|
1, // G8R8S
|
||||||
|
1, // BGRA8
|
||||||
|
1, // RGBA32F
|
||||||
|
1, // RG32F
|
||||||
|
1, // R32F
|
||||||
|
1, // R16F
|
||||||
|
1, // R16U
|
||||||
|
1, // R16S
|
||||||
|
1, // R16UI
|
||||||
|
1, // R16I
|
||||||
|
1, // RG16
|
||||||
|
1, // RG16F
|
||||||
|
1, // RG16UI
|
||||||
|
1, // RG16I
|
||||||
|
1, // RG16S
|
||||||
|
1, // RGB32F
|
||||||
|
1, // RGBA8_SRGB
|
||||||
|
1, // RG8U
|
||||||
|
1, // RG8S
|
||||||
|
1, // RG32UI
|
||||||
|
1, // R32UI
|
||||||
|
8, // ASTC_2D_8X8
|
||||||
|
5, // ASTC_2D_8X5
|
||||||
|
4, // ASTC_2D_5X4
|
||||||
|
1, // BGRA8_SRGB
|
||||||
|
4, // DXT1_SRGB
|
||||||
|
4, // DXT23_SRGB
|
||||||
|
4, // DXT45_SRGB
|
||||||
|
4, // BC7U_SRGB
|
||||||
|
4, // ASTC_2D_4X4_SRGB
|
||||||
|
8, // ASTC_2D_8X8_SRGB
|
||||||
|
5, // ASTC_2D_8X5_SRGB
|
||||||
|
4, // ASTC_2D_5X4_SRGB
|
||||||
|
1, // Z32F
|
||||||
|
1, // Z16
|
||||||
|
1, // Z24S8
|
||||||
|
1, // S8Z24
|
||||||
|
1, // Z32FS8
|
||||||
|
}};
|
||||||
|
|
||||||
|
ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
|
||||||
|
return block_height_table[static_cast<std::size_t>(format)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr u32 GetFormatBpp(PixelFormat format) {
|
||||||
|
if (format == PixelFormat::Invalid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
|
||||||
|
32, // ABGR8U
|
||||||
|
32, // ABGR8S
|
||||||
|
32, // ABGR8UI
|
||||||
|
16, // B5G6R5U
|
||||||
|
32, // A2B10G10R10U
|
||||||
|
16, // A1B5G5R5U
|
||||||
|
8, // R8U
|
||||||
|
8, // R8UI
|
||||||
|
64, // RGBA16F
|
||||||
|
64, // RGBA16U
|
||||||
|
64, // RGBA16UI
|
||||||
|
32, // R11FG11FB10F
|
||||||
|
128, // RGBA32UI
|
||||||
|
64, // DXT1
|
||||||
|
128, // DXT23
|
||||||
|
128, // DXT45
|
||||||
|
64, // DXN1
|
||||||
|
128, // DXN2UNORM
|
||||||
|
128, // DXN2SNORM
|
||||||
|
128, // BC7U
|
||||||
|
128, // BC6H_UF16
|
||||||
|
128, // BC6H_SF16
|
||||||
|
32, // ASTC_2D_4X4
|
||||||
|
16, // G8R8U
|
||||||
|
16, // G8R8S
|
||||||
|
32, // BGRA8
|
||||||
|
128, // RGBA32F
|
||||||
|
64, // RG32F
|
||||||
|
32, // R32F
|
||||||
|
16, // R16F
|
||||||
|
16, // R16U
|
||||||
|
16, // R16S
|
||||||
|
16, // R16UI
|
||||||
|
16, // R16I
|
||||||
|
32, // RG16
|
||||||
|
32, // RG16F
|
||||||
|
32, // RG16UI
|
||||||
|
32, // RG16I
|
||||||
|
32, // RG16S
|
||||||
|
96, // RGB32F
|
||||||
|
32, // RGBA8_SRGB
|
||||||
|
16, // RG8U
|
||||||
|
16, // RG8S
|
||||||
|
64, // RG32UI
|
||||||
|
32, // R32UI
|
||||||
|
16, // ASTC_2D_8X8
|
||||||
|
16, // ASTC_2D_8X5
|
||||||
|
32, // ASTC_2D_5X4
|
||||||
|
32, // BGRA8_SRGB
|
||||||
|
64, // DXT1_SRGB
|
||||||
|
128, // DXT23_SRGB
|
||||||
|
128, // DXT45_SRGB
|
||||||
|
128, // BC7U
|
||||||
|
32, // ASTC_2D_4X4_SRGB
|
||||||
|
16, // ASTC_2D_8X8_SRGB
|
||||||
|
16, // ASTC_2D_8X5_SRGB
|
||||||
|
32, // ASTC_2D_5X4_SRGB
|
||||||
|
32, // Z32F
|
||||||
|
16, // Z16
|
||||||
|
32, // Z24S8
|
||||||
|
32, // S8Z24
|
||||||
|
64, // Z32FS8
|
||||||
|
}};
|
||||||
|
|
||||||
|
ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
|
||||||
|
return bpp_table[static_cast<std::size_t>(format)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sizer in bytes of the specified pixel format
|
||||||
|
static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
|
||||||
|
if (pixel_format == PixelFormat::Invalid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return GetFormatBpp(pixel_format) / CHAR_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
|
||||||
|
|
||||||
|
bool SurfaceTargetIsLayered(SurfaceTarget target);
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||||
|
Tegra::Texture::ComponentType component_type,
|
||||||
|
bool is_srgb);
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type);
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format);
|
||||||
|
|
||||||
|
PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format);
|
||||||
|
|
||||||
|
ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format);
|
||||||
|
|
||||||
|
SurfaceType GetFormatType(PixelFormat pixel_format);
|
||||||
|
|
||||||
|
bool IsPixelFormatASTC(PixelFormat format);
|
||||||
|
|
||||||
|
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
|
||||||
|
|
||||||
|
/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
|
||||||
|
bool IsFormatBCn(PixelFormat format);
|
||||||
|
|
||||||
|
} // namespace VideoCore::Surface
|
|
@ -102,16 +102,27 @@ void TelemetryJson::Complete() {
|
||||||
impl->SerializeSection(Telemetry::FieldType::App, "App");
|
impl->SerializeSection(Telemetry::FieldType::App, "App");
|
||||||
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
|
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
|
||||||
impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
|
impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
|
||||||
impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
|
|
||||||
impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
|
impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
|
||||||
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
|
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
|
||||||
|
|
||||||
auto content = impl->TopSection().dump();
|
auto content = impl->TopSection().dump();
|
||||||
// Send the telemetry async but don't handle the errors since they were written to the log
|
// Send the telemetry async but don't handle the errors since they were written to the log
|
||||||
Common::DetachedTasks::AddTask(
|
Common::DetachedTasks::AddTask([host{impl->host}, content]() {
|
||||||
[host{impl->host}, username{impl->username}, token{impl->token}, content]() {
|
Client{host, "", ""}.PostJson("/telemetry", content, true);
|
||||||
Client{host, username, token}.PostJson("/telemetry", content, true);
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
bool TelemetryJson::SubmitTestcase() {
|
||||||
|
impl->SerializeSection(Telemetry::FieldType::App, "App");
|
||||||
|
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
|
||||||
|
impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
|
||||||
|
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
|
||||||
|
|
||||||
|
auto content = impl->TopSection().dump();
|
||||||
|
Client client(impl->host, impl->username, impl->token);
|
||||||
|
auto value = client.PostJson("/gamedb/testcase", content, false);
|
||||||
|
|
||||||
|
return value.result_code == Common::WebResult::Code::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace WebService
|
} // namespace WebService
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
|
void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
|
||||||
|
|
||||||
void Complete() override;
|
void Complete() override;
|
||||||
|
bool SubmitTestcase() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Impl;
|
struct Impl;
|
||||||
|
|
|
@ -56,6 +56,8 @@ add_executable(yuzu
|
||||||
main.h
|
main.h
|
||||||
ui_settings.cpp
|
ui_settings.cpp
|
||||||
ui_settings.h
|
ui_settings.h
|
||||||
|
util/limitable_input_dialog.cpp
|
||||||
|
util/limitable_input_dialog.h
|
||||||
util/spinbox.cpp
|
util/spinbox.cpp
|
||||||
util/spinbox.h
|
util/spinbox.h
|
||||||
util/util.cpp
|
util/util.cpp
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/telemetry.h"
|
#include "common/telemetry.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
@ -23,6 +24,8 @@ CompatDB::CompatDB(QWidget* parent)
|
||||||
connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||||
connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||||
connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
|
connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
|
||||||
|
connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
|
||||||
|
&CompatDB::OnTestcaseSubmitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompatDB::~CompatDB() = default;
|
CompatDB::~CompatDB() = default;
|
||||||
|
@ -48,18 +51,38 @@ void CompatDB::Submit() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CompatDBPage::Final:
|
case CompatDBPage::Final:
|
||||||
|
back();
|
||||||
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
||||||
Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
|
Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
|
||||||
compatibility->checkedId());
|
compatibility->checkedId());
|
||||||
// older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
|
|
||||||
// workaround
|
button(NextButton)->setEnabled(false);
|
||||||
|
button(NextButton)->setText(tr("Submitting"));
|
||||||
button(QWizard::CancelButton)->setVisible(false);
|
button(QWizard::CancelButton)->setVisible(false);
|
||||||
|
|
||||||
|
testcase_watcher.setFuture(QtConcurrent::run(
|
||||||
|
[this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompatDB::OnTestcaseSubmitted() {
|
||||||
|
if (!testcase_watcher.result()) {
|
||||||
|
QMessageBox::critical(this, tr("Communication error"),
|
||||||
|
tr("An error occured while sending the Testcase"));
|
||||||
|
button(NextButton)->setEnabled(true);
|
||||||
|
button(NextButton)->setText(tr("Next"));
|
||||||
|
button(QWizard::CancelButton)->setVisible(true);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
// older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
|
||||||
|
// workaround
|
||||||
|
button(QWizard::CancelButton)->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CompatDB::EnableNext() {
|
void CompatDB::EnableNext() {
|
||||||
button(NextButton)->setEnabled(true);
|
button(NextButton)->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QWizard>
|
#include <QWizard>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -19,8 +20,11 @@ public:
|
||||||
~CompatDB();
|
~CompatDB();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QFutureWatcher<bool> testcase_watcher;
|
||||||
|
|
||||||
std::unique_ptr<Ui::CompatDB> ui;
|
std::unique_ptr<Ui::CompatDB> ui;
|
||||||
|
|
||||||
void Submit();
|
void Submit();
|
||||||
|
void OnTestcaseSubmitted();
|
||||||
void EnableNext();
|
void EnableNext();
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,20 +6,20 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QInputDialog>
|
#include <QHeaderView>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include "common/common_paths.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/file_util.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
#include "core/hle/service/acc/profile_manager.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "ui_configure_system.h"
|
#include "ui_configure_system.h"
|
||||||
#include "yuzu/configuration/configure_system.h"
|
#include "yuzu/configuration/configure_system.h"
|
||||||
#include "yuzu/main.h"
|
#include "yuzu/util/limitable_input_dialog.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr std::array<int, 12> days_in_month = {{
|
constexpr std::array<int, 12> days_in_month = {{
|
||||||
|
@ -83,6 +83,12 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
|
||||||
|
|
||||||
return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) {
|
||||||
|
return LimitableInputDialog::GetText(parent, ConfigureSystem::tr("Enter Username"),
|
||||||
|
description_text, 1,
|
||||||
|
static_cast<int>(Service::Account::profile_username_size));
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
ConfigureSystem::ConfigureSystem(QWidget* parent)
|
ConfigureSystem::ConfigureSystem(QWidget* parent)
|
||||||
|
@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureSystem::AddUser() {
|
void ConfigureSystem::AddUser() {
|
||||||
const auto uuid = Service::Account::UUID::Generate();
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
const auto username =
|
const auto username =
|
||||||
QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"),
|
GetProfileUsernameFromUser(this, tr("Enter a username for the new user:"));
|
||||||
QLineEdit::Normal, QString(), &ok);
|
if (username.isEmpty()) {
|
||||||
if (!ok)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto uuid = Service::Account::UUID::Generate();
|
||||||
profile_manager->CreateNewUser(uuid, username.toStdString());
|
profile_manager->CreateNewUser(uuid, username.toStdString());
|
||||||
|
|
||||||
item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
|
item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
|
||||||
|
@ -267,24 +271,15 @@ void ConfigureSystem::RenameUser() {
|
||||||
if (!profile_manager->GetProfileBase(*uuid, profile))
|
if (!profile_manager->GetProfileBase(*uuid, profile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool ok = false;
|
const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
|
||||||
const auto old_username = GetAccountUsername(*profile_manager, *uuid);
|
if (new_username.isEmpty()) {
|
||||||
const auto new_username =
|
|
||||||
QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"),
|
|
||||||
QLineEdit::Normal, old_username, &ok);
|
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::fill(profile.username.begin(), profile.username.end(), '\0');
|
|
||||||
const auto username_std = new_username.toStdString();
|
|
||||||
if (username_std.size() > profile.username.size()) {
|
|
||||||
std::copy_n(username_std.begin(), std::min(profile.username.size(), username_std.size()),
|
|
||||||
profile.username.begin());
|
|
||||||
} else {
|
|
||||||
std::copy(username_std.begin(), username_std.end(), profile.username.begin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto username_std = new_username.toStdString();
|
||||||
|
std::fill(profile.username.begin(), profile.username.end(), '\0');
|
||||||
|
std::copy(username_std.begin(), username_std.end(), profile.username.begin());
|
||||||
|
|
||||||
profile_manager->SetProfileBase(*uuid, profile);
|
profile_manager->SetProfileBase(*uuid, profile);
|
||||||
|
|
||||||
item_model->setItem(
|
item_model->setItem(
|
||||||
|
|
59
src/yuzu/util/limitable_input_dialog.cpp
Normal file
59
src/yuzu/util/limitable_input_dialog.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2018 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include "yuzu/util/limitable_input_dialog.h"
|
||||||
|
|
||||||
|
LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} {
|
||||||
|
CreateUI();
|
||||||
|
ConnectEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
LimitableInputDialog::~LimitableInputDialog() = default;
|
||||||
|
|
||||||
|
void LimitableInputDialog::CreateUI() {
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
text_label = new QLabel(this);
|
||||||
|
text_entry = new QLineEdit(this);
|
||||||
|
buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
|
|
||||||
|
auto* const layout = new QVBoxLayout;
|
||||||
|
layout->addWidget(text_label);
|
||||||
|
layout->addWidget(text_entry);
|
||||||
|
layout->addWidget(buttons);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimitableInputDialog::ConnectEvents() {
|
||||||
|
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
|
||||||
|
int min_character_limit, int max_character_limit) {
|
||||||
|
Q_ASSERT(min_character_limit <= max_character_limit);
|
||||||
|
|
||||||
|
LimitableInputDialog dialog{parent};
|
||||||
|
dialog.setWindowTitle(title);
|
||||||
|
dialog.text_label->setText(text);
|
||||||
|
dialog.text_entry->setMaxLength(max_character_limit);
|
||||||
|
|
||||||
|
auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
|
||||||
|
ok_button->setEnabled(false);
|
||||||
|
connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
|
||||||
|
ok_button->setEnabled(new_text.length() >= min_character_limit);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dialog.exec() != QDialog::Accepted) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog.text_entry->text();
|
||||||
|
}
|
31
src/yuzu/util/limitable_input_dialog.h
Normal file
31
src/yuzu/util/limitable_input_dialog.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2018 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QDialogButtonBox;
|
||||||
|
class QLabel;
|
||||||
|
class QLineEdit;
|
||||||
|
|
||||||
|
/// A QDialog that functions similarly to QInputDialog, however, it allows
|
||||||
|
/// restricting the minimum and total number of characters that can be entered.
|
||||||
|
class LimitableInputDialog final : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit LimitableInputDialog(QWidget* parent = nullptr);
|
||||||
|
~LimitableInputDialog() override;
|
||||||
|
|
||||||
|
static QString GetText(QWidget* parent, const QString& title, const QString& text,
|
||||||
|
int min_character_limit, int max_character_limit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateUI();
|
||||||
|
void ConnectEvents();
|
||||||
|
|
||||||
|
QLabel* text_label;
|
||||||
|
QLineEdit* text_entry;
|
||||||
|
QDialogButtonBox* buttons;
|
||||||
|
};
|
Loading…
Reference in a new issue