Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95c98f963d | ||
|
|
0e91b7102a | ||
|
|
c73854dee0 | ||
|
|
e391516315 | ||
|
|
95ff9dda45 | ||
|
|
24acfb1ee7 | ||
|
|
887c2395da | ||
|
|
02b185cc4a | ||
|
|
831bb4fbb1 | ||
|
|
56346f927e | ||
|
|
5f36b35666 | ||
|
|
2b7dfc9413 | ||
|
|
207dd1b0a8 | ||
|
|
d7e3f79a19 | ||
|
|
13eb8874e0 |
No files matched your search
+4
-4
@@ -26,11 +26,11 @@
|
||||
path = externals/mbedtls
|
||||
url = https://github.com/DarkLordZach/mbedtls
|
||||
[submodule "opus"]
|
||||
path = externals/opus/opus
|
||||
url = https://github.com/xiph/opus.git
|
||||
path = externals/opus
|
||||
url = https://github.com/ogniK5377/opus.git
|
||||
[submodule "soundtouch"]
|
||||
path = externals/soundtouch
|
||||
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||
path = externals/soundtouch
|
||||
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||
[submodule "libressl"]
|
||||
path = externals/libressl
|
||||
url = https://github.com/citra-emu/ext-libressl-portable.git
|
||||
|
||||
+1
Submodule externals/opus added at 562f8ba555.
Vendored
-250
@@ -1,250 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(opus)
|
||||
|
||||
option(OPUS_STACK_PROTECTOR "Use stack protection" OFF)
|
||||
option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF)
|
||||
option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" OFF)
|
||||
option(OPUS_FIXED_POINT "Compile as fixed-point (for machines without a fast enough FPU)" OFF)
|
||||
option(OPUS_ENABLE_FLOAT_API "Compile with the floating point API (for machines with float library" ON)
|
||||
|
||||
include(opus/opus_functions.cmake)
|
||||
|
||||
if(OPUS_STACK_PROTECTOR)
|
||||
if(NOT MSVC) # GC on by default on MSVC
|
||||
check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong)
|
||||
endif()
|
||||
else()
|
||||
if(MSVC)
|
||||
check_and_set_flag(BUFFER_SECURITY_CHECK /GS-)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(opus STATIC
|
||||
# CELT sources
|
||||
opus/celt/bands.c
|
||||
opus/celt/celt.c
|
||||
opus/celt/celt_decoder.c
|
||||
opus/celt/celt_encoder.c
|
||||
opus/celt/celt_lpc.c
|
||||
opus/celt/cwrs.c
|
||||
opus/celt/entcode.c
|
||||
opus/celt/entdec.c
|
||||
opus/celt/entenc.c
|
||||
opus/celt/kiss_fft.c
|
||||
opus/celt/laplace.c
|
||||
opus/celt/mathops.c
|
||||
opus/celt/mdct.c
|
||||
opus/celt/modes.c
|
||||
opus/celt/pitch.c
|
||||
opus/celt/quant_bands.c
|
||||
opus/celt/rate.c
|
||||
opus/celt/vq.c
|
||||
|
||||
# SILK sources
|
||||
opus/silk/A2NLSF.c
|
||||
opus/silk/CNG.c
|
||||
opus/silk/HP_variable_cutoff.c
|
||||
opus/silk/LPC_analysis_filter.c
|
||||
opus/silk/LPC_fit.c
|
||||
opus/silk/LPC_inv_pred_gain.c
|
||||
opus/silk/LP_variable_cutoff.c
|
||||
opus/silk/NLSF2A.c
|
||||
opus/silk/NLSF_VQ.c
|
||||
opus/silk/NLSF_VQ_weights_laroia.c
|
||||
opus/silk/NLSF_decode.c
|
||||
opus/silk/NLSF_del_dec_quant.c
|
||||
opus/silk/NLSF_encode.c
|
||||
opus/silk/NLSF_stabilize.c
|
||||
opus/silk/NLSF_unpack.c
|
||||
opus/silk/NSQ.c
|
||||
opus/silk/NSQ_del_dec.c
|
||||
opus/silk/PLC.c
|
||||
opus/silk/VAD.c
|
||||
opus/silk/VQ_WMat_EC.c
|
||||
opus/silk/ana_filt_bank_1.c
|
||||
opus/silk/biquad_alt.c
|
||||
opus/silk/bwexpander.c
|
||||
opus/silk/bwexpander_32.c
|
||||
opus/silk/check_control_input.c
|
||||
opus/silk/code_signs.c
|
||||
opus/silk/control_SNR.c
|
||||
opus/silk/control_audio_bandwidth.c
|
||||
opus/silk/control_codec.c
|
||||
opus/silk/dec_API.c
|
||||
opus/silk/decode_core.c
|
||||
opus/silk/decode_frame.c
|
||||
opus/silk/decode_indices.c
|
||||
opus/silk/decode_parameters.c
|
||||
opus/silk/decode_pitch.c
|
||||
opus/silk/decode_pulses.c
|
||||
opus/silk/decoder_set_fs.c
|
||||
opus/silk/enc_API.c
|
||||
opus/silk/encode_indices.c
|
||||
opus/silk/encode_pulses.c
|
||||
opus/silk/gain_quant.c
|
||||
opus/silk/init_decoder.c
|
||||
opus/silk/init_encoder.c
|
||||
opus/silk/inner_prod_aligned.c
|
||||
opus/silk/interpolate.c
|
||||
opus/silk/lin2log.c
|
||||
opus/silk/log2lin.c
|
||||
opus/silk/pitch_est_tables.c
|
||||
opus/silk/process_NLSFs.c
|
||||
opus/silk/quant_LTP_gains.c
|
||||
opus/silk/resampler.c
|
||||
opus/silk/resampler_down2.c
|
||||
opus/silk/resampler_down2_3.c
|
||||
opus/silk/resampler_private_AR2.c
|
||||
opus/silk/resampler_private_IIR_FIR.c
|
||||
opus/silk/resampler_private_down_FIR.c
|
||||
opus/silk/resampler_private_up2_HQ.c
|
||||
opus/silk/resampler_rom.c
|
||||
opus/silk/shell_coder.c
|
||||
opus/silk/sigm_Q15.c
|
||||
opus/silk/sort.c
|
||||
opus/silk/stereo_LR_to_MS.c
|
||||
opus/silk/stereo_MS_to_LR.c
|
||||
opus/silk/stereo_decode_pred.c
|
||||
opus/silk/stereo_encode_pred.c
|
||||
opus/silk/stereo_find_predictor.c
|
||||
opus/silk/stereo_quant_pred.c
|
||||
opus/silk/sum_sqr_shift.c
|
||||
opus/silk/table_LSF_cos.c
|
||||
opus/silk/tables_LTP.c
|
||||
opus/silk/tables_NLSF_CB_NB_MB.c
|
||||
opus/silk/tables_NLSF_CB_WB.c
|
||||
opus/silk/tables_gain.c
|
||||
opus/silk/tables_other.c
|
||||
opus/silk/tables_pitch_lag.c
|
||||
opus/silk/tables_pulses_per_block.c
|
||||
|
||||
# Opus sources
|
||||
opus/src/analysis.c
|
||||
opus/src/mapping_matrix.c
|
||||
opus/src/mlp.c
|
||||
opus/src/mlp_data.c
|
||||
opus/src/opus.c
|
||||
opus/src/opus_decoder.c
|
||||
opus/src/opus_encoder.c
|
||||
opus/src/opus_multistream.c
|
||||
opus/src/opus_multistream_decoder.c
|
||||
opus/src/opus_multistream_encoder.c
|
||||
opus/src/opus_projection_decoder.c
|
||||
opus/src/opus_projection_encoder.c
|
||||
opus/src/repacketizer.c
|
||||
)
|
||||
|
||||
if (DEBUG)
|
||||
target_sources(opus PRIVATE opus/silk/debug.c)
|
||||
endif()
|
||||
|
||||
if (OPUS_FIXED_POINT)
|
||||
target_sources(opus PRIVATE
|
||||
opus/silk/fixed/LTP_analysis_filter_FIX.c
|
||||
opus/silk/fixed/LTP_scale_ctrl_FIX.c
|
||||
opus/silk/fixed/apply_sine_window_FIX.c
|
||||
opus/silk/fixed/autocorr_FIX.c
|
||||
opus/silk/fixed/burg_modified_FIX.c
|
||||
opus/silk/fixed/corrMatrix_FIX.c
|
||||
opus/silk/fixed/encode_frame_FIX.c
|
||||
opus/silk/fixed/find_LPC_FIX.c
|
||||
opus/silk/fixed/find_LTP_FIX.c
|
||||
opus/silk/fixed/find_pitch_lags_FIX.c
|
||||
opus/silk/fixed/find_pred_coefs_FIX.c
|
||||
opus/silk/fixed/k2a_FIX.c
|
||||
opus/silk/fixed/k2a_Q16_FIX.c
|
||||
opus/silk/fixed/noise_shape_analysis_FIX.c
|
||||
opus/silk/fixed/pitch_analysis_core_FIX.c
|
||||
opus/silk/fixed/prefilter_FIX.c
|
||||
opus/silk/fixed/process_gains_FIX.c
|
||||
opus/silk/fixed/regularize_correlations_FIX.c
|
||||
opus/silk/fixed/residual_energy16_FIX.c
|
||||
opus/silk/fixed/residual_energy_FIX.c
|
||||
opus/silk/fixed/schur64_FIX.c
|
||||
opus/silk/fixed/schur_FIX.c
|
||||
opus/silk/fixed/solve_LS_FIX.c
|
||||
opus/silk/fixed/vector_ops_FIX.c
|
||||
opus/silk/fixed/warped_autocorrelation_FIX.c
|
||||
)
|
||||
else()
|
||||
target_sources(opus PRIVATE
|
||||
opus/silk/float/LPC_analysis_filter_FLP.c
|
||||
opus/silk/float/LPC_inv_pred_gain_FLP.c
|
||||
opus/silk/float/LTP_analysis_filter_FLP.c
|
||||
opus/silk/float/LTP_scale_ctrl_FLP.c
|
||||
opus/silk/float/apply_sine_window_FLP.c
|
||||
opus/silk/float/autocorrelation_FLP.c
|
||||
opus/silk/float/burg_modified_FLP.c
|
||||
opus/silk/float/bwexpander_FLP.c
|
||||
opus/silk/float/corrMatrix_FLP.c
|
||||
opus/silk/float/encode_frame_FLP.c
|
||||
opus/silk/float/energy_FLP.c
|
||||
opus/silk/float/find_LPC_FLP.c
|
||||
opus/silk/float/find_LTP_FLP.c
|
||||
opus/silk/float/find_pitch_lags_FLP.c
|
||||
opus/silk/float/find_pred_coefs_FLP.c
|
||||
opus/silk/float/inner_product_FLP.c
|
||||
opus/silk/float/k2a_FLP.c
|
||||
opus/silk/float/noise_shape_analysis_FLP.c
|
||||
opus/silk/float/pitch_analysis_core_FLP.c
|
||||
opus/silk/float/process_gains_FLP.c
|
||||
opus/silk/float/regularize_correlations_FLP.c
|
||||
opus/silk/float/residual_energy_FLP.c
|
||||
opus/silk/float/scale_copy_vector_FLP.c
|
||||
opus/silk/float/scale_vector_FLP.c
|
||||
opus/silk/float/schur_FLP.c
|
||||
opus/silk/float/sort_FLP.c
|
||||
opus/silk/float/warped_autocorrelation_FLP.c
|
||||
opus/silk/float/wrappers_FLP.c
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
|
||||
# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99
|
||||
# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack
|
||||
# allocation If none is defined, then the fallback is a non-threadsafe global
|
||||
# array
|
||||
if(OPUS_USE_ALLOCA OR MSVC)
|
||||
target_compile_definitions(opus PRIVATE USE_ALLOCA)
|
||||
else()
|
||||
target_compile_definitions(opus PRIVATE VAR_ARRAYS)
|
||||
endif()
|
||||
|
||||
if(OPUS_CUSTOM_MODES)
|
||||
target_compile_definitions(opus PRIVATE CUSTOM_MODES)
|
||||
endif()
|
||||
|
||||
if(NOT OPUS_ENABLE_FLOAT_API)
|
||||
target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(opus
|
||||
PUBLIC
|
||||
-DOPUS_VERSION="\\"1.3.1\\""
|
||||
|
||||
PRIVATE
|
||||
# Use C99 intrinsics to speed up float-to-int conversion
|
||||
HAVE_LRINTF
|
||||
)
|
||||
|
||||
if (FIXED_POINT)
|
||||
target_compile_definitions(opus PRIVATE -DFIXED_POINT=1 -DDISABLE_FLOAT_API)
|
||||
endif()
|
||||
|
||||
target_include_directories(opus
|
||||
PUBLIC
|
||||
opus/include
|
||||
|
||||
PRIVATE
|
||||
opus/celt
|
||||
opus/silk
|
||||
opus/silk/fixed
|
||||
opus/silk/float
|
||||
opus/src
|
||||
)
|
||||
Vendored
-1
Submodule externals/opus/opus deleted from ad8fe90db7.
@@ -22,9 +22,9 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {}
|
||||
|
||||
GlobalScheduler::~GlobalScheduler() = default;
|
||||
GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {
|
||||
is_reselection_pending = false;
|
||||
}
|
||||
|
||||
void GlobalScheduler::AddThread(SharedPtr<Thread> thread) {
|
||||
thread_list.push_back(std::move(thread));
|
||||
@@ -35,11 +35,24 @@ void GlobalScheduler::RemoveThread(const Thread* thread) {
|
||||
thread_list.end());
|
||||
}
|
||||
|
||||
/*
|
||||
* UnloadThread selects a core and forces it to unload its current thread's context
|
||||
*/
|
||||
void GlobalScheduler::UnloadThread(s32 core) {
|
||||
Scheduler& sched = system.Scheduler(core);
|
||||
sched.UnloadThread();
|
||||
}
|
||||
|
||||
/*
|
||||
* SelectThread takes care of selecting the new scheduled thread.
|
||||
* It does it in 3 steps:
|
||||
* - First a thread is selected from the top of the priority queue. If no thread
|
||||
* is obtained then we move to step two, else we are done.
|
||||
* - Second we try to get a suggested thread that's not assigned to any core or
|
||||
* that is not the top thread in that core.
|
||||
* - Third is no suggested thread is found, we do a second pass and pick a running
|
||||
* thread in another core and swap it with its current thread.
|
||||
*/
|
||||
void GlobalScheduler::SelectThread(u32 core) {
|
||||
const auto update_thread = [](Thread* thread, Scheduler& sched) {
|
||||
if (thread != sched.selected_thread) {
|
||||
@@ -101,19 +114,30 @@ void GlobalScheduler::SelectThread(u32 core) {
|
||||
update_thread(current_thread, sched);
|
||||
}
|
||||
|
||||
/*
|
||||
* YieldThread takes a thread and moves it to the back of the it's priority list
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool GlobalScheduler::YieldThread(Thread* yielding_thread) {
|
||||
// Note: caller should use critical section, etc.
|
||||
const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID());
|
||||
const u32 priority = yielding_thread->GetPriority();
|
||||
|
||||
// Yield the thread
|
||||
const Thread* const winner = scheduled_queue[core_id].front(priority);
|
||||
ASSERT_MSG(yielding_thread == winner, "Thread yielding without being in front");
|
||||
ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority),
|
||||
"Thread yielding without being in front");
|
||||
scheduled_queue[core_id].yield(priority);
|
||||
|
||||
Thread* winner = scheduled_queue[core_id].front(priority);
|
||||
return AskForReselectionOrMarkRedundant(yielding_thread, winner);
|
||||
}
|
||||
|
||||
/*
|
||||
* YieldThreadAndBalanceLoad takes a thread and moves it to the back of the it's priority list.
|
||||
* Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or
|
||||
* a better priority than the next thread in the core.
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
|
||||
// Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section,
|
||||
// etc.
|
||||
@@ -165,6 +189,12 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
|
||||
return AskForReselectionOrMarkRedundant(yielding_thread, winner);
|
||||
}
|
||||
|
||||
/*
|
||||
* YieldThreadAndWaitForLoadBalancing takes a thread and moves it out of the scheduling queue
|
||||
* and into the suggested queue. If no thread can be squeduled afterwards in that core,
|
||||
* a suggested thread is obtained instead.
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) {
|
||||
// Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section,
|
||||
// etc.
|
||||
@@ -250,7 +280,7 @@ void GlobalScheduler::PreemptThreads() {
|
||||
if (winner->IsRunning()) {
|
||||
UnloadThread(winner->GetProcessorID());
|
||||
}
|
||||
TransferToCore(winner->GetPriority(), s32(core_id), winner);
|
||||
TransferToCore(winner->GetPriority(), core_id, winner);
|
||||
current_thread =
|
||||
winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread;
|
||||
}
|
||||
@@ -283,7 +313,7 @@ void GlobalScheduler::PreemptThreads() {
|
||||
if (winner->IsRunning()) {
|
||||
UnloadThread(winner->GetProcessorID());
|
||||
}
|
||||
TransferToCore(winner->GetPriority(), s32(core_id), winner);
|
||||
TransferToCore(winner->GetPriority(), core_id, winner);
|
||||
current_thread = winner;
|
||||
}
|
||||
}
|
||||
@@ -301,12 +331,12 @@ void GlobalScheduler::Unsuggest(u32 priority, u32 core, Thread* thread) {
|
||||
}
|
||||
|
||||
void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) {
|
||||
ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core.");
|
||||
ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core.");
|
||||
scheduled_queue[core].add(thread, priority);
|
||||
}
|
||||
|
||||
void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) {
|
||||
ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core.");
|
||||
ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core.");
|
||||
scheduled_queue[core].add(thread, priority, false);
|
||||
}
|
||||
|
||||
@@ -338,8 +368,7 @@ void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread*
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread,
|
||||
const Thread* winner) {
|
||||
bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) {
|
||||
if (current_thread == winner) {
|
||||
current_thread->IncrementYieldCount();
|
||||
return true;
|
||||
@@ -357,6 +386,8 @@ void GlobalScheduler::Shutdown() {
|
||||
thread_list.clear();
|
||||
}
|
||||
|
||||
GlobalScheduler::~GlobalScheduler() = default;
|
||||
|
||||
Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id)
|
||||
: system(system), cpu_core(cpu_core), core_id(core_id) {}
|
||||
|
||||
@@ -439,7 +470,7 @@ void Scheduler::SwitchContext() {
|
||||
|
||||
// Load context of new thread
|
||||
if (new_thread) {
|
||||
ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id),
|
||||
ASSERT_MSG(new_thread->GetProcessorID() == this->core_id,
|
||||
"Thread must be assigned to this core.");
|
||||
ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready,
|
||||
"Thread must be ready to become running.");
|
||||
|
||||
@@ -26,7 +26,6 @@ public:
|
||||
|
||||
explicit GlobalScheduler(Core::System& system);
|
||||
~GlobalScheduler();
|
||||
|
||||
/// Adds a new thread to the scheduler
|
||||
void AddThread(SharedPtr<Thread> thread);
|
||||
|
||||
@@ -38,57 +37,47 @@ public:
|
||||
return thread_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a thread to the suggested queue of a cpu core. Suggested threads may be
|
||||
* picked if no thread is scheduled to run on the core.
|
||||
*/
|
||||
// Add a thread to the suggested queue of a cpu core. Suggested threads may be
|
||||
// picked if no thread is scheduled to run on the core.
|
||||
void Suggest(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/**
|
||||
* Remove a thread to the suggested queue of a cpu core. Suggested threads may be
|
||||
* picked if no thread is scheduled to run on the core.
|
||||
*/
|
||||
// Remove a thread to the suggested queue of a cpu core. Suggested threads may be
|
||||
// picked if no thread is scheduled to run on the core.
|
||||
void Unsuggest(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/**
|
||||
* Add a thread to the scheduling queue of a cpu core. The thread is added at the
|
||||
* back the queue in its priority level.
|
||||
*/
|
||||
// Add a thread to the scheduling queue of a cpu core. The thread is added at the
|
||||
// back the queue in its priority level
|
||||
void Schedule(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/**
|
||||
* Add a thread to the scheduling queue of a cpu core. The thread is added at the
|
||||
* front the queue in its priority level.
|
||||
*/
|
||||
// Add a thread to the scheduling queue of a cpu core. The thread is added at the
|
||||
// front the queue in its priority level
|
||||
void SchedulePrepend(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/// Reschedule an already scheduled thread based on a new priority
|
||||
// Reschedule an already scheduled thread based on a new priority
|
||||
void Reschedule(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/// Unschedules a thread.
|
||||
// Unschedule a thread.
|
||||
void Unschedule(u32 priority, u32 core, Thread* thread);
|
||||
|
||||
/**
|
||||
* Transfers a thread into an specific core. If the destination_core is -1
|
||||
* it will be unscheduled from its source code and added into its suggested
|
||||
* queue.
|
||||
*/
|
||||
// Transfers a thread into an specific core. If the destination_core is -1
|
||||
// it will be unscheduled from its source code and added into its suggested
|
||||
// queue.
|
||||
void TransferToCore(u32 priority, s32 destination_core, Thread* thread);
|
||||
|
||||
/// Selects a core and forces it to unload its current thread's context
|
||||
/*
|
||||
* UnloadThread selects a core and forces it to unload its current thread's context
|
||||
*/
|
||||
void UnloadThread(s32 core);
|
||||
|
||||
/**
|
||||
* Takes care of selecting the new scheduled thread in three steps:
|
||||
*
|
||||
* 1. First a thread is selected from the top of the priority queue. If no thread
|
||||
* is obtained then we move to step two, else we are done.
|
||||
*
|
||||
* 2. Second we try to get a suggested thread that's not assigned to any core or
|
||||
* that is not the top thread in that core.
|
||||
*
|
||||
* 3. Third is no suggested thread is found, we do a second pass and pick a running
|
||||
* thread in another core and swap it with its current thread.
|
||||
/*
|
||||
* SelectThread takes care of selecting the new scheduled thread.
|
||||
* It does it in 3 steps:
|
||||
* - First a thread is selected from the top of the priority queue. If no thread
|
||||
* is obtained then we move to step two, else we are done.
|
||||
* - Second we try to get a suggested thread that's not assigned to any core or
|
||||
* that is not the top thread in that core.
|
||||
* - Third is no suggested thread is found, we do a second pass and pick a running
|
||||
* thread in another core and swap it with its current thread.
|
||||
*/
|
||||
void SelectThread(u32 core);
|
||||
|
||||
@@ -96,37 +85,33 @@ public:
|
||||
return !scheduled_queue[core_id].empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a thread and moves it to the back of the it's priority list.
|
||||
*
|
||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||
/*
|
||||
* YieldThread takes a thread and moves it to the back of the it's priority list
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool YieldThread(Thread* thread);
|
||||
|
||||
/**
|
||||
* Takes a thread and moves it to the back of the it's priority list.
|
||||
/*
|
||||
* YieldThreadAndBalanceLoad takes a thread and moves it to the back of the it's priority list.
|
||||
* Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or
|
||||
* a better priority than the next thread in the core.
|
||||
*
|
||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool YieldThreadAndBalanceLoad(Thread* thread);
|
||||
|
||||
/**
|
||||
* Takes a thread and moves it out of the scheduling queue.
|
||||
* and into the suggested queue. If no thread can be scheduled afterwards in that core,
|
||||
/*
|
||||
* YieldThreadAndWaitForLoadBalancing takes a thread and moves it out of the scheduling queue
|
||||
* and into the suggested queue. If no thread can be squeduled afterwards in that core,
|
||||
* a suggested thread is obtained instead.
|
||||
*
|
||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||
* This operation can be redundant and no scheduling is changed if marked as so.
|
||||
*/
|
||||
bool YieldThreadAndWaitForLoadBalancing(Thread* thread);
|
||||
|
||||
/**
|
||||
* Rotates the scheduling queues of threads at a preemption priority and then does
|
||||
* some core rebalancing. Preemption priorities can be found in the array
|
||||
* 'preemption_priorities'.
|
||||
*
|
||||
* @note This operation happens every 10ms.
|
||||
/*
|
||||
* PreemptThreads this operation rotates the scheduling queues of threads at
|
||||
* a preemption priority and then does some core rebalancing. Preemption priorities
|
||||
* can be found in the array 'preemption_priorities'. This operation happens
|
||||
* every 10ms.
|
||||
*/
|
||||
void PreemptThreads();
|
||||
|
||||
@@ -145,15 +130,15 @@ public:
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
|
||||
bool AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner);
|
||||
|
||||
static constexpr u32 min_regular_priority = 2;
|
||||
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue;
|
||||
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue;
|
||||
std::atomic<bool> is_reselection_pending{false};
|
||||
std::atomic<bool> is_reselection_pending;
|
||||
|
||||
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
|
||||
// ordered from Core 0 to Core 3.
|
||||
// `preemption_priorities` are the priority levels at which the global scheduler
|
||||
// preempts threads every 10 ms. They are ordered from Core 0 to Core 3
|
||||
std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
|
||||
|
||||
/// Lists all thread ids that aren't deleted/etc.
|
||||
@@ -196,8 +181,10 @@ public:
|
||||
|
||||
private:
|
||||
friend class GlobalScheduler;
|
||||
|
||||
/// Switches the CPU's active thread context to that of the specified thread
|
||||
/**
|
||||
* Switches the CPU's active thread context to that of the specified thread
|
||||
* @param new_thread The thread to switch to
|
||||
*/
|
||||
void SwitchContext();
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,8 +36,6 @@ add_library(video_core STATIC
|
||||
memory_manager.h
|
||||
morton.cpp
|
||||
morton.h
|
||||
rasterizer_accelerated.cpp
|
||||
rasterizer_accelerated.h
|
||||
rasterizer_cache.cpp
|
||||
rasterizer_cache.h
|
||||
rasterizer_interface.h
|
||||
|
||||
@@ -35,7 +35,7 @@ struct SamplerDescriptor {
|
||||
}
|
||||
|
||||
bool operator!=(const SamplerDescriptor& rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
return raw != rhs.raw;
|
||||
}
|
||||
|
||||
static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) {
|
||||
@@ -77,12 +77,13 @@ struct SamplerDescriptor {
|
||||
result.is_buffer.Assign(0);
|
||||
result.is_shadow.Assign(0);
|
||||
return result;
|
||||
case Tegra::Texture::TextureType::Texture1DBuffer:
|
||||
case Tegra::Texture::TextureType::Texture1DBuffer: {
|
||||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D);
|
||||
result.is_array.Assign(0);
|
||||
result.is_buffer.Assign(1);
|
||||
result.is_shadow.Assign(0);
|
||||
return result;
|
||||
}
|
||||
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
||||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D);
|
||||
result.is_array.Assign(0);
|
||||
|
||||
@@ -50,7 +50,7 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
|
||||
}
|
||||
}
|
||||
|
||||
Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
|
||||
Tegra::Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
|
||||
const std::bitset<8> cbuf_mask = launch_description.const_buffer_enable_mask.Value();
|
||||
ASSERT(cbuf_mask[regs.tex_cb_index]);
|
||||
|
||||
@@ -61,11 +61,13 @@ Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
|
||||
ASSERT(address < texinfo.Address() + texinfo.size);
|
||||
|
||||
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(address)};
|
||||
return GetTextureInfo(tex_handle);
|
||||
return GetTextureInfo(tex_handle, offset);
|
||||
}
|
||||
|
||||
Texture::FullTextureInfo KeplerCompute::GetTextureInfo(Texture::TextureHandle tex_handle) const {
|
||||
return Texture::FullTextureInfo{GetTICEntry(tex_handle.tic_id), GetTSCEntry(tex_handle.tsc_id)};
|
||||
Texture::FullTextureInfo KeplerCompute::GetTextureInfo(const Texture::TextureHandle tex_handle,
|
||||
std::size_t offset) const {
|
||||
return Texture::FullTextureInfo{static_cast<u32>(offset), GetTICEntry(tex_handle.tic_id),
|
||||
GetTSCEntry(tex_handle.tsc_id)};
|
||||
}
|
||||
|
||||
u32 KeplerCompute::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const {
|
||||
@@ -87,7 +89,7 @@ SamplerDescriptor KeplerCompute::AccessBindlessSampler(ShaderType stage, u64 con
|
||||
const GPUVAddr tex_info_address = tex_info_buffer.Address() + offset;
|
||||
|
||||
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(tex_info_address)};
|
||||
const Texture::FullTextureInfo tex_info = GetTextureInfo(tex_handle);
|
||||
const Texture::FullTextureInfo tex_info = GetTextureInfo(tex_handle, offset);
|
||||
SamplerDescriptor result = SamplerDescriptor::FromTicTexture(tex_info.tic.texture_type.Value());
|
||||
result.is_shadow.Assign(tex_info.tsc.depth_compare_enabled.Value());
|
||||
return result;
|
||||
|
||||
@@ -196,10 +196,11 @@ public:
|
||||
/// Write the value to the register identified by method.
|
||||
void CallMethod(const GPU::MethodCall& method_call);
|
||||
|
||||
Texture::FullTextureInfo GetTexture(std::size_t offset) const;
|
||||
Tegra::Texture::FullTextureInfo GetTexture(std::size_t offset) const;
|
||||
|
||||
/// Given a texture handle, returns the TSC and TIC entries.
|
||||
Texture::FullTextureInfo GetTextureInfo(Texture::TextureHandle tex_handle) const;
|
||||
/// Given a Texture Handle, returns the TSC and TIC entries.
|
||||
Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
|
||||
std::size_t offset) const;
|
||||
|
||||
u32 AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const override;
|
||||
|
||||
|
||||
@@ -98,10 +98,11 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
|
||||
}
|
||||
|
||||
#define DIRTY_REGS_POS(field_name) static_cast<u8>(offsetof(Maxwell3D::DirtyRegs, field_name))
|
||||
#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
|
||||
|
||||
void Maxwell3D::InitDirtySettings() {
|
||||
const auto set_block = [this](std::size_t start, std::size_t range, u8 position) {
|
||||
const auto set_block = [this](const std::size_t start, const std::size_t range,
|
||||
const u8 position) {
|
||||
const auto start_itr = dirty_pointers.begin() + start;
|
||||
const auto end_itr = start_itr + range;
|
||||
std::fill(start_itr, end_itr, position);
|
||||
@@ -112,10 +113,10 @@ void Maxwell3D::InitDirtySettings() {
|
||||
constexpr u32 registers_per_rt = sizeof(regs.rt[0]) / sizeof(u32);
|
||||
constexpr u32 rt_start_reg = MAXWELL3D_REG_INDEX(rt);
|
||||
constexpr u32 rt_end_reg = rt_start_reg + registers_per_rt * 8;
|
||||
u8 rt_dirty_reg = DIRTY_REGS_POS(render_target);
|
||||
u32 rt_dirty_reg = DIRTY_REGS_POS(render_target);
|
||||
for (u32 rt_reg = rt_start_reg; rt_reg < rt_end_reg; rt_reg += registers_per_rt) {
|
||||
set_block(rt_reg, registers_per_rt, rt_dirty_reg);
|
||||
++rt_dirty_reg;
|
||||
rt_dirty_reg++;
|
||||
}
|
||||
constexpr u32 depth_buffer_flag = DIRTY_REGS_POS(depth_buffer);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(zeta_enable)] = depth_buffer_flag;
|
||||
@@ -129,35 +130,35 @@ void Maxwell3D::InitDirtySettings() {
|
||||
constexpr u32 vertex_array_start = MAXWELL3D_REG_INDEX(vertex_array);
|
||||
constexpr u32 vertex_array_size = sizeof(regs.vertex_array[0]) / sizeof(u32);
|
||||
constexpr u32 vertex_array_end = vertex_array_start + vertex_array_size * Regs::NumVertexArrays;
|
||||
u8 va_dirty_reg = DIRTY_REGS_POS(vertex_array);
|
||||
u8 vi_dirty_reg = DIRTY_REGS_POS(vertex_instance);
|
||||
u32 va_reg = DIRTY_REGS_POS(vertex_array);
|
||||
u32 vi_reg = DIRTY_REGS_POS(vertex_instance);
|
||||
for (u32 vertex_reg = vertex_array_start; vertex_reg < vertex_array_end;
|
||||
vertex_reg += vertex_array_size) {
|
||||
set_block(vertex_reg, 3, va_dirty_reg);
|
||||
set_block(vertex_reg, 3, va_reg);
|
||||
// The divisor concerns vertex array instances
|
||||
dirty_pointers[static_cast<std::size_t>(vertex_reg) + 3] = vi_dirty_reg;
|
||||
++va_dirty_reg;
|
||||
++vi_dirty_reg;
|
||||
dirty_pointers[vertex_reg + 3] = vi_reg;
|
||||
va_reg++;
|
||||
vi_reg++;
|
||||
}
|
||||
constexpr u32 vertex_limit_start = MAXWELL3D_REG_INDEX(vertex_array_limit);
|
||||
constexpr u32 vertex_limit_size = sizeof(regs.vertex_array_limit[0]) / sizeof(u32);
|
||||
constexpr u32 vertex_limit_end = vertex_limit_start + vertex_limit_size * Regs::NumVertexArrays;
|
||||
va_dirty_reg = DIRTY_REGS_POS(vertex_array);
|
||||
va_reg = DIRTY_REGS_POS(vertex_array);
|
||||
for (u32 vertex_reg = vertex_limit_start; vertex_reg < vertex_limit_end;
|
||||
vertex_reg += vertex_limit_size) {
|
||||
set_block(vertex_reg, vertex_limit_size, va_dirty_reg);
|
||||
va_dirty_reg++;
|
||||
set_block(vertex_reg, vertex_limit_size, va_reg);
|
||||
va_reg++;
|
||||
}
|
||||
constexpr u32 vertex_instance_start = MAXWELL3D_REG_INDEX(instanced_arrays);
|
||||
constexpr u32 vertex_instance_size =
|
||||
sizeof(regs.instanced_arrays.is_instanced[0]) / sizeof(u32);
|
||||
constexpr u32 vertex_instance_end =
|
||||
vertex_instance_start + vertex_instance_size * Regs::NumVertexArrays;
|
||||
vi_dirty_reg = DIRTY_REGS_POS(vertex_instance);
|
||||
vi_reg = DIRTY_REGS_POS(vertex_instance);
|
||||
for (u32 vertex_reg = vertex_instance_start; vertex_reg < vertex_instance_end;
|
||||
vertex_reg += vertex_instance_size) {
|
||||
set_block(vertex_reg, vertex_instance_size, vi_dirty_reg);
|
||||
vi_dirty_reg++;
|
||||
set_block(vertex_reg, vertex_instance_size, vi_reg);
|
||||
vi_reg++;
|
||||
}
|
||||
set_block(MAXWELL3D_REG_INDEX(vertex_attrib_format), regs.vertex_attrib_format.size(),
|
||||
DIRTY_REGS_POS(vertex_attrib_format));
|
||||
@@ -171,7 +172,7 @@ void Maxwell3D::InitDirtySettings() {
|
||||
// State
|
||||
|
||||
// Viewport
|
||||
constexpr u8 viewport_dirty_reg = DIRTY_REGS_POS(viewport);
|
||||
constexpr u32 viewport_dirty_reg = DIRTY_REGS_POS(viewport);
|
||||
constexpr u32 viewport_start = MAXWELL3D_REG_INDEX(viewports);
|
||||
constexpr u32 viewport_size = sizeof(regs.viewports) / sizeof(u32);
|
||||
set_block(viewport_start, viewport_size, viewport_dirty_reg);
|
||||
@@ -198,7 +199,7 @@ void Maxwell3D::InitDirtySettings() {
|
||||
set_block(primitive_restart_start, primitive_restart_size, DIRTY_REGS_POS(primitive_restart));
|
||||
|
||||
// Depth Test
|
||||
constexpr u8 depth_test_dirty_reg = DIRTY_REGS_POS(depth_test);
|
||||
constexpr u32 depth_test_dirty_reg = DIRTY_REGS_POS(depth_test);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_enable)] = depth_test_dirty_reg;
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(depth_write_enabled)] = depth_test_dirty_reg;
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_func)] = depth_test_dirty_reg;
|
||||
@@ -223,12 +224,12 @@ void Maxwell3D::InitDirtySettings() {
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_mask)] = stencil_test_dirty_reg;
|
||||
|
||||
// Color Mask
|
||||
constexpr u8 color_mask_dirty_reg = DIRTY_REGS_POS(color_mask);
|
||||
constexpr u32 color_mask_dirty_reg = DIRTY_REGS_POS(color_mask);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(color_mask_common)] = color_mask_dirty_reg;
|
||||
set_block(MAXWELL3D_REG_INDEX(color_mask), sizeof(regs.color_mask) / sizeof(u32),
|
||||
color_mask_dirty_reg);
|
||||
// Blend State
|
||||
constexpr u8 blend_state_dirty_reg = DIRTY_REGS_POS(blend_state);
|
||||
constexpr u32 blend_state_dirty_reg = DIRTY_REGS_POS(blend_state);
|
||||
set_block(MAXWELL3D_REG_INDEX(blend_color), sizeof(regs.blend_color) / sizeof(u32),
|
||||
blend_state_dirty_reg);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(independent_blend_enable)] = blend_state_dirty_reg;
|
||||
@@ -237,12 +238,12 @@ void Maxwell3D::InitDirtySettings() {
|
||||
blend_state_dirty_reg);
|
||||
|
||||
// Scissor State
|
||||
constexpr u8 scissor_test_dirty_reg = DIRTY_REGS_POS(scissor_test);
|
||||
constexpr u32 scissor_test_dirty_reg = DIRTY_REGS_POS(scissor_test);
|
||||
set_block(MAXWELL3D_REG_INDEX(scissor_test), sizeof(regs.scissor_test) / sizeof(u32),
|
||||
scissor_test_dirty_reg);
|
||||
|
||||
// Polygon Offset
|
||||
constexpr u8 polygon_offset_dirty_reg = DIRTY_REGS_POS(polygon_offset);
|
||||
constexpr u32 polygon_offset_dirty_reg = DIRTY_REGS_POS(polygon_offset);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_fill_enable)] = polygon_offset_dirty_reg;
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_line_enable)] = polygon_offset_dirty_reg;
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_point_enable)] = polygon_offset_dirty_reg;
|
||||
@@ -251,7 +252,7 @@ void Maxwell3D::InitDirtySettings() {
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg;
|
||||
|
||||
// Depth bounds
|
||||
constexpr u8 depth_bounds_values_dirty_reg = DIRTY_REGS_POS(depth_bounds_values);
|
||||
constexpr u32 depth_bounds_values_dirty_reg = DIRTY_REGS_POS(depth_bounds_values);
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(depth_bounds[0])] = depth_bounds_values_dirty_reg;
|
||||
dirty_pointers[MAXWELL3D_REG_INDEX(depth_bounds[1])] = depth_bounds_values_dirty_reg;
|
||||
}
|
||||
@@ -760,8 +761,61 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const {
|
||||
return tsc_entry;
|
||||
}
|
||||
|
||||
Texture::FullTextureInfo Maxwell3D::GetTextureInfo(Texture::TextureHandle tex_handle) const {
|
||||
return Texture::FullTextureInfo{GetTICEntry(tex_handle.tic_id), GetTSCEntry(tex_handle.tsc_id)};
|
||||
std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderStage stage) const {
|
||||
std::vector<Texture::FullTextureInfo> textures;
|
||||
|
||||
auto& fragment_shader = state.shader_stages[static_cast<std::size_t>(stage)];
|
||||
auto& tex_info_buffer = fragment_shader.const_buffers[regs.tex_cb_index];
|
||||
ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0);
|
||||
|
||||
GPUVAddr tex_info_buffer_end = tex_info_buffer.address + tex_info_buffer.size;
|
||||
|
||||
// Offset into the texture constbuffer where the texture info begins.
|
||||
static constexpr std::size_t TextureInfoOffset = 0x20;
|
||||
|
||||
for (GPUVAddr current_texture = tex_info_buffer.address + TextureInfoOffset;
|
||||
current_texture < tex_info_buffer_end; current_texture += sizeof(Texture::TextureHandle)) {
|
||||
|
||||
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(current_texture)};
|
||||
|
||||
Texture::FullTextureInfo tex_info{};
|
||||
// TODO(Subv): Use the shader to determine which textures are actually accessed.
|
||||
tex_info.index =
|
||||
static_cast<u32>(current_texture - tex_info_buffer.address - TextureInfoOffset) /
|
||||
sizeof(Texture::TextureHandle);
|
||||
|
||||
// Load the TIC data.
|
||||
auto tic_entry = GetTICEntry(tex_handle.tic_id);
|
||||
// TODO(Subv): Workaround for BitField's move constructor being deleted.
|
||||
std::memcpy(&tex_info.tic, &tic_entry, sizeof(tic_entry));
|
||||
|
||||
// Load the TSC data
|
||||
auto tsc_entry = GetTSCEntry(tex_handle.tsc_id);
|
||||
// TODO(Subv): Workaround for BitField's move constructor being deleted.
|
||||
std::memcpy(&tex_info.tsc, &tsc_entry, sizeof(tsc_entry));
|
||||
|
||||
textures.push_back(tex_info);
|
||||
}
|
||||
|
||||
return textures;
|
||||
}
|
||||
|
||||
Texture::FullTextureInfo Maxwell3D::GetTextureInfo(const Texture::TextureHandle tex_handle,
|
||||
std::size_t offset) const {
|
||||
Texture::FullTextureInfo tex_info{};
|
||||
tex_info.index = static_cast<u32>(offset);
|
||||
|
||||
// Load the TIC data.
|
||||
auto tic_entry = GetTICEntry(tex_handle.tic_id);
|
||||
// TODO(Subv): Workaround for BitField's move constructor being deleted.
|
||||
std::memcpy(&tex_info.tic, &tic_entry, sizeof(tic_entry));
|
||||
|
||||
// Load the TSC data
|
||||
auto tsc_entry = GetTSCEntry(tex_handle.tsc_id);
|
||||
// TODO(Subv): Workaround for BitField's move constructor being deleted.
|
||||
std::memcpy(&tex_info.tsc, &tsc_entry, sizeof(tsc_entry));
|
||||
|
||||
return tex_info;
|
||||
}
|
||||
|
||||
Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
|
||||
@@ -777,7 +831,7 @@ Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
|
||||
|
||||
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(tex_info_address)};
|
||||
|
||||
return GetTextureInfo(tex_handle);
|
||||
return GetTextureInfo(tex_handle, offset);
|
||||
}
|
||||
|
||||
u32 Maxwell3D::GetRegisterValue(u32 method) const {
|
||||
@@ -814,7 +868,7 @@ SamplerDescriptor Maxwell3D::AccessBindlessSampler(ShaderType stage, u64 const_b
|
||||
const GPUVAddr tex_info_address = tex_info_buffer.address + offset;
|
||||
|
||||
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(tex_info_address)};
|
||||
const Texture::FullTextureInfo tex_info = GetTextureInfo(tex_handle);
|
||||
const Texture::FullTextureInfo tex_info = GetTextureInfo(tex_handle, offset);
|
||||
SamplerDescriptor result = SamplerDescriptor::FromTicTexture(tex_info.tic.texture_type.Value());
|
||||
result.is_shadow.Assign(tex_info.tsc.depth_compare_enabled.Value());
|
||||
return result;
|
||||
|
||||
@@ -1166,8 +1166,6 @@ public:
|
||||
|
||||
struct DirtyRegs {
|
||||
static constexpr std::size_t NUM_REGS = 256;
|
||||
static_assert(NUM_REGS - 1 <= std::numeric_limits<u8>::max());
|
||||
|
||||
union {
|
||||
struct {
|
||||
bool null_dirty;
|
||||
@@ -1250,8 +1248,12 @@ public:
|
||||
|
||||
void FlushMMEInlineDraw();
|
||||
|
||||
/// Given a texture handle, returns the TSC and TIC entries.
|
||||
Texture::FullTextureInfo GetTextureInfo(Texture::TextureHandle tex_handle) const;
|
||||
/// Given a Texture Handle, returns the TSC and TIC entries.
|
||||
Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
|
||||
std::size_t offset) const;
|
||||
|
||||
/// Returns a list of enabled textures for the specified shader stage.
|
||||
std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const;
|
||||
|
||||
/// Returns the texture information for a specific texture in a specific shader stage.
|
||||
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
|
||||
|
||||
@@ -112,7 +112,6 @@ static constexpr ConversionArray morton_to_linear_fns = {
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_8X6_SRGB>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_6X5>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_6X5_SRGB>,
|
||||
MortonCopy<true, PixelFormat::E5B9G9R9F>,
|
||||
MortonCopy<true, PixelFormat::Z32F>,
|
||||
MortonCopy<true, PixelFormat::Z16>,
|
||||
MortonCopy<true, PixelFormat::Z24S8>,
|
||||
@@ -193,7 +192,6 @@ static constexpr ConversionArray linear_to_morton_fns = {
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
MortonCopy<false, PixelFormat::E5B9G9R9F>,
|
||||
MortonCopy<false, PixelFormat::Z32F>,
|
||||
MortonCopy<false, PixelFormat::Z16>,
|
||||
MortonCopy<false, PixelFormat::Z24S8>,
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Map, typename Interval>
|
||||
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
RasterizerAccelerated::RasterizerAccelerated() = default;
|
||||
|
||||
RasterizerAccelerated::~RasterizerAccelerated() = default;
|
||||
|
||||
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||
std::lock_guard lock{pages_mutex};
|
||||
const u64 page_start{addr >> Memory::PAGE_BITS};
|
||||
const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS};
|
||||
|
||||
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
|
||||
// subtract after iterating
|
||||
const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end);
|
||||
if (delta > 0) {
|
||||
cached_pages.add({pages_interval, delta});
|
||||
}
|
||||
|
||||
for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
|
||||
const auto interval = pair.first & pages_interval;
|
||||
const int count = pair.second;
|
||||
|
||||
const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS;
|
||||
const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS;
|
||||
const u64 interval_size = interval_end_addr - interval_start_addr;
|
||||
|
||||
if (delta > 0 && count == delta) {
|
||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
|
||||
} else if (delta < 0 && count == -delta) {
|
||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
|
||||
} else {
|
||||
ASSERT(count >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (delta < 0) {
|
||||
cached_pages.add({pages_interval, delta});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VideoCore
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface.
|
||||
class RasterizerAccelerated : public RasterizerInterface {
|
||||
public:
|
||||
explicit RasterizerAccelerated();
|
||||
~RasterizerAccelerated() override;
|
||||
|
||||
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
|
||||
|
||||
private:
|
||||
using CachedPageMap = boost::icl::interval_map<u64, int>;
|
||||
CachedPageMap cached_pages;
|
||||
|
||||
std::mutex pages_mutex;
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
@@ -68,6 +68,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
|
||||
ScreenInfo& info)
|
||||
: texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device},
|
||||
system{system}, screen_info{info}, buffer_cache{*this, system, STREAM_BUFFER_SIZE} {
|
||||
OpenGLState::ApplyDefaultState();
|
||||
|
||||
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
|
||||
state.draw.shader_program = 0;
|
||||
state.Apply();
|
||||
@@ -340,6 +342,42 @@ std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const {
|
||||
static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
|
||||
}
|
||||
|
||||
template <typename Map, typename Interval>
|
||||
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||
std::lock_guard lock{pages_mutex};
|
||||
const u64 page_start{addr >> Memory::PAGE_BITS};
|
||||
const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS};
|
||||
|
||||
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
|
||||
// subtract after iterating
|
||||
const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end);
|
||||
if (delta > 0)
|
||||
cached_pages.add({pages_interval, delta});
|
||||
|
||||
for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
|
||||
const auto interval = pair.first & pages_interval;
|
||||
const int count = pair.second;
|
||||
|
||||
const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS;
|
||||
const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS;
|
||||
const u64 interval_size = interval_end_addr - interval_start_addr;
|
||||
|
||||
if (delta > 0 && count == delta)
|
||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
|
||||
else if (delta < 0 && count == -delta)
|
||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
|
||||
else
|
||||
ASSERT(count >= 0);
|
||||
}
|
||||
|
||||
if (delta < 0)
|
||||
cached_pages.add({pages_interval, delta});
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
shader_cache.LoadDiskCache(stop_loading, callback);
|
||||
@@ -931,7 +969,7 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& entry = entries[bindpoint];
|
||||
const auto texture = [&] {
|
||||
const auto texture = [&]() {
|
||||
if (!entry.IsBindless()) {
|
||||
return maxwell3d.GetStageTexture(stage, entry.GetOffset());
|
||||
}
|
||||
@@ -939,7 +977,7 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
|
||||
Tegra::Texture::TextureHandle tex_handle;
|
||||
Tegra::Engines::ShaderType shader_type = static_cast<Tegra::Engines::ShaderType>(stage);
|
||||
tex_handle.raw = maxwell3d.AccessConstBuffer32(shader_type, cbuf.first, cbuf.second);
|
||||
return maxwell3d.GetTextureInfo(tex_handle);
|
||||
return maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
|
||||
}();
|
||||
|
||||
if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) {
|
||||
@@ -962,7 +1000,7 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& entry = entries[bindpoint];
|
||||
const auto texture = [&] {
|
||||
const auto texture = [&]() {
|
||||
if (!entry.IsBindless()) {
|
||||
return compute.GetTexture(entry.GetOffset());
|
||||
}
|
||||
@@ -970,7 +1008,7 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
|
||||
Tegra::Texture::TextureHandle tex_handle;
|
||||
tex_handle.raw = compute.AccessConstBuffer32(Tegra::Engines::ShaderType::Compute,
|
||||
cbuf.first, cbuf.second);
|
||||
return compute.GetTextureInfo(tex_handle);
|
||||
return compute.GetTextureInfo(tex_handle, entry.GetOffset());
|
||||
}();
|
||||
|
||||
if (SetupTexture(bindpoint, texture, entry)) {
|
||||
@@ -1008,7 +1046,7 @@ void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
|
||||
const auto& entries = shader->GetShaderEntries().images;
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& entry = entries[bindpoint];
|
||||
const auto tic = [&] {
|
||||
const auto tic = [&]() {
|
||||
if (!entry.IsBindless()) {
|
||||
return compute.GetTexture(entry.GetOffset()).tic;
|
||||
}
|
||||
@@ -1016,7 +1054,7 @@ void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
|
||||
Tegra::Texture::TextureHandle tex_handle;
|
||||
tex_handle.raw = compute.AccessConstBuffer32(Tegra::Engines::ShaderType::Compute,
|
||||
cbuf.first, cbuf.second);
|
||||
return compute.GetTextureInfo(tex_handle).tic;
|
||||
return compute.GetTextureInfo(tex_handle, entry.GetOffset()).tic;
|
||||
}();
|
||||
SetupImage(bindpoint, tic, entry);
|
||||
}
|
||||
|
||||
@@ -9,16 +9,17 @@
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/engines/const_buffer_info.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/rasterizer_accelerated.h"
|
||||
#include "video_core/rasterizer_cache.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
@@ -51,7 +52,7 @@ namespace OpenGL {
|
||||
struct ScreenInfo;
|
||||
struct DrawParameters;
|
||||
|
||||
class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
|
||||
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
|
||||
public:
|
||||
explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
|
||||
ScreenInfo& info);
|
||||
@@ -72,6 +73,7 @@ public:
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) override;
|
||||
bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
|
||||
u32 pixel_stride) override;
|
||||
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
|
||||
void LoadDiskResources(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) override;
|
||||
|
||||
@@ -226,6 +228,11 @@ private:
|
||||
AccelDraw accelerate_draw = AccelDraw::Disabled;
|
||||
|
||||
OGLFramebuffer clear_framebuffer;
|
||||
|
||||
using CachedPageMap = boost::icl::interval_map<u64, int>;
|
||||
CachedPageMap cached_pages;
|
||||
|
||||
std::mutex pages_mutex;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <glad/glad.h>
|
||||
#include "common/assert.h"
|
||||
@@ -70,29 +69,147 @@ void Enable(GLenum cap, GLuint index, bool enable) {
|
||||
}
|
||||
|
||||
void Enable(GLenum cap, bool& current_value, bool new_value) {
|
||||
if (UpdateValue(current_value, new_value)) {
|
||||
if (UpdateValue(current_value, new_value))
|
||||
Enable(cap, new_value);
|
||||
}
|
||||
}
|
||||
|
||||
void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) {
|
||||
if (UpdateValue(current_value, new_value)) {
|
||||
if (UpdateValue(current_value, new_value))
|
||||
Enable(cap, index, new_value);
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
} // namespace
|
||||
|
||||
OpenGLState::OpenGLState() = default;
|
||||
OpenGLState::OpenGLState() {
|
||||
// These all match default OpenGL values
|
||||
framebuffer_srgb.enabled = false;
|
||||
|
||||
multisample_control.alpha_to_coverage = false;
|
||||
multisample_control.alpha_to_one = false;
|
||||
|
||||
cull.enabled = false;
|
||||
cull.mode = GL_BACK;
|
||||
cull.front_face = GL_CCW;
|
||||
|
||||
depth.test_enabled = false;
|
||||
depth.test_func = GL_LESS;
|
||||
depth.write_mask = GL_TRUE;
|
||||
|
||||
primitive_restart.enabled = false;
|
||||
primitive_restart.index = 0;
|
||||
|
||||
for (auto& item : color_mask) {
|
||||
item.red_enabled = GL_TRUE;
|
||||
item.green_enabled = GL_TRUE;
|
||||
item.blue_enabled = GL_TRUE;
|
||||
item.alpha_enabled = GL_TRUE;
|
||||
}
|
||||
|
||||
const auto ResetStencil = [](auto& config) {
|
||||
config.test_func = GL_ALWAYS;
|
||||
config.test_ref = 0;
|
||||
config.test_mask = 0xFFFFFFFF;
|
||||
config.write_mask = 0xFFFFFFFF;
|
||||
config.action_depth_fail = GL_KEEP;
|
||||
config.action_depth_pass = GL_KEEP;
|
||||
config.action_stencil_fail = GL_KEEP;
|
||||
};
|
||||
stencil.test_enabled = false;
|
||||
ResetStencil(stencil.front);
|
||||
ResetStencil(stencil.back);
|
||||
|
||||
for (auto& item : viewports) {
|
||||
item.x = 0;
|
||||
item.y = 0;
|
||||
item.width = 0;
|
||||
item.height = 0;
|
||||
item.depth_range_near = 0.0f;
|
||||
item.depth_range_far = 1.0f;
|
||||
item.scissor.enabled = false;
|
||||
item.scissor.x = 0;
|
||||
item.scissor.y = 0;
|
||||
item.scissor.width = 0;
|
||||
item.scissor.height = 0;
|
||||
}
|
||||
|
||||
for (auto& item : blend) {
|
||||
item.enabled = true;
|
||||
item.rgb_equation = GL_FUNC_ADD;
|
||||
item.a_equation = GL_FUNC_ADD;
|
||||
item.src_rgb_func = GL_ONE;
|
||||
item.dst_rgb_func = GL_ZERO;
|
||||
item.src_a_func = GL_ONE;
|
||||
item.dst_a_func = GL_ZERO;
|
||||
}
|
||||
|
||||
independant_blend.enabled = false;
|
||||
|
||||
blend_color.red = 0.0f;
|
||||
blend_color.green = 0.0f;
|
||||
blend_color.blue = 0.0f;
|
||||
blend_color.alpha = 0.0f;
|
||||
|
||||
logic_op.enabled = false;
|
||||
logic_op.operation = GL_COPY;
|
||||
|
||||
draw.read_framebuffer = 0;
|
||||
draw.draw_framebuffer = 0;
|
||||
draw.vertex_array = 0;
|
||||
draw.shader_program = 0;
|
||||
draw.program_pipeline = 0;
|
||||
|
||||
clip_distance = {};
|
||||
|
||||
point.size = 1;
|
||||
|
||||
fragment_color_clamp.enabled = false;
|
||||
|
||||
depth_clamp.far_plane = false;
|
||||
depth_clamp.near_plane = 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;
|
||||
|
||||
alpha_test.enabled = false;
|
||||
alpha_test.func = GL_ALWAYS;
|
||||
alpha_test.ref = 0.0f;
|
||||
}
|
||||
|
||||
void OpenGLState::SetDefaultViewports() {
|
||||
viewports.fill(Viewport{});
|
||||
for (auto& item : viewports) {
|
||||
item.x = 0;
|
||||
item.y = 0;
|
||||
item.width = 0;
|
||||
item.height = 0;
|
||||
item.depth_range_near = 0.0f;
|
||||
item.depth_range_far = 1.0f;
|
||||
item.scissor.enabled = false;
|
||||
item.scissor.x = 0;
|
||||
item.scissor.y = 0;
|
||||
item.scissor.width = 0;
|
||||
item.scissor.height = 0;
|
||||
}
|
||||
|
||||
depth_clamp.far_plane = false;
|
||||
depth_clamp.near_plane = false;
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyFramebufferState() {
|
||||
void OpenGLState::ApplyDefaultState() {
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyFramebufferState() const {
|
||||
if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
|
||||
}
|
||||
@@ -101,52 +218,52 @@ void OpenGLState::ApplyFramebufferState() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyVertexArrayState() {
|
||||
void OpenGLState::ApplyVertexArrayState() const {
|
||||
if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) {
|
||||
glBindVertexArray(draw.vertex_array);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyShaderProgram() {
|
||||
void OpenGLState::ApplyShaderProgram() const {
|
||||
if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) {
|
||||
glUseProgram(draw.shader_program);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyProgramPipeline() {
|
||||
void OpenGLState::ApplyProgramPipeline() const {
|
||||
if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) {
|
||||
glBindProgramPipeline(draw.program_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyClipDistances() {
|
||||
void OpenGLState::ApplyClipDistances() const {
|
||||
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
|
||||
Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i],
|
||||
clip_distance[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyPointSize() {
|
||||
void OpenGLState::ApplyPointSize() const {
|
||||
if (UpdateValue(cur_state.point.size, point.size)) {
|
||||
glPointSize(point.size);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyFragmentColorClamp() {
|
||||
void OpenGLState::ApplyFragmentColorClamp() const {
|
||||
if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) {
|
||||
glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
|
||||
fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyMultisample() {
|
||||
void OpenGLState::ApplyMultisample() const {
|
||||
Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage,
|
||||
multisample_control.alpha_to_coverage);
|
||||
Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one,
|
||||
multisample_control.alpha_to_one);
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyDepthClamp() {
|
||||
void OpenGLState::ApplyDepthClamp() const {
|
||||
if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
|
||||
depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
|
||||
return;
|
||||
@@ -159,7 +276,7 @@ void OpenGLState::ApplyDepthClamp() {
|
||||
Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane);
|
||||
}
|
||||
|
||||
void OpenGLState::ApplySRgb() {
|
||||
void OpenGLState::ApplySRgb() const {
|
||||
if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled)
|
||||
return;
|
||||
cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled;
|
||||
@@ -170,7 +287,7 @@ void OpenGLState::ApplySRgb() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyCulling() {
|
||||
void OpenGLState::ApplyCulling() const {
|
||||
Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled);
|
||||
|
||||
if (UpdateValue(cur_state.cull.mode, cull.mode)) {
|
||||
@@ -182,12 +299,7 @@ void OpenGLState::ApplyCulling() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyColorMask() {
|
||||
if (!dirty.color_mask) {
|
||||
return;
|
||||
}
|
||||
dirty.color_mask = false;
|
||||
|
||||
void OpenGLState::ApplyColorMask() const {
|
||||
for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
|
||||
const auto& updated = color_mask[i];
|
||||
auto& current = cur_state.color_mask[i];
|
||||
@@ -202,7 +314,7 @@ void OpenGLState::ApplyColorMask() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyDepth() {
|
||||
void OpenGLState::ApplyDepth() const {
|
||||
Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled);
|
||||
|
||||
if (cur_state.depth.test_func != depth.test_func) {
|
||||
@@ -216,7 +328,7 @@ void OpenGLState::ApplyDepth() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyPrimitiveRestart() {
|
||||
void OpenGLState::ApplyPrimitiveRestart() const {
|
||||
Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled);
|
||||
|
||||
if (cur_state.primitive_restart.index != primitive_restart.index) {
|
||||
@@ -225,12 +337,7 @@ void OpenGLState::ApplyPrimitiveRestart() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyStencilTest() {
|
||||
if (!dirty.stencil_state) {
|
||||
return;
|
||||
}
|
||||
dirty.stencil_state = false;
|
||||
|
||||
void OpenGLState::ApplyStencilTest() const {
|
||||
Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled);
|
||||
|
||||
const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) {
|
||||
@@ -259,7 +366,7 @@ void OpenGLState::ApplyStencilTest() {
|
||||
ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyViewport() {
|
||||
void OpenGLState::ApplyViewport() const {
|
||||
for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) {
|
||||
const auto& updated = viewports[i];
|
||||
auto& current = cur_state.viewports[i];
|
||||
@@ -296,7 +403,7 @@ void OpenGLState::ApplyViewport() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyGlobalBlending() {
|
||||
void OpenGLState::ApplyGlobalBlending() const {
|
||||
const Blend& updated = blend[0];
|
||||
Blend& current = cur_state.blend[0];
|
||||
|
||||
@@ -320,7 +427,7 @@ void OpenGLState::ApplyGlobalBlending() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) {
|
||||
void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
|
||||
const Blend& updated = blend[target];
|
||||
Blend& current = cur_state.blend[target];
|
||||
|
||||
@@ -344,12 +451,7 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyBlending() {
|
||||
if (!dirty.blend_state) {
|
||||
return;
|
||||
}
|
||||
dirty.blend_state = false;
|
||||
|
||||
void OpenGLState::ApplyBlending() const {
|
||||
if (independant_blend.enabled) {
|
||||
const bool force = independant_blend.enabled != cur_state.independant_blend.enabled;
|
||||
for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) {
|
||||
@@ -368,7 +470,7 @@ void OpenGLState::ApplyBlending() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyLogicOp() {
|
||||
void OpenGLState::ApplyLogicOp() const {
|
||||
Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled);
|
||||
|
||||
if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) {
|
||||
@@ -376,12 +478,7 @@ void OpenGLState::ApplyLogicOp() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyPolygonOffset() {
|
||||
if (!dirty.polygon_offset) {
|
||||
return;
|
||||
}
|
||||
dirty.polygon_offset = false;
|
||||
|
||||
void OpenGLState::ApplyPolygonOffset() const {
|
||||
Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable,
|
||||
polygon_offset.fill_enable);
|
||||
Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable,
|
||||
@@ -402,7 +499,7 @@ void OpenGLState::ApplyPolygonOffset() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyAlphaTest() {
|
||||
void OpenGLState::ApplyAlphaTest() const {
|
||||
Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled);
|
||||
if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref),
|
||||
std::tie(alpha_test.func, alpha_test.ref))) {
|
||||
@@ -410,19 +507,19 @@ void OpenGLState::ApplyAlphaTest() {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyTextures() {
|
||||
void OpenGLState::ApplyTextures() const {
|
||||
if (const auto update = UpdateArray(cur_state.textures, textures)) {
|
||||
glBindTextures(update->first, update->second, textures.data() + update->first);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplySamplers() {
|
||||
void OpenGLState::ApplySamplers() const {
|
||||
if (const auto update = UpdateArray(cur_state.samplers, samplers)) {
|
||||
glBindSamplers(update->first, update->second, samplers.data() + update->first);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyImages() {
|
||||
void OpenGLState::ApplyImages() const {
|
||||
if (const auto update = UpdateArray(cur_state.images, images)) {
|
||||
glBindImageTextures(update->first, update->second, images.data() + update->first);
|
||||
}
|
||||
@@ -438,20 +535,32 @@ void OpenGLState::Apply() {
|
||||
ApplyPointSize();
|
||||
ApplyFragmentColorClamp();
|
||||
ApplyMultisample();
|
||||
ApplyColorMask();
|
||||
if (dirty.color_mask) {
|
||||
ApplyColorMask();
|
||||
dirty.color_mask = false;
|
||||
}
|
||||
ApplyDepthClamp();
|
||||
ApplyViewport();
|
||||
ApplyStencilTest();
|
||||
if (dirty.stencil_state) {
|
||||
ApplyStencilTest();
|
||||
dirty.stencil_state = false;
|
||||
}
|
||||
ApplySRgb();
|
||||
ApplyCulling();
|
||||
ApplyDepth();
|
||||
ApplyPrimitiveRestart();
|
||||
ApplyBlending();
|
||||
if (dirty.blend_state) {
|
||||
ApplyBlending();
|
||||
dirty.blend_state = false;
|
||||
}
|
||||
ApplyLogicOp();
|
||||
ApplyTextures();
|
||||
ApplySamplers();
|
||||
ApplyImages();
|
||||
ApplyPolygonOffset();
|
||||
if (dirty.polygon_offset) {
|
||||
ApplyPolygonOffset();
|
||||
dirty.polygon_offset = false;
|
||||
}
|
||||
ApplyAlphaTest();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,146 +5,168 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <glad/glad.h>
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
namespace TextureUnits {
|
||||
|
||||
struct TextureUnit {
|
||||
GLint id;
|
||||
constexpr GLenum Enum() const {
|
||||
return static_cast<GLenum>(GL_TEXTURE0 + id);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr TextureUnit MaxwellTexture(int unit) {
|
||||
return TextureUnit{unit};
|
||||
}
|
||||
|
||||
constexpr TextureUnit LightingLUT{3};
|
||||
constexpr TextureUnit FogLUT{4};
|
||||
constexpr TextureUnit ProcTexNoiseLUT{5};
|
||||
constexpr TextureUnit ProcTexColorMap{6};
|
||||
constexpr TextureUnit ProcTexAlphaMap{7};
|
||||
constexpr TextureUnit ProcTexLUT{8};
|
||||
constexpr TextureUnit ProcTexDiffLUT{9};
|
||||
|
||||
} // namespace TextureUnits
|
||||
|
||||
class OpenGLState {
|
||||
public:
|
||||
struct {
|
||||
bool enabled = false; // GL_FRAMEBUFFER_SRGB
|
||||
bool enabled; // GL_FRAMEBUFFER_SRGB
|
||||
} framebuffer_srgb;
|
||||
|
||||
struct {
|
||||
bool alpha_to_coverage = false; // GL_ALPHA_TO_COVERAGE
|
||||
bool alpha_to_one = false; // GL_ALPHA_TO_ONE
|
||||
bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE
|
||||
bool alpha_to_one; // GL_ALPHA_TO_ONE
|
||||
} multisample_control;
|
||||
|
||||
struct {
|
||||
bool enabled = false; // GL_CLAMP_FRAGMENT_COLOR_ARB
|
||||
bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
|
||||
} fragment_color_clamp;
|
||||
|
||||
struct {
|
||||
bool far_plane = false;
|
||||
bool near_plane = false;
|
||||
bool far_plane;
|
||||
bool near_plane;
|
||||
} depth_clamp; // GL_DEPTH_CLAMP
|
||||
|
||||
struct {
|
||||
bool enabled = false; // GL_CULL_FACE
|
||||
GLenum mode = GL_BACK; // GL_CULL_FACE_MODE
|
||||
GLenum front_face = GL_CCW; // GL_FRONT_FACE
|
||||
bool enabled; // GL_CULL_FACE
|
||||
GLenum mode; // GL_CULL_FACE_MODE
|
||||
GLenum front_face; // GL_FRONT_FACE
|
||||
} cull;
|
||||
|
||||
struct {
|
||||
bool test_enabled = false; // GL_DEPTH_TEST
|
||||
GLboolean write_mask = GL_TRUE; // GL_DEPTH_WRITEMASK
|
||||
GLenum test_func = GL_LESS; // GL_DEPTH_FUNC
|
||||
bool test_enabled; // GL_DEPTH_TEST
|
||||
GLenum test_func; // GL_DEPTH_FUNC
|
||||
GLboolean write_mask; // GL_DEPTH_WRITEMASK
|
||||
} depth;
|
||||
|
||||
struct {
|
||||
bool enabled = false;
|
||||
GLuint index = 0;
|
||||
bool enabled;
|
||||
GLuint index;
|
||||
} primitive_restart; // GL_PRIMITIVE_RESTART
|
||||
|
||||
struct ColorMask {
|
||||
GLboolean red_enabled = GL_TRUE;
|
||||
GLboolean green_enabled = GL_TRUE;
|
||||
GLboolean blue_enabled = GL_TRUE;
|
||||
GLboolean alpha_enabled = GL_TRUE;
|
||||
GLboolean red_enabled;
|
||||
GLboolean green_enabled;
|
||||
GLboolean blue_enabled;
|
||||
GLboolean alpha_enabled;
|
||||
};
|
||||
std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
|
||||
color_mask; // GL_COLOR_WRITEMASK
|
||||
struct {
|
||||
bool test_enabled = false; // GL_STENCIL_TEST
|
||||
bool test_enabled; // GL_STENCIL_TEST
|
||||
struct {
|
||||
GLenum test_func = GL_ALWAYS; // GL_STENCIL_FUNC
|
||||
GLint test_ref = 0; // GL_STENCIL_REF
|
||||
GLuint test_mask = 0xFFFFFFFF; // GL_STENCIL_VALUE_MASK
|
||||
GLuint write_mask = 0xFFFFFFFF; // GL_STENCIL_WRITEMASK
|
||||
GLenum action_stencil_fail = GL_KEEP; // GL_STENCIL_FAIL
|
||||
GLenum action_depth_fail = GL_KEEP; // GL_STENCIL_PASS_DEPTH_FAIL
|
||||
GLenum action_depth_pass = GL_KEEP; // GL_STENCIL_PASS_DEPTH_PASS
|
||||
GLenum test_func; // GL_STENCIL_FUNC
|
||||
GLint test_ref; // GL_STENCIL_REF
|
||||
GLuint test_mask; // GL_STENCIL_VALUE_MASK
|
||||
GLuint write_mask; // GL_STENCIL_WRITEMASK
|
||||
GLenum action_stencil_fail; // GL_STENCIL_FAIL
|
||||
GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL
|
||||
GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS
|
||||
} front, back;
|
||||
} stencil;
|
||||
|
||||
struct Blend {
|
||||
bool enabled = false; // GL_BLEND
|
||||
GLenum rgb_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_RGB
|
||||
GLenum a_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_ALPHA
|
||||
GLenum src_rgb_func = GL_ONE; // GL_BLEND_SRC_RGB
|
||||
GLenum dst_rgb_func = GL_ZERO; // GL_BLEND_DST_RGB
|
||||
GLenum src_a_func = GL_ONE; // GL_BLEND_SRC_ALPHA
|
||||
GLenum dst_a_func = GL_ZERO; // GL_BLEND_DST_ALPHA
|
||||
bool enabled; // GL_BLEND
|
||||
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
|
||||
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
|
||||
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
|
||||
GLenum dst_rgb_func; // GL_BLEND_DST_RGB
|
||||
GLenum src_a_func; // GL_BLEND_SRC_ALPHA
|
||||
GLenum dst_a_func; // GL_BLEND_DST_ALPHA
|
||||
};
|
||||
std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
|
||||
|
||||
struct {
|
||||
bool enabled = false;
|
||||
bool enabled;
|
||||
} independant_blend;
|
||||
|
||||
struct {
|
||||
GLclampf red = 0.0f;
|
||||
GLclampf green = 0.0f;
|
||||
GLclampf blue = 0.0f;
|
||||
GLclampf alpha = 0.0f;
|
||||
GLclampf red;
|
||||
GLclampf green;
|
||||
GLclampf blue;
|
||||
GLclampf alpha;
|
||||
} blend_color; // GL_BLEND_COLOR
|
||||
|
||||
struct {
|
||||
bool enabled = false; // GL_LOGIC_OP_MODE
|
||||
GLenum operation = GL_COPY;
|
||||
bool enabled; // GL_LOGIC_OP_MODE
|
||||
GLenum operation;
|
||||
} logic_op;
|
||||
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures = {};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers = {};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images = {};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures{};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers{};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images{};
|
||||
|
||||
struct {
|
||||
GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING
|
||||
GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING
|
||||
GLuint vertex_array = 0; // GL_VERTEX_ARRAY_BINDING
|
||||
GLuint shader_program = 0; // GL_CURRENT_PROGRAM
|
||||
GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING
|
||||
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
|
||||
GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
|
||||
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
|
||||
GLuint shader_program; // GL_CURRENT_PROGRAM
|
||||
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
|
||||
} draw;
|
||||
|
||||
struct Viewport {
|
||||
GLint x = 0;
|
||||
GLint y = 0;
|
||||
GLint width = 0;
|
||||
GLint height = 0;
|
||||
GLfloat depth_range_near = 0.0f; // GL_DEPTH_RANGE
|
||||
GLfloat depth_range_far = 1.0f; // GL_DEPTH_RANGE
|
||||
struct viewport {
|
||||
GLint x;
|
||||
GLint y;
|
||||
GLint width;
|
||||
GLint height;
|
||||
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
||||
GLfloat depth_range_far; // GL_DEPTH_RANGE
|
||||
struct {
|
||||
bool enabled = false; // GL_SCISSOR_TEST
|
||||
GLint x = 0;
|
||||
GLint y = 0;
|
||||
GLsizei width = 0;
|
||||
GLsizei height = 0;
|
||||
bool enabled; // GL_SCISSOR_TEST
|
||||
GLint x;
|
||||
GLint y;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
} scissor;
|
||||
};
|
||||
std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
|
||||
std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
|
||||
|
||||
struct {
|
||||
float size = 1.0f; // GL_POINT_SIZE
|
||||
float size; // GL_POINT_SIZE
|
||||
} point;
|
||||
|
||||
struct {
|
||||
bool point_enable = false;
|
||||
bool line_enable = false;
|
||||
bool fill_enable = false;
|
||||
GLfloat units = 0.0f;
|
||||
GLfloat factor = 0.0f;
|
||||
GLfloat clamp = 0.0f;
|
||||
bool point_enable;
|
||||
bool line_enable;
|
||||
bool fill_enable;
|
||||
GLfloat units;
|
||||
GLfloat factor;
|
||||
GLfloat clamp;
|
||||
} polygon_offset;
|
||||
|
||||
struct {
|
||||
bool enabled = false; // GL_ALPHA_TEST
|
||||
GLenum func = GL_ALWAYS; // GL_ALPHA_TEST_FUNC
|
||||
GLfloat ref = 0.0f; // GL_ALPHA_TEST_REF
|
||||
bool enabled; // GL_ALPHA_TEST
|
||||
GLenum func; // GL_ALPHA_TEST_FUNC
|
||||
GLfloat ref; // GL_ALPHA_TEST_REF
|
||||
} alpha_test;
|
||||
|
||||
std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE
|
||||
std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE
|
||||
|
||||
OpenGLState();
|
||||
|
||||
@@ -157,31 +179,34 @@ public:
|
||||
/// Apply this state as the current OpenGL state
|
||||
void Apply();
|
||||
|
||||
void ApplyFramebufferState();
|
||||
void ApplyVertexArrayState();
|
||||
void ApplyShaderProgram();
|
||||
void ApplyProgramPipeline();
|
||||
void ApplyClipDistances();
|
||||
void ApplyPointSize();
|
||||
void ApplyFragmentColorClamp();
|
||||
void ApplyMultisample();
|
||||
void ApplySRgb();
|
||||
void ApplyCulling();
|
||||
void ApplyColorMask();
|
||||
void ApplyDepth();
|
||||
void ApplyPrimitiveRestart();
|
||||
void ApplyStencilTest();
|
||||
void ApplyViewport();
|
||||
void ApplyTargetBlending(std::size_t target, bool force);
|
||||
void ApplyGlobalBlending();
|
||||
void ApplyBlending();
|
||||
void ApplyLogicOp();
|
||||
void ApplyTextures();
|
||||
void ApplySamplers();
|
||||
void ApplyImages();
|
||||
void ApplyDepthClamp();
|
||||
void ApplyPolygonOffset();
|
||||
void ApplyAlphaTest();
|
||||
void ApplyFramebufferState() const;
|
||||
void ApplyVertexArrayState() const;
|
||||
void ApplyShaderProgram() const;
|
||||
void ApplyProgramPipeline() const;
|
||||
void ApplyClipDistances() const;
|
||||
void ApplyPointSize() const;
|
||||
void ApplyFragmentColorClamp() const;
|
||||
void ApplyMultisample() const;
|
||||
void ApplySRgb() const;
|
||||
void ApplyCulling() const;
|
||||
void ApplyColorMask() const;
|
||||
void ApplyDepth() const;
|
||||
void ApplyPrimitiveRestart() const;
|
||||
void ApplyStencilTest() const;
|
||||
void ApplyViewport() const;
|
||||
void ApplyTargetBlending(std::size_t target, bool force) const;
|
||||
void ApplyGlobalBlending() const;
|
||||
void ApplyBlending() const;
|
||||
void ApplyLogicOp() const;
|
||||
void ApplyTextures() const;
|
||||
void ApplySamplers() const;
|
||||
void ApplyImages() const;
|
||||
void ApplyDepthClamp() const;
|
||||
void ApplyPolygonOffset() const;
|
||||
void ApplyAlphaTest() const;
|
||||
|
||||
/// Set the initial OpenGL state
|
||||
static void ApplyDefaultState();
|
||||
|
||||
/// Resets any references to the given resource
|
||||
OpenGLState& UnbindTexture(GLuint handle);
|
||||
@@ -228,6 +253,5 @@ private:
|
||||
bool color_mask;
|
||||
} dirty{};
|
||||
};
|
||||
static_assert(std::is_trivially_copyable_v<OpenGLState>);
|
||||
|
||||
} // namespace OpenGL
|
||||
@@ -131,7 +131,6 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X6_SRGB
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5_SRGB
|
||||
{GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, ComponentType::Float, false}, // E5B9G9R9F
|
||||
|
||||
// Depth formats
|
||||
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
|
||||
|
||||
@@ -168,8 +168,8 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
|
||||
if (opcode->get().GetId() == OpCode::Id::LD_C) {
|
||||
if (instr.gpr0.Value() == track_register &&
|
||||
instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) {
|
||||
result.buffer = instr.cbuf36.index.Value();
|
||||
result.offset = static_cast<u32>(instr.cbuf36.GetOffset());
|
||||
result.buffer = instr.cbuf36.index;
|
||||
result.offset = instr.cbuf36.GetOffset();
|
||||
track_register = instr.gpr8.Value();
|
||||
pos--;
|
||||
found_track = true;
|
||||
@@ -190,7 +190,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
const Instruction instr = state.program_code[pos];
|
||||
const Instruction instr = {state.program_code[pos]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() == OpCode::Id::SHL_IMM) {
|
||||
if (instr.gpr0.Value() == track_register) {
|
||||
@@ -214,7 +214,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
const Instruction instr = state.program_code[pos];
|
||||
const Instruction instr = {state.program_code[pos]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) {
|
||||
if (instr.gpr0.Value() == track_register) {
|
||||
@@ -231,7 +231,7 @@ std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState&
|
||||
if (!found_track) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return result;
|
||||
return {result};
|
||||
}
|
||||
|
||||
std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
|
||||
|
||||
@@ -155,7 +155,7 @@ void ShaderIR::Decode() {
|
||||
[[fallthrough]];
|
||||
case CompileDepth::BruteForce: {
|
||||
coverage_begin = main_offset;
|
||||
const std::size_t shader_end = program_code.size();
|
||||
const u32 shader_end = program_code.size();
|
||||
coverage_end = shader_end;
|
||||
for (u32 label = main_offset; label < shader_end; label++) {
|
||||
basic_blocks.insert({label, DecodeRange(label, label + 1)});
|
||||
|
||||
@@ -284,7 +284,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
|
||||
|
||||
const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
|
||||
std::optional<SamplerInfo> sampler_info) {
|
||||
const auto offset = static_cast<u32>(sampler.index.Value());
|
||||
const auto offset = static_cast<std::size_t>(sampler.index.Value());
|
||||
|
||||
Tegra::Shader::TextureType type;
|
||||
bool is_array;
|
||||
@@ -293,14 +293,17 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
|
||||
type = sampler_info->type;
|
||||
is_array = sampler_info->is_array;
|
||||
is_shadow = sampler_info->is_shadow;
|
||||
} else if (auto sampler = locker.ObtainBoundSampler(offset); sampler) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
type = Tegra::Shader::TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
auto sampler = locker.ObtainBoundSampler(offset);
|
||||
if (sampler) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
type = Tegra::Shader::TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If this sampler has already been used, return the existing mapping.
|
||||
@@ -317,7 +320,7 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
|
||||
const std::size_t next_index = used_samplers.size();
|
||||
const Sampler entry{offset, next_index, type, is_array, is_shadow};
|
||||
return *used_samplers.emplace(entry).first;
|
||||
} // namespace VideoCommon::Shader
|
||||
}
|
||||
|
||||
const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
|
||||
std::optional<SamplerInfo> sampler_info) {
|
||||
@@ -333,14 +336,17 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
|
||||
type = sampler_info->type;
|
||||
is_array = sampler_info->is_array;
|
||||
is_shadow = sampler_info->is_shadow;
|
||||
} else if (auto sampler = locker.ObtainBindlessSampler(cbuf_index, cbuf_offset); sampler) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
type = Tegra::Shader::TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
auto sampler = locker.ObtainBindlessSampler(cbuf_index, cbuf_offset);
|
||||
if (sampler) {
|
||||
type = sampler->texture_type.Value();
|
||||
is_array = sampler->is_array.Value() != 0;
|
||||
is_shadow = sampler->is_shadow.Value() != 0;
|
||||
} else {
|
||||
type = Tegra::Shader::TextureType::Texture2D;
|
||||
is_array = false;
|
||||
is_shadow = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If this sampler has already been used, return the existing mapping.
|
||||
|
||||
@@ -315,14 +315,6 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Tegra::Texture::TextureFormat::E5B9G9R9_SHAREDEXP:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::E5B9G9R9F;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Tegra::Texture::TextureFormat::ZF32:
|
||||
return PixelFormat::Z32F;
|
||||
case Tegra::Texture::TextureFormat::Z16:
|
||||
|
||||
@@ -86,20 +86,19 @@ enum class PixelFormat {
|
||||
ASTC_2D_8X6_SRGB = 68,
|
||||
ASTC_2D_6X5 = 69,
|
||||
ASTC_2D_6X5_SRGB = 70,
|
||||
E5B9G9R9F = 71,
|
||||
|
||||
MaxColorFormat,
|
||||
|
||||
// Depth formats
|
||||
Z32F = 72,
|
||||
Z16 = 73,
|
||||
Z32F = 71,
|
||||
Z16 = 72,
|
||||
|
||||
MaxDepthFormat,
|
||||
|
||||
// DepthStencil formats
|
||||
Z24S8 = 74,
|
||||
S8Z24 = 75,
|
||||
Z32FS8 = 76,
|
||||
Z24S8 = 73,
|
||||
S8Z24 = 74,
|
||||
Z32FS8 = 75,
|
||||
|
||||
MaxDepthStencilFormat,
|
||||
|
||||
@@ -208,7 +207,6 @@ constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{
|
||||
2, // ASTC_2D_8X6_SRGB
|
||||
2, // ASTC_2D_6X5
|
||||
2, // ASTC_2D_6X5_SRGB
|
||||
0, // E5B9G9R9F
|
||||
0, // Z32F
|
||||
0, // Z16
|
||||
0, // Z24S8
|
||||
@@ -304,7 +302,6 @@ constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
|
||||
8, // ASTC_2D_8X6_SRGB
|
||||
6, // ASTC_2D_6X5
|
||||
6, // ASTC_2D_6X5_SRGB
|
||||
1, // E5B9G9R9F
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
@@ -392,7 +389,6 @@ constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
|
||||
6, // ASTC_2D_8X6_SRGB
|
||||
5, // ASTC_2D_6X5
|
||||
5, // ASTC_2D_6X5_SRGB
|
||||
1, // E5B9G9R9F
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
@@ -480,7 +476,6 @@ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
|
||||
128, // ASTC_2D_8X6_SRGB
|
||||
128, // ASTC_2D_6X5
|
||||
128, // ASTC_2D_6X5_SRGB
|
||||
32, // E5B9G9R9F
|
||||
32, // Z32F
|
||||
16, // Z16
|
||||
32, // Z24S8
|
||||
@@ -583,7 +578,6 @@ constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table
|
||||
SurfaceCompression::Converted, // ASTC_2D_8X6_SRGB
|
||||
SurfaceCompression::Converted, // ASTC_2D_6X5
|
||||
SurfaceCompression::Converted, // ASTC_2D_6X5_SRGB
|
||||
SurfaceCompression::None, // E5B9G9R9F
|
||||
SurfaceCompression::None, // Z32F
|
||||
SurfaceCompression::None, // Z16
|
||||
SurfaceCompression::None, // Z24S8
|
||||
|
||||
@@ -422,7 +422,7 @@ static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
|
||||
TexelWeightParams params;
|
||||
|
||||
// Read the entire block mode all at once
|
||||
uint16_t modeBits = static_cast<uint16_t>(strm.ReadBits(11));
|
||||
uint16_t modeBits = strm.ReadBits(11);
|
||||
|
||||
// Does this match the void extent block mode?
|
||||
if ((modeBits & 0x01FF) == 0x1FC) {
|
||||
@@ -625,10 +625,10 @@ static void FillVoidExtentLDR(InputBitStream& strm, uint32_t* const outBuf, uint
|
||||
}
|
||||
|
||||
// Decode the RGBA components and renormalize them to the range [0, 255]
|
||||
uint16_t r = static_cast<uint16_t>(strm.ReadBits(16));
|
||||
uint16_t g = static_cast<uint16_t>(strm.ReadBits(16));
|
||||
uint16_t b = static_cast<uint16_t>(strm.ReadBits(16));
|
||||
uint16_t a = static_cast<uint16_t>(strm.ReadBits(16));
|
||||
uint16_t r = strm.ReadBits(16);
|
||||
uint16_t g = strm.ReadBits(16);
|
||||
uint16_t b = strm.ReadBits(16);
|
||||
uint16_t a = strm.ReadBits(16);
|
||||
|
||||
uint32_t rgba = (r >> 8) | (g & 0xFF00) | (static_cast<uint32_t>(b) & 0xFF00) << 8 |
|
||||
(static_cast<uint32_t>(a) & 0xFF00) << 16;
|
||||
@@ -681,10 +681,9 @@ protected:
|
||||
|
||||
public:
|
||||
Pixel() = default;
|
||||
Pixel(uint32_t a, uint32_t r, uint32_t g, uint32_t b, unsigned bitDepth = 8)
|
||||
Pixel(ChannelType a, ChannelType r, ChannelType g, ChannelType b, unsigned bitDepth = 8)
|
||||
: m_BitDepth{uint8_t(bitDepth), uint8_t(bitDepth), uint8_t(bitDepth), uint8_t(bitDepth)},
|
||||
color{static_cast<ChannelType>(a), static_cast<ChannelType>(r),
|
||||
static_cast<ChannelType>(g), static_cast<ChannelType>(b)} {}
|
||||
color{a, r, g, b} {}
|
||||
|
||||
// Changes the depth of each pixel. This scales the values to
|
||||
// the appropriate bit depth by either truncating the least
|
||||
|
||||
@@ -354,6 +354,7 @@ struct TSCEntry {
|
||||
static_assert(sizeof(TSCEntry) == 0x20, "TSCEntry has wrong size");
|
||||
|
||||
struct FullTextureInfo {
|
||||
u32 index;
|
||||
TICEntry tic;
|
||||
TSCEntry tsc;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user