Compare commits

..

32 Commits

Author SHA1 Message Date
Marcos Vitali
cd94dc484a Initialize polygon_offset in the constructor. 2018-11-23 10:38:06 -03:00
Marcos Vitali
ddeb7809f7 Clang Format fixes. 2018-11-23 10:10:48 -03:00
Marcos Vitali
33ba10591e GPU States: Implement Polygon Offset. This is used in SMO all the time. 2018-11-23 03:01:33 -03:00
Mat M
bee5a7acb1 Merge pull request #1779 from DarkLordZach/debug-pad-unmapped
debug_pad: Avoid loading input for nonexistent buttons (Home and Screenshot)
2018-11-22 13:41:32 -05:00
Zach Hilman
b358e88512 debug_pad: Avoid loading input for nonexistent buttons (Home and Screenshot)
Prevents memory exceptions when the debug pad is enabled.
2018-11-22 12:23:43 -05:00
bunnei
50d2abaaa9 Merge pull request #1775 from bunnei/blend-eq
maxwell_3d: Implement alternate blend equations.
2018-11-22 08:44:05 -08:00
bunnei
af159a4d08 Merge pull request #1765 from bunnei/multi-audout
audout_u: Add support for multiple IAudioOut streams.
2018-11-22 08:43:53 -08:00
bunnei
e633021532 Merge pull request #1764 from bunnei/macrointerpreter
macro_interpreter: Implement AddWithCarry and SubtractWithBorrow.
2018-11-22 08:43:29 -08:00
bunnei
033b46253e macro_interpreter: Implement AddWithCarry and SubtractWithBorrow.
- Used by Undertale.
2018-11-22 00:58:00 -05:00
bunnei
5a6dc4d041 audout_u: Add support for multiple IAudioOut streams.
- Used by Undertale.
2018-11-22 00:53:39 -05:00
bunnei
0e6a608245 maxwell_3d: Implement alternate blend equations.
- Used by Undertale.
2018-11-22 00:51:01 -05:00
bunnei
b84f4cfb62 Merge pull request #1737 from FernandoS27/layer-copy
Implemented Fast Layered Copy
2018-11-21 21:39:16 -08:00
bunnei
f0d3f1b376 Merge pull request #1771 from lioncash/bit-set
common: Remove bit_set.h
2018-11-21 21:36:15 -08:00
bunnei
f926559ef4 Merge pull request #1767 from lioncash/handle
kernel/handle_table: Minor changes
2018-11-21 21:26:48 -08:00
Lioncash
8b27e73bd7 common: Remove bit_set.h
This is an analog of BitSet from Dolphin that was introduced to allow
iterating over a set of bits. Given it's currently unused, and given
that std::bitset exists, we can remove this. If it's ever needed in the
future it can be brought back.
2018-11-21 21:30:10 -05:00
Lioncash
0e35f1bb18 kernel/handle_table: Move private static functions into the cpp file
These don't depend on class state, and are effectively implementation
details, so they can go into the cpp file .
2018-11-21 18:31:01 -05:00
Lioncash
568bcbc29d kernel/handle_table: Restrict handle table size to 1024 entries
The previous handle table size is a holdover from Citra. The actual
handle table construct on Horizon only allows for a maximum of 1024
entries.
2018-11-21 18:28:03 -05:00
Lioncash
f5ce71793e kernel/handle_table: Default destructor in the cpp file
We don't need to potentially inline the teardown logic of all of the
handle instances.
2018-11-21 18:23:09 -05:00
bunnei
ec38b4e883 Merge pull request #1753 from FernandoS27/ufbtype
Use default values for unknown framebuffer pixel format
2018-11-21 14:15:27 -08:00
bunnei
61586e8794 Merge pull request #1752 from ReinUsesLisp/unimpl-decompiler
gl_shader_decompiler: Use UNIMPLEMENTED when applicable
2018-11-21 14:13:28 -08:00
bunnei
d4012a4540 Merge pull request #1742 from lioncash/hle-swkbd
am/applets: Minor cleanup
2018-11-21 11:43:43 -08:00
bunnei
bb175ab430 Merge pull request #1754 from ReinUsesLisp/zero-register
gl_shader_decompiler: Remove UNREACHABLE when setting RZ
2018-11-21 08:06:29 -08:00
bunnei
8cdb48224d Merge pull request #1758 from lioncash/rect
common/math_util: Minor cleanup
2018-11-21 08:05:39 -08:00
bunnei
81e14c072a Merge pull request #1759 from lioncash/unused
common: Remove depencency on xbyak
2018-11-21 08:05:14 -08:00
FernandoS27
0a9fedfac9 Use default values for unknown framebuffer pixel format 2018-11-21 07:33:34 -04:00
Lioncash
3533d33ff5 common: Remove dependency on xbyak
Xbyak is currently entirely unused. Rather than carting it along, remove
it and get rid of a dependency. If it's ever needed in the future, then
it can be re-added (and likely be more up to date at that point in
time).
2018-11-21 03:43:41 -05:00
ReinUsesLisp
423a3ed2c8 gl_shader_decompiler: Remove UNREACHABLE when setting RZ 2018-11-20 22:23:10 -03:00
ReinUsesLisp
bb893188eb gl_shader_decompiler: Use UNIMPLEMENTED instead of LOG+UNREACHABLE when applicable 2018-11-20 22:00:13 -03:00
Lioncash
73b7748984 am/applets: Make the applet data broker part of the applet itself.
The accessor should be doing just that, accessing, rather than retaining
the lifetime of the data broker as well.
2018-11-20 12:36:33 -05:00
Lioncash
8b4b560df5 am/applets: Replace includes with forward declarations where applicable
Also resolve places where includes should have been provided, but
weren't.
2018-11-20 11:53:55 -05:00
Lioncash
dd254c603d am/applets: Relocate comments above the relevant data member in AppletDataBroker
Avoids wonky wrapping and makes it nicer to read.
2018-11-20 11:49:49 -05:00
FernandoS27
eb36463e03 Implemented Fast Layered Copy 2018-11-19 19:51:13 -04:00
30 changed files with 543 additions and 987 deletions

3
.gitmodules vendored
View File

@@ -13,9 +13,6 @@
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "fmt"]
path = externals/fmt
url = https://github.com/fmtlib/fmt.git

View File

@@ -9,7 +9,6 @@ target_include_directories(catch-single-include INTERFACE catch/single_include)
# Dynarmic
if (ARCHITECTURE_x86_64)
add_library(xbyak INTERFACE)
set(DYNARMIC_TESTS OFF)
set(DYNARMIC_NO_BUNDLED_FMT ON)
add_subdirectory(dynarmic)
@@ -53,14 +52,6 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# SoundTouch
add_subdirectory(soundtouch)
# Xbyak
if (ARCHITECTURE_x86_64)
# Defined before "dynarmic" above
# add_library(xbyak INTERFACE)
target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
# Opus
add_subdirectory(opus)
target_include_directories(opus INTERFACE ./opus/include)

1
externals/xbyak vendored

Submodule externals/xbyak deleted from 1de435ed04

View File

@@ -44,7 +44,6 @@ add_library(common STATIC
detached_tasks.cpp
detached_tasks.h
bit_field.h
bit_set.h
cityhash.cpp
cityhash.h
color.h
@@ -95,14 +94,9 @@ if(ARCHITECTURE_x86_64)
PRIVATE
x64/cpu_detect.cpp
x64/cpu_detect.h
x64/xbyak_abi.h
x64/xbyak_util.h
)
endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)
endif()

View File

@@ -1,244 +0,0 @@
// This file is under the public domain.
#pragma once
#include <cstddef>
#ifdef _WIN32
#include <intrin.h>
#endif
#include <initializer_list>
#include <new>
#include <type_traits>
#include "common/common_types.h"
// namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly
namespace Common {
// Helper functions:
#ifdef _MSC_VER
template <typename T>
static inline int CountSetBits(T v) {
// from https://graphics.stanford.edu/~seander/bithacks.html
// GCC has this built in, but MSVC's intrinsic will only emit the actual
// POPCNT instruction, which we're not depending on
v = v - ((v >> 1) & (T) ~(T)0 / 3);
v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
}
static inline int LeastSignificantSetBit(u8 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u16 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u32 val) {
unsigned long index;
_BitScanForward(&index, val);
return (int)index;
}
static inline int LeastSignificantSetBit(u64 val) {
unsigned long index;
_BitScanForward64(&index, val);
return (int)index;
}
#else
static inline int CountSetBits(u8 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u16 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u32 val) {
return __builtin_popcount(val);
}
static inline int CountSetBits(u64 val) {
return __builtin_popcountll(val);
}
static inline int LeastSignificantSetBit(u8 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u16 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u32 val) {
return __builtin_ctz(val);
}
static inline int LeastSignificantSetBit(u64 val) {
return __builtin_ctzll(val);
}
#endif
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
// using the set bits of an integer to represent a set of integers. Like that
// class, it acts like an array of bools:
// BitSet32 bs;
// bs[1] = true;
// but also like the underlying integer ([0] = least significant bit):
// BitSet32 bs2 = ...;
// bs = (bs ^ bs2) & BitSet32(0xffff);
// The following additional functionality is provided:
// - Construction using an initializer list.
// BitSet bs { 1, 2, 4, 8 };
// - Efficiently iterating through the set bits:
// for (int i : bs)
// [i is the *index* of a set bit]
// (This uses the appropriate CPU instruction to find the next set bit in one
// operation.)
// - Counting set bits using .Count() - see comment on that method.
// TODO: use constexpr when MSVC gets out of the Dark Ages
template <typename IntTy>
class BitSet {
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
public:
// A reference to a particular bit, returned from operator[].
class Ref {
public:
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
operator bool() const {
return (m_bs->m_val & m_mask) != 0;
}
bool operator=(bool set) {
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
return set;
}
private:
BitSet* m_bs;
IntTy m_mask;
};
// A STL-like iterator is required to be able to use range-based for loops.
class Iterator {
public:
Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
Iterator(IntTy val) : m_val(val), m_bit(0) {}
Iterator& operator=(Iterator other) {
new (this) Iterator(other);
return *this;
}
int operator*() {
return m_bit + ComputeLsb();
}
Iterator& operator++() {
int lsb = ComputeLsb();
m_val >>= lsb + 1;
m_bit += lsb + 1;
m_has_lsb = false;
return *this;
}
Iterator operator++(int _) {
Iterator other(*this);
++*this;
return other;
}
bool operator==(Iterator other) const {
return m_val == other.m_val;
}
bool operator!=(Iterator other) const {
return m_val != other.m_val;
}
private:
int ComputeLsb() {
if (!m_has_lsb) {
m_lsb = LeastSignificantSetBit(m_val);
m_has_lsb = true;
}
return m_lsb;
}
IntTy m_val;
int m_bit;
int m_lsb = -1;
bool m_has_lsb = false;
};
BitSet() : m_val(0) {}
explicit BitSet(IntTy val) : m_val(val) {}
BitSet(std::initializer_list<int> init) {
m_val = 0;
for (int bit : init)
m_val |= (IntTy)1 << bit;
}
static BitSet AllTrue(std::size_t count) {
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
}
Ref operator[](std::size_t bit) {
return Ref(this, (IntTy)1 << bit);
}
const Ref operator[](std::size_t bit) const {
return (*const_cast<BitSet*>(this))[bit];
}
bool operator==(BitSet other) const {
return m_val == other.m_val;
}
bool operator!=(BitSet other) const {
return m_val != other.m_val;
}
bool operator<(BitSet other) const {
return m_val < other.m_val;
}
bool operator>(BitSet other) const {
return m_val > other.m_val;
}
BitSet operator|(BitSet other) const {
return BitSet(m_val | other.m_val);
}
BitSet operator&(BitSet other) const {
return BitSet(m_val & other.m_val);
}
BitSet operator^(BitSet other) const {
return BitSet(m_val ^ other.m_val);
}
BitSet operator~() const {
return BitSet(~m_val);
}
BitSet& operator|=(BitSet other) {
return *this = *this | other;
}
BitSet& operator&=(BitSet other) {
return *this = *this & other;
}
BitSet& operator^=(BitSet other) {
return *this = *this ^ other;
}
operator u32() = delete;
operator bool() {
return m_val != 0;
}
// Warning: Even though on modern CPUs this is a single fast instruction,
// Dolphin's official builds do not currently assume POPCNT support on x86,
// so slower explicit bit twiddling is generated. Still should generally
// be faster than a loop.
unsigned int Count() const {
return CountSetBits(m_val);
}
Iterator begin() const {
return Iterator(m_val);
}
Iterator end() const {
return Iterator(0);
}
IntTy m_val;
};
} // namespace Common
typedef Common::BitSet<u8> BitSet8;
typedef Common::BitSet<u16> BitSet16;
typedef Common::BitSet<u32> BitSet32;
typedef Common::BitSet<u64> BitSet64;

View File

@@ -1,222 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <initializer_list>
#include <xbyak.h>
#include "common/assert.h"
#include "common/bit_set.h"
namespace Common::X64 {
inline int RegToIndex(const Xbyak::Reg& reg) {
using Kind = Xbyak::Reg::Kind;
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
"RegSet only support GPRs and XMM registers.");
ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
}
inline Xbyak::Reg64 IndexToReg64(int reg_index) {
ASSERT(reg_index < 16);
return Xbyak::Reg64(reg_index);
}
inline Xbyak::Xmm IndexToXmm(int reg_index) {
ASSERT(reg_index >= 16 && reg_index < 32);
return Xbyak::Xmm(reg_index - 16);
}
inline Xbyak::Reg IndexToReg(int reg_index) {
if (reg_index < 16) {
return IndexToReg64(reg_index);
} else {
return IndexToXmm(reg_index);
}
}
inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
BitSet32 bits;
for (const Xbyak::Reg& reg : regs) {
bits[RegToIndex(reg)] = true;
}
return bits;
}
const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
#ifdef _WIN32
// Microsoft x64 ABI
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm5,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rsi,
Xbyak::util::rdi,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::r15,
// XMMs
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0x20;
#else
// System V x86-64 ABI
const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rcx,
Xbyak::util::rdx,
Xbyak::util::rdi,
Xbyak::util::rsi,
Xbyak::util::r8,
Xbyak::util::r9,
Xbyak::util::r10,
Xbyak::util::r11,
// XMMs
Xbyak::util::xmm0,
Xbyak::util::xmm1,
Xbyak::util::xmm2,
Xbyak::util::xmm3,
Xbyak::util::xmm4,
Xbyak::util::xmm5,
Xbyak::util::xmm6,
Xbyak::util::xmm7,
Xbyak::util::xmm8,
Xbyak::util::xmm9,
Xbyak::util::xmm10,
Xbyak::util::xmm11,
Xbyak::util::xmm12,
Xbyak::util::xmm13,
Xbyak::util::xmm14,
Xbyak::util::xmm15,
});
const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
// GPRs
Xbyak::util::rbx,
Xbyak::util::rbp,
Xbyak::util::r12,
Xbyak::util::r13,
Xbyak::util::r14,
Xbyak::util::r15,
});
constexpr std::size_t ABI_SHADOW_SPACE = 0;
#endif
inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment,
std::size_t needed_frame_size, s32* out_subtraction,
s32* out_xmm_offset) {
int count = (regs & ABI_ALL_GPRS).Count();
rsp_alignment -= count * 8;
std::size_t subtraction = 0;
int xmm_count = (regs & ABI_ALL_XMMS).Count();
if (xmm_count) {
// If we have any XMMs to save, we must align the stack here.
subtraction = rsp_alignment & 0xF;
}
subtraction += 0x10 * xmm_count;
std::size_t xmm_base_subtraction = subtraction;
subtraction += needed_frame_size;
subtraction += ABI_SHADOW_SPACE;
// Final alignment.
rsp_alignment -= subtraction;
subtraction += rsp_alignment & 0xF;
*out_subtraction = (s32)subtraction;
*out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
}
inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
for (int reg_index : (regs & ABI_ALL_GPRS)) {
code.push(IndexToReg64(reg_index));
}
if (subtraction != 0) {
code.sub(code.rsp, subtraction);
}
for (int reg_index : (regs & ABI_ALL_XMMS)) {
code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
xmm_offset += 0x10;
}
return ABI_SHADOW_SPACE;
}
inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
std::size_t rsp_alignment,
std::size_t needed_frame_size = 0) {
s32 subtraction, xmm_offset;
ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
for (int reg_index : (regs & ABI_ALL_XMMS)) {
code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
xmm_offset += 0x10;
}
if (subtraction != 0) {
code.add(code.rsp, subtraction);
}
// GPRs need to be popped in reverse order
for (int reg_index = 15; reg_index >= 0; reg_index--) {
if (regs[reg_index]) {
code.pop(IndexToReg64(reg_index));
}
}
}
} // namespace Common::X64

View File

@@ -1,47 +0,0 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <type_traits>
#include <xbyak.h>
#include "common/x64/xbyak_abi.h"
namespace Common::X64 {
// Constants for use with cmpps/cmpss
enum {
CMP_EQ = 0,
CMP_LT = 1,
CMP_LE = 2,
CMP_UNORD = 3,
CMP_NEQ = 4,
CMP_NLT = 5,
CMP_NLE = 6,
CMP_ORD = 7,
};
inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
u64 distance = target - (ref + 5);
return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
}
inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
}
template <typename T>
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
std::size_t addr = reinterpret_cast<std::size_t>(f);
if (IsWithin2G(code, addr)) {
code.call(f);
} else {
// ABI_RETURN is a safe temp register to use before a call
code.mov(ABI_RETURN, addr);
code.call(ABI_RETURN);
}
}
} // namespace Common::X64

View File

@@ -12,12 +12,23 @@
#include "core/hle/kernel/thread.h"
namespace Kernel {
namespace {
constexpr u16 GetSlot(Handle handle) {
return handle >> 15;
}
constexpr u16 GetGeneration(Handle handle) {
return handle & 0x7FFF;
}
} // Anonymous namespace
HandleTable::HandleTable() {
next_generation = 1;
Clear();
}
HandleTable::~HandleTable() = default;
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
DEBUG_ASSERT(obj != nullptr);

View File

@@ -43,6 +43,7 @@ enum KernelHandle : Handle {
class HandleTable final : NonCopyable {
public:
HandleTable();
~HandleTable();
/**
* Allocates a handle for the given object.
@@ -89,18 +90,8 @@ public:
void Clear();
private:
/**
* This is the maximum limit of handles allowed per process in CTR-OS. It can be further
* reduced by ExHeader values, but this is not emulated here.
*/
static const std::size_t MAX_COUNT = 4096;
static u16 GetSlot(Handle handle) {
return handle >> 15;
}
static u16 GetGeneration(Handle handle) {
return handle & 0x7FFF;
}
/// This is the maximum limit of handles allowed per process in Horizon
static constexpr std::size_t MAX_COUNT = 1024;
/// Stores the Object referenced by the handle or null if the slot is empty.
std::array<SharedPtr<Object>, MAX_COUNT> objects;

View File

@@ -532,8 +532,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)),
broker(std::make_shared<Applets::AppletDataBroker>()) {
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
@@ -562,7 +561,7 @@ public:
private:
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
const auto event = broker->GetStateChangedEvent();
const auto event = applet->GetBroker().GetStateChangedEvent();
event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -590,7 +589,7 @@ private:
void Start(Kernel::HLERequestContext& ctx) {
ASSERT(applet != nullptr);
applet->Initialize(broker);
applet->Initialize();
applet->Execute();
IPC::ResponseBuilder rb{ctx, 2};
@@ -601,7 +600,7 @@ private:
void PushInData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -612,7 +611,7 @@ private:
void PopOutData(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
const auto storage = broker->PopNormalDataToGame();
const auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) {
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
@@ -626,7 +625,7 @@ private:
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
ASSERT(applet->IsInitialized());
applet->ExecuteInteractive();
@@ -641,7 +640,7 @@ private:
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
const auto storage = broker->PopInteractiveDataToGame();
const auto storage = applet->GetBroker().PopInteractiveDataToGame();
if (storage == nullptr) {
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
@@ -656,7 +655,7 @@ private:
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(broker->GetNormalDataEvent());
rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
LOG_DEBUG(Service_AM, "called");
}
@@ -664,13 +663,12 @@ private:
void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(broker->GetInteractiveDataEvent());
rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<Applets::Applet> applet;
std::shared_ptr<Applets::AppletDataBroker> broker;
};
void IStorage::Open(Kernel::HLERequestContext& ctx) {

View File

@@ -98,10 +98,8 @@ Applet::Applet() = default;
Applet::~Applet() = default;
void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
broker = std::move(broker_);
const auto common = broker->PopNormalDataToApplet();
void Applet::Initialize() {
const auto common = broker.PopNormalDataToApplet();
ASSERT(common != nullptr);
const auto common_data = common->GetData();

View File

@@ -4,14 +4,17 @@
#pragma once
#include <functional>
#include <memory>
#include <queue>
#include "common/swap.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/kernel.h"
union ResultCode;
namespace Kernel {
class Event;
}
namespace Service::AM {
class IStorage;
@@ -43,19 +46,26 @@ public:
private:
// Queues are named from applet's perspective
std::queue<std::unique_ptr<IStorage>>
in_channel; // PopNormalDataToApplet and PushNormalDataFromGame
std::queue<std::unique_ptr<IStorage>>
out_channel; // PopNormalDataToGame and PushNormalDataFromApplet
std::queue<std::unique_ptr<IStorage>>
in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame
std::queue<std::unique_ptr<IStorage>>
out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet
// PopNormalDataToApplet and PushNormalDataFromGame
std::queue<std::unique_ptr<IStorage>> in_channel;
// PopNormalDataToGame and PushNormalDataFromApplet
std::queue<std::unique_ptr<IStorage>> out_channel;
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
Kernel::SharedPtr<Kernel::Event> state_changed_event;
Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet
Kernel::SharedPtr<Kernel::Event>
pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet
// Signaled on PushNormalDataFromApplet
Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
// Signaled on PushInteractiveDataFromApplet
Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
};
class Applet {
@@ -63,7 +73,7 @@ public:
Applet();
virtual ~Applet();
virtual void Initialize(std::shared_ptr<AppletDataBroker> broker);
virtual void Initialize();
virtual bool TransactionComplete() const = 0;
virtual ResultCode GetStatus() const = 0;
@@ -74,6 +84,14 @@ public:
return initialized;
}
AppletDataBroker& GetBroker() {
return broker;
}
const AppletDataBroker& GetBroker() const {
return broker;
}
protected:
struct CommonArguments {
u32_le arguments_version;
@@ -85,8 +103,8 @@ protected:
};
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
CommonArguments common_args;
std::shared_ptr<AppletDataBroker> broker;
CommonArguments common_args{};
AppletDataBroker broker;
bool initialized = false;
};

View File

@@ -42,21 +42,21 @@ SoftwareKeyboard::SoftwareKeyboard() = default;
SoftwareKeyboard::~SoftwareKeyboard() = default;
void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
void SoftwareKeyboard::Initialize() {
complete = false;
initial_text.clear();
final_data.clear();
Applet::Initialize(std::move(broker_));
Applet::Initialize();
const auto keyboard_config_storage = broker->PopNormalDataToApplet();
const auto keyboard_config_storage = broker.PopNormalDataToApplet();
ASSERT(keyboard_config_storage != nullptr);
const auto& keyboard_config = keyboard_config_storage->GetData();
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
const auto work_buffer_storage = broker->PopNormalDataToApplet();
const auto work_buffer_storage = broker.PopNormalDataToApplet();
ASSERT(work_buffer_storage != nullptr);
const auto& work_buffer = work_buffer_storage->GetData();
@@ -81,7 +81,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
if (complete)
return;
const auto storage = broker->PopInteractiveDataToApplet();
const auto storage = broker.PopInteractiveDataToApplet();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
const auto status = static_cast<bool>(data[0]);
@@ -95,13 +95,13 @@ void SoftwareKeyboard::ExecuteInteractive() {
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
frontend.SendTextCheckDialog(
Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
[this] { broker->SignalStateChanged(); });
[this] { broker.SignalStateChanged(); });
}
}
void SoftwareKeyboard::Execute() {
if (complete) {
broker->PushNormalDataFromApplet(IStorage{final_data});
broker.PushNormalDataFromApplet(IStorage{final_data});
return;
}
@@ -145,17 +145,17 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
final_data = output_main;
if (complete) {
broker->PushNormalDataFromApplet(IStorage{output_main});
broker.PushNormalDataFromApplet(IStorage{output_main});
} else {
broker->PushInteractiveDataFromApplet(IStorage{output_sub});
broker.PushInteractiveDataFromApplet(IStorage{output_sub});
}
broker->SignalStateChanged();
broker.SignalStateChanged();
} else {
output_main[0] = 1;
complete = true;
broker->PushNormalDataFromApplet(IStorage{output_main});
broker->SignalStateChanged();
broker.PushNormalDataFromApplet(IStorage{output_main});
broker.SignalStateChanged();
}
}
} // namespace Service::AM::Applets

View File

@@ -4,7 +4,12 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "common/common_funcs.h"
#include "common/swap.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
@@ -50,7 +55,7 @@ public:
SoftwareKeyboard();
~SoftwareKeyboard() override;
void Initialize(std::shared_ptr<AppletDataBroker> broker) override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;

View File

@@ -44,8 +44,10 @@ enum class AudioState : u32 {
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
: ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
std::string&& unique_name)
: ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params),
device_name(std::move(device_name)) {
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -69,7 +71,7 @@ public:
Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
"IAudioOut", [=]() { buffer_event->Signal(); });
std::move(unique_name), [=]() { buffer_event->Signal(); });
}
private:
@@ -177,6 +179,7 @@ private:
AudioCore::AudioOut& audio_core;
AudioCore::StreamPtr stream;
std::string device_name;
AudoutParams audio_params{};
@@ -199,7 +202,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
ctx.WriteBuffer(DefaultDevice);
const auto device_name_data{ctx.ReadBuffer()};
std::string device_name;
if (device_name_data[0] != '\0') {
device_name.assign(device_name_data.begin(), device_name_data.end());
} else {
device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
}
ctx.WriteBuffer(device_name);
IPC::RequestParser rp{ctx};
auto params{rp.PopRaw<AudoutParams>()};
if (params.channel_count <= 2) {
@@ -212,10 +223,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
params.sample_rate = DefaultSampleRate;
}
// TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
// will likely need to be updated as well.
ASSERT_MSG(!audio_out_interface, "Unimplemented");
audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
auto audio_out_interface = std::make_shared<IAudioOut>(
params, *audio_core, std::move(device_name), std::move(unique_name));
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -224,6 +234,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
audio_out_interfaces.push_back(std::move(audio_out_interface));
}
AudOutU::AudOutU() : ServiceFramework("audout:u") {

View File

@@ -4,6 +4,7 @@
#pragma once
#include <vector>
#include "core/hle/service/service.h"
namespace AudioCore {
@@ -24,7 +25,7 @@ public:
~AudOutU() override;
private:
std::shared_ptr<IAudioOut> audio_out_interface;
std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
std::unique_ptr<AudioCore::AudioOut> audio_core;
void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);

View File

@@ -71,8 +71,9 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
void Controller_DebugPad::OnLoadInputDevices() {
std::transform(Settings::values.debug_pad_buttons.begin(),
Settings::values.debug_pad_buttons.end(), buttons.begin(),
Input::CreateDevice<Input::ButtonDevice>);
Settings::values.debug_pad_buttons.begin() +
Settings::NativeButton::NUM_BUTTONS_HID,
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
std::transform(Settings::values.debug_pad_analogs.begin(),
Settings::values.debug_pad_analogs.end(), analogs.begin(),
Input::CreateDevice<Input::AnalogDevice>);

View File

@@ -389,6 +389,13 @@ public:
ReverseSubtract = 3,
Min = 4,
Max = 5,
// These values are used by Nouveau and some games.
AddGL = 0x8006,
SubtractGL = 0x8007,
ReverseSubtractGL = 0x8008,
MinGL = 0x800a,
MaxGL = 0x800b
};
enum class Factor : u32 {
@@ -583,10 +590,18 @@ public:
float clear_color[4];
float clear_depth;
INSERT_PADDING_WORDS(0x3);
s32 clear_stencil;
INSERT_PADDING_WORDS(0x17);
INSERT_PADDING_WORDS(0x7);
u32 polygon_offset_point_enable;
u32 polygon_offset_line_enable;
u32 polygon_offset_fill_enable;
INSERT_PADDING_WORDS(0xD);
std::array<ScissorTest, NumViewports> scissor_test;
@@ -745,7 +760,11 @@ public:
}
} tsc;
INSERT_PADDING_WORDS(0x3);
INSERT_PADDING_WORDS(0x1);
float polygon_offset_factor;
INSERT_PADDING_WORDS(0x1);
struct {
u32 tic_address_high;
@@ -770,7 +789,9 @@ public:
u32 framebuffer_srgb;
INSERT_PADDING_WORDS(0x12);
float polygon_offset_units;
INSERT_PADDING_WORDS(0x11);
union {
BitField<2, 1, u32> coord_origin;
@@ -847,7 +868,9 @@ public:
INSERT_PADDING_WORDS(0x7);
INSERT_PADDING_WORDS(0x20);
INSERT_PADDING_WORDS(0x1F);
float polygon_offset_clamp;
struct {
u32 is_instanced[NumVertexArrays];
@@ -1120,6 +1143,9 @@ ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(clear_color[0], 0x360);
ASSERT_REG_POSITION(clear_depth, 0x364);
ASSERT_REG_POSITION(clear_stencil, 0x368);
ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
ASSERT_REG_POSITION(scissor_test, 0x380);
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
@@ -1157,6 +1183,7 @@ ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(multisample_control, 0x54F);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(polygon_offset_factor, 0x55b);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
@@ -1164,11 +1191,13 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
ASSERT_REG_POSITION(framebuffer_srgb, 0x56E);
ASSERT_REG_POSITION(polygon_offset_units, 0x56F);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(primitive_restart, 0x591);
ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(logic_op, 0x671);

View File

@@ -17,6 +17,8 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) {
switch (format) {
case PixelFormat::ABGR8:
return 4;
default:
return 4;
}
UNREACHABLE();

View File

@@ -35,6 +35,7 @@ void MacroInterpreter::Reset() {
// The next parameter index starts at 1, because $r1 already has the value of the first
// parameter.
next_parameter_index = 1;
carry_flag = false;
}
bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
@@ -135,14 +136,28 @@ MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
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) {
switch (operation) {
case ALUOperation::Add:
return src_a + src_b;
// TODO(Subv): Implement AddWithCarry
case ALUOperation::Subtract:
return src_a - src_b;
// TODO(Subv): Implement SubtractWithBorrow
case ALUOperation::Add: {
const u64 result{static_cast<u64>(src_a) + src_b};
carry_flag = result > 0xffffffff;
return static_cast<u32>(result);
}
case ALUOperation::AddWithCarry: {
const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)};
carry_flag = result > 0xffffffff;
return static_cast<u32>(result);
}
case ALUOperation::Subtract: {
const u64 result{static_cast<u64>(src_a) - src_b};
carry_flag = result < 0x100000000;
return static_cast<u32>(result);
}
case ALUOperation::SubtractWithBorrow: {
const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)};
carry_flag = result < 0x100000000;
return static_cast<u32>(result);
}
case ALUOperation::Xor:
return src_a ^ src_b;
case ALUOperation::Or:

View File

@@ -117,7 +117,7 @@ private:
bool Step(u32 offset, bool is_delay_slot);
/// 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);
/// Performs the result operation on the input result and stores it in the specified register
/// (if necessary).
@@ -165,5 +165,7 @@ private:
std::vector<u32> parameters;
/// Index of the next parameter that will be fetched by the 'parm' instruction.
u32 next_parameter_index = 0;
bool carry_flag{};
};
} // namespace Tegra

View File

@@ -593,7 +593,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncTransformFeedback();
SyncPointState();
CheckAlphaTests();
SyncPolygonOffset();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -1152,6 +1152,16 @@ void RasterizerOpenGL::SyncPointState() {
state.point.size = regs.point_size;
}
void RasterizerOpenGL::SyncPolygonOffset() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
state.polygon_offset.units = regs.polygon_offset_units;
state.polygon_offset.factor = regs.polygon_offset_factor;
state.polygon_offset.clamp = regs.polygon_offset_clamp;
}
void RasterizerOpenGL::CheckAlphaTests() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;

View File

@@ -182,6 +182,9 @@ private:
/// Syncs Color Mask
void SyncColorMask();
/// Syncs the polygon offsets
void SyncPolygonOffset();
/// Check asserts for alpha testing.
void CheckAlphaTests();

View File

@@ -1275,6 +1275,31 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) {
return surface;
}
void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface,
const Surface& dst_surface) {
const auto& init_params{src_surface->GetSurfaceParams()};
const auto& dst_params{dst_surface->GetSurfaceParams()};
VAddr address = init_params.addr;
const std::size_t layer_size = dst_params.LayerMemorySize();
for (u32 layer = 0; layer < dst_params.depth; layer++) {
for (u32 mipmap = 0; mipmap < dst_params.max_mip_level; mipmap++) {
const VAddr sub_address = address + dst_params.GetMipmapLevelOffset(mipmap);
const Surface& copy = TryGet(sub_address);
if (!copy)
continue;
const auto& src_params{copy->GetSurfaceParams()};
const u32 width{std::min(src_params.width, dst_params.MipWidth(mipmap))};
const u32 height{std::min(src_params.height, dst_params.MipHeight(mipmap))};
glCopyImageSubData(copy->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0,
0, 0, dst_surface->Texture().handle,
SurfaceTargetToGL(dst_params.target), mipmap, 0, 0, layer, width,
height, 1);
}
address += layer_size;
}
}
void RasterizerCacheOpenGL::FermiCopySurface(
const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) {
@@ -1340,11 +1365,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
CopySurface(old_surface, new_surface, copy_pbo.handle);
}
break;
case SurfaceTarget::TextureCubemap:
case SurfaceTarget::Texture3D:
AccurateCopySurface(old_surface, new_surface);
break;
case SurfaceTarget::TextureCubemap:
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
AccurateCopySurface(old_surface, new_surface);
FastLayeredCopySurface(old_surface, new_surface);
break;
default:
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",

View File

@@ -350,6 +350,7 @@ private:
/// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
/// previously been used. This is to prevent surfaces from being constantly created and

File diff suppressed because it is too large Load Diff

View File

@@ -92,6 +92,13 @@ OpenGLState::OpenGLState() {
point.size = 1;
fragment_color_clamp.enabled = false;
polygon_offset.fill_enable = false;
polygon_offset.line_enable = false;
polygon_offset.point_enable = false;
polygon_offset.factor = 0.0f;
polygon_offset.units = 0.0f;
polygon_offset.clamp = 0.0f;
}
void OpenGLState::ApplyDefaultState() {
@@ -383,6 +390,55 @@ void OpenGLState::ApplyLogicOp() const {
}
}
void OpenGLState::ApplyPolygonOffset() const {
const bool fill_enable_changed =
polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
const bool line_enable_changed =
polygon_offset.line_enable != cur_state.polygon_offset.line_enable;
const bool point_enable_changed =
polygon_offset.point_enable != cur_state.polygon_offset.point_enable;
const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor;
const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units;
const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp;
if (fill_enable_changed) {
if (polygon_offset.fill_enable) {
glEnable(GL_POLYGON_OFFSET_FILL);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
}
}
if (line_enable_changed) {
if (polygon_offset.line_enable) {
glEnable(GL_POLYGON_OFFSET_LINE);
} else {
glDisable(GL_POLYGON_OFFSET_LINE);
}
}
if (point_enable_changed) {
if (polygon_offset.point_enable) {
glEnable(GL_POLYGON_OFFSET_POINT);
} else {
glDisable(GL_POLYGON_OFFSET_POINT);
}
}
if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) &&
(factor_changed || units_changed || clamp_changed)) {
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
} else {
glPolygonOffset(polygon_offset.factor, polygon_offset.units);
UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
"Unimplemented Depth polygon offset clamp.");
}
}
}
void OpenGLState::ApplyTextures() const {
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
const auto& texture_unit = texture_units[i];
@@ -509,6 +565,7 @@ void OpenGLState::Apply() const {
ApplyLogicOp();
ApplyTextures();
ApplySamplers();
ApplyPolygonOffset();
cur_state = *this;
}

View File

@@ -176,6 +176,15 @@ public:
float size; // GL_POINT_SIZE
} point;
struct {
bool point_enable;
bool line_enable;
bool fill_enable;
GLfloat units;
GLfloat factor;
GLfloat clamp;
} polygon_offset;
std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
OpenGLState();
@@ -225,6 +234,7 @@ private:
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
void ApplyPolygonOffset() const;
};
} // namespace OpenGL

View File

@@ -218,14 +218,19 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
switch (equation) {
case Maxwell::Blend::Equation::Add:
case Maxwell::Blend::Equation::AddGL:
return GL_FUNC_ADD;
case Maxwell::Blend::Equation::Subtract:
case Maxwell::Blend::Equation::SubtractGL:
return GL_FUNC_SUBTRACT;
case Maxwell::Blend::Equation::ReverseSubtract:
case Maxwell::Blend::Equation::ReverseSubtractGL:
return GL_FUNC_REVERSE_SUBTRACT;
case Maxwell::Blend::Equation::Min:
case Maxwell::Blend::Equation::MinGL:
return GL_MIN;
case Maxwell::Blend::Equation::Max:
case Maxwell::Blend::Equation::MaxGL:
return GL_MAX;
}
LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));

View File

@@ -304,6 +304,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
gl_framebuffer_data.resize(texture.width * texture.height * 4);
break;
default:
internal_format = GL_RGBA;
texture.gl_format = GL_RGBA;
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
gl_framebuffer_data.resize(texture.width * texture.height * 4);
LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer pixel format: {}",
static_cast<u32>(framebuffer.pixel_format));
UNREACHABLE();
}