summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/CMakeLists.txt5
-rw-r--r--src/audio_core/audio_core.cpp37
-rw-r--r--src/audio_core/audio_core.h5
-rw-r--r--src/audio_core/hle/dsp.cpp49
-rw-r--r--src/audio_core/hle/dsp.h18
-rw-r--r--src/audio_core/interpolate.cpp85
-rw-r--r--src/audio_core/interpolate.h41
-rw-r--r--src/audio_core/null_sink.h29
-rw-r--r--src/audio_core/sink_details.cpp18
-rw-r--r--src/audio_core/sink_details.h27
-rw-r--r--src/citra/config.cpp3
-rw-r--r--src/citra/default_ini.h5
-rw-r--r--src/citra_qt/config.cpp8
-rw-r--r--src/citra_qt/debugger/graphics_tracing.cpp4
-rw-r--r--src/common/bit_field.h2
-rw-r--r--src/common/bit_set.h3
-rw-r--r--src/common/code_block.h6
-rw-r--r--src/common/common_funcs.h4
-rw-r--r--src/common/file_util.h2
-rw-r--r--src/common/x64/emitter.h2
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/ac_u.cpp26
-rw-r--r--src/core/hle/service/gsp_gpu.cpp40
-rw-r--r--src/core/hle/service/gsp_gpu.h1
-rw-r--r--src/core/hle/service/ndm/ndm.cpp197
-rw-r--r--src/core/hle/service/ndm/ndm.h216
-rw-r--r--src/core/hle/service/ndm/ndm_u.cpp34
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/hw/lcd.h2
-rw-r--r--src/core/settings.cpp5
-rw-r--r--src/core/settings.h6
-rw-r--r--src/core/tracer/recorder.h1
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/clipper.cpp13
-rw-r--r--src/video_core/command_processor.cpp149
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp14
-rw-r--r--src/video_core/debug_utils/debug_utils.h46
-rw-r--r--src/video_core/pica.cpp5
-rw-r--r--src/video_core/pica.h7
-rw-r--r--src/video_core/pica_state.h5
-rw-r--r--src/video_core/pica_types.h1
-rw-r--r--src/video_core/primitive_assembly.cpp3
-rw-r--r--src/video_core/rasterizer.cpp10
-rw-r--r--src/video_core/renderer_base.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h55
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_state.h1
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h7
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp15
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h3
-rw-r--r--src/video_core/shader/shader.cpp18
-rw-r--r--src/video_core/shader/shader.h10
-rw-r--r--src/video_core/shader/shader_interpreter.cpp12
-rw-r--r--src/video_core/shader/shader_interpreter.h4
-rw-r--r--src/video_core/shader/shader_jit_x64.cpp10
-rw-r--r--src/video_core/shader/shader_jit_x64.h5
-rw-r--r--src/video_core/swrasterizer.h6
-rw-r--r--src/video_core/utils.cpp36
-rw-r--r--src/video_core/utils.h27
-rw-r--r--src/video_core/vertex_loader.cpp140
-rw-r--r--src/video_core/vertex_loader.h33
-rw-r--r--src/video_core/video_core.cpp4
68 files changed, 1244 insertions, 348 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index c08ce69e0..5a2747e78 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -4,6 +4,8 @@ set(SRCS
hle/dsp.cpp
hle/filter.cpp
hle/pipe.cpp
+ interpolate.cpp
+ sink_details.cpp
)
set(HEADERS
@@ -13,7 +15,10 @@ set(HEADERS
hle/dsp.h
hle/filter.h
hle/pipe.h
+ interpolate.h
+ null_sink.h
sink.h
+ sink_details.h
)
include_directories(../../externals/soundtouch/include)
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index b512b0f9b..d42249ebd 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -2,9 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <memory>
+#include <string>
+
#include "audio_core/audio_core.h"
#include "audio_core/hle/dsp.h"
#include "audio_core/hle/pipe.h"
+#include "audio_core/null_sink.h"
+#include "audio_core/sink.h"
+#include "audio_core/sink_details.h"
#include "core/core_timing.h"
#include "core/hle/kernel/vm_manager.h"
@@ -28,7 +34,6 @@ static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
}
-/// Initialise Audio
void Init() {
DSP::HLE::Init();
@@ -36,19 +41,39 @@ void Init() {
CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event);
}
-/// Add DSP address spaces to Process's address space.
void AddAddressSpace(Kernel::VMManager& address_space) {
- auto r0_vma = address_space.MapBackingMemory(DSP::HLE::region0_base, reinterpret_cast<u8*>(&DSP::HLE::g_region0), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
+ auto r0_vma = address_space.MapBackingMemory(DSP::HLE::region0_base, reinterpret_cast<u8*>(&DSP::HLE::g_regions[0]), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
address_space.Reprotect(r0_vma, Kernel::VMAPermission::ReadWrite);
- auto r1_vma = address_space.MapBackingMemory(DSP::HLE::region1_base, reinterpret_cast<u8*>(&DSP::HLE::g_region1), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
+ auto r1_vma = address_space.MapBackingMemory(DSP::HLE::region1_base, reinterpret_cast<u8*>(&DSP::HLE::g_regions[1]), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom();
address_space.Reprotect(r1_vma, Kernel::VMAPermission::ReadWrite);
}
-/// Shutdown Audio
+void SelectSink(std::string sink_id) {
+ if (sink_id == "auto") {
+ // Auto-select.
+ // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+ const auto& sink_detail = g_sink_details.front();
+ DSP::HLE::SetSink(sink_detail.factory());
+ return;
+ }
+
+ auto iter = std::find_if(g_sink_details.begin(), g_sink_details.end(), [sink_id](const auto& sink_detail) {
+ return sink_detail.id == sink_id;
+ });
+
+ if (iter == g_sink_details.end()) {
+ LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id");
+ DSP::HLE::SetSink(std::make_unique<NullSink>());
+ return;
+ }
+
+ DSP::HLE::SetSink(iter->factory());
+}
+
void Shutdown() {
CoreTiming::UnscheduleEvent(tick_event, 0);
DSP::HLE::Shutdown();
}
-} //namespace
+} // namespace AudioCore
diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h
index b349895ea..f618361f3 100644
--- a/src/audio_core/audio_core.h
+++ b/src/audio_core/audio_core.h
@@ -4,6 +4,8 @@
#pragma once
+#include <string>
+
namespace Kernel {
class VMManager;
}
@@ -18,6 +20,9 @@ void Init();
/// Add DSP address spaces to a Process.
void AddAddressSpace(Kernel::VMManager& vm_manager);
+/// Select the sink to use based on sink id.
+void SelectSink(std::string sink_id);
+
/// Shutdown Audio Core
void Shutdown();
diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp
index c89356edc..4d44bd2d9 100644
--- a/src/audio_core/hle/dsp.cpp
+++ b/src/audio_core/hle/dsp.cpp
@@ -2,14 +2,43 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <memory>
+
#include "audio_core/hle/dsp.h"
#include "audio_core/hle/pipe.h"
+#include "audio_core/sink.h"
namespace DSP {
namespace HLE {
-SharedMemory g_region0;
-SharedMemory g_region1;
+std::array<SharedMemory, 2> g_regions;
+
+static size_t CurrentRegionIndex() {
+ // The region with the higher frame counter is chosen unless there is wraparound.
+ // This function only returns a 0 or 1.
+
+ if (g_regions[0].frame_counter == 0xFFFFu && g_regions[1].frame_counter != 0xFFFEu) {
+ // Wraparound has occured.
+ return 1;
+ }
+
+ if (g_regions[1].frame_counter == 0xFFFFu && g_regions[0].frame_counter != 0xFFFEu) {
+ // Wraparound has occured.
+ return 0;
+ }
+
+ return (g_regions[0].frame_counter > g_regions[1].frame_counter) ? 0 : 1;
+}
+
+static SharedMemory& ReadRegion() {
+ return g_regions[CurrentRegionIndex()];
+}
+
+static SharedMemory& WriteRegion() {
+ return g_regions[1 - CurrentRegionIndex()];
+}
+
+static std::unique_ptr<AudioCore::Sink> sink;
void Init() {
DSP::HLE::ResetPipes();
@@ -22,20 +51,8 @@ bool Tick() {
return true;
}
-SharedMemory& CurrentRegion() {
- // The region with the higher frame counter is chosen unless there is wraparound.
-
- if (g_region0.frame_counter == 0xFFFFu && g_region1.frame_counter != 0xFFFEu) {
- // Wraparound has occured.
- return g_region1;
- }
-
- if (g_region1.frame_counter == 0xFFFFu && g_region0.frame_counter != 0xFFFEu) {
- // Wraparound has occured.
- return g_region0;
- }
-
- return (g_region0.frame_counter > g_region1.frame_counter) ? g_region0 : g_region1;
+void SetSink(std::unique_ptr<AudioCore::Sink> sink_) {
+ sink = std::move(sink_);
}
} // namespace HLE
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h
index c76350bdd..4f2410c27 100644
--- a/src/audio_core/hle/dsp.h
+++ b/src/audio_core/hle/dsp.h
@@ -4,7 +4,9 @@
#pragma once
+#include <array>
#include <cstddef>
+#include <memory>
#include <type_traits>
#include "audio_core/hle/common.h"
@@ -14,6 +16,10 @@
#include "common/common_types.h"
#include "common/swap.h"
+namespace AudioCore {
+class Sink;
+}
+
namespace DSP {
namespace HLE {
@@ -30,10 +36,9 @@ namespace HLE {
struct SharedMemory;
constexpr VAddr region0_base = 0x1FF50000;
-extern SharedMemory g_region0;
-
constexpr VAddr region1_base = 0x1FF70000;
-extern SharedMemory g_region1;
+
+extern std::array<SharedMemory, 2> g_regions;
/**
* The DSP is native 16-bit. The DSP also appears to be big-endian. When reading 32-bit numbers from
@@ -535,8 +540,11 @@ void Shutdown();
*/
bool Tick();
-/// Returns a mutable reference to the current region. Current region is selected based on the frame counter.
-SharedMemory& CurrentRegion();
+/**
+ * Set the output sink. This must be called before calling Tick().
+ * @param sink The sink to which audio will be output to.
+ */
+void SetSink(std::unique_ptr<AudioCore::Sink> sink);
} // namespace HLE
} // namespace DSP
diff --git a/src/audio_core/interpolate.cpp b/src/audio_core/interpolate.cpp
new file mode 100644
index 000000000..fcd3aa066
--- /dev/null
+++ b/src/audio_core/interpolate.cpp
@@ -0,0 +1,85 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "audio_core/interpolate.h"
+
+#include "common/assert.h"
+#include "common/math_util.h"
+
+namespace AudioInterp {
+
+// Calculations are done in fixed point with 24 fractional bits.
+// (This is not verified. This was chosen for minimal error.)
+constexpr u64 scale_factor = 1 << 24;
+constexpr u64 scale_mask = scale_factor - 1;
+
+/// Here we step over the input in steps of rate_multiplier, until we consume all of the input.
+/// Three adjacent samples are passed to fn each step.
+template <typename Function>
+static StereoBuffer16 StepOverSamples(State& state, const StereoBuffer16& input, float rate_multiplier, Function fn) {
+ ASSERT(rate_multiplier > 0);
+
+ if (input.size() < 2)
+ return {};
+
+ StereoBuffer16 output;
+ output.reserve(static_cast<size_t>(input.size() / rate_multiplier));
+
+ u64 step_size = static_cast<u64>(rate_multiplier * scale_factor);
+
+ u64 fposition = 0;
+ const u64 max_fposition = input.size() * scale_factor;
+
+ while (fposition < 1 * scale_factor) {
+ u64 fraction = fposition & scale_mask;
+
+ output.push_back(fn(fraction, state.xn2, state.xn1, input[0]));
+
+ fposition += step_size;
+ }
+
+ while (fposition < 2 * scale_factor) {
+ u64 fraction = fposition & scale_mask;
+
+ output.push_back(fn(fraction, state.xn1, input[0], input[1]));
+
+ fposition += step_size;
+ }
+
+ while (fposition < max_fposition) {
+ u64 fraction = fposition & scale_mask;
+
+ size_t index = static_cast<size_t>(fposition / scale_factor);
+ output.push_back(fn(fraction, input[index - 2], input[index - 1], input[index]));
+
+ fposition += step_size;
+ }
+
+ state.xn2 = input[input.size() - 2];
+ state.xn1 = input[input.size() - 1];
+
+ return output;
+}
+
+StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multiplier) {
+ return StepOverSamples(state, input, rate_multiplier, [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) {
+ return x0;
+ });
+}
+
+StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier) {
+ // Note on accuracy: Some values that this produces are +/- 1 from the actual firmware.
+ return StepOverSamples(state, input, rate_multiplier, [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) {
+ // This is a saturated subtraction. (Verified by black-box fuzzing.)
+ s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767);
+ s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767);
+
+ return std::array<s16, 2> {
+ static_cast<s16>(x0[0] + fraction * delta0 / scale_factor),
+ static_cast<s16>(x0[1] + fraction * delta1 / scale_factor)
+ };
+ });
+}
+
+} // namespace AudioInterp
diff --git a/src/audio_core/interpolate.h b/src/audio_core/interpolate.h
new file mode 100644
index 000000000..a4c0a453d
--- /dev/null
+++ b/src/audio_core/interpolate.h
@@ -0,0 +1,41 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace AudioInterp {
+
+/// A variable length buffer of signed PCM16 stereo samples.
+using StereoBuffer16 = std::vector<std::array<s16, 2>>;
+
+struct State {
+ // Two historical samples.
+ std::array<s16, 2> xn1 = {}; ///< x[n-1]
+ std::array<s16, 2> xn2 = {}; ///< x[n-2]
+};
+
+/**
+ * No interpolation. This is equivalent to a zero-order hold. There is a two-sample predelay.
+ * @param input Input buffer.
+ * @param rate_multiplier Stretch factor. Must be a positive non-zero value.
+ * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 performs upsampling.
+ * @return The resampled audio buffer.
+ */
+StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multiplier);
+
+/**
+ * Linear interpolation. This is equivalent to a first-order hold. There is a two-sample predelay.
+ * @param input Input buffer.
+ * @param rate_multiplier Stretch factor. Must be a positive non-zero value.
+ * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 performs upsampling.
+ * @return The resampled audio buffer.
+ */
+StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier);
+
+} // namespace AudioInterp
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
new file mode 100644
index 000000000..faf0ee4e1
--- /dev/null
+++ b/src/audio_core/null_sink.h
@@ -0,0 +1,29 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+
+#include "audio_core/audio_core.h"
+#include "audio_core/sink.h"
+
+namespace AudioCore {
+
+class NullSink final : public Sink {
+public:
+ ~NullSink() override = default;
+
+ unsigned int GetNativeSampleRate() const override {
+ return native_sample_rate;
+ }
+
+ void EnqueueSamples(const std::vector<s16>&) override {}
+
+ size_t SamplesInQueue() const override {
+ return 0;
+ }
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
new file mode 100644
index 000000000..d2cc74103
--- /dev/null
+++ b/src/audio_core/sink_details.cpp
@@ -0,0 +1,18 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+#include <vector>
+
+#include "audio_core/null_sink.h"
+#include "audio_core/sink_details.h"
+
+namespace AudioCore {
+
+// g_sink_details is ordered in terms of desirability, with the best choice at the top.
+const std::vector<SinkDetails> g_sink_details = {
+ { "null", []() { return std::make_unique<NullSink>(); } },
+};
+
+} // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
new file mode 100644
index 000000000..4b30cf835
--- /dev/null
+++ b/src/audio_core/sink_details.h
@@ -0,0 +1,27 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace AudioCore {
+
+class Sink;
+
+struct SinkDetails {
+ SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>()> factory_)
+ : id(id_), factory(factory_) {}
+
+ /// Name for this sink.
+ const char* id;
+ /// A method to call to construct an instance of this type of sink.
+ std::function<std::unique_ptr<Sink>()> factory;
+};
+
+extern const std::vector<SinkDetails> g_sink_details;
+
+} // namespace AudioCore
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 9e2ecd307..0d17c80bf 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -71,6 +71,9 @@ void Config::ReadValues() {
Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 1.0);
Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 1.0);
+ // Audio
+ Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
+
// Data Storage
Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 1f1aa716b..0e6171736 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -56,6 +56,11 @@ bg_red =
bg_blue =
bg_green =
+[Audio]
+# Which audio output engine to use.
+# auto (default): Auto-select, null: No audio output
+output_engine =
+
[Data Storage]
# Whether to create a virtual SD card.
# 1 (default): Yes, 0: No
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 7dc61fe40..b5bb75537 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -52,6 +52,10 @@ void Config::ReadValues() {
Settings::values.bg_blue = qt_config->value("bg_blue", 1.0).toFloat();
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
qt_config->endGroup();
@@ -138,6 +142,10 @@ void Config::SaveValues() {
qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
qt_config->endGroup();
+ qt_config->beginGroup("Audio");
+ qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
+ qt_config->endGroup();
+
qt_config->beginGroup("Data Storage");
qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
qt_config->endGroup();
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp
index e06498744..1402f8e79 100644
--- a/src/citra_qt/debugger/graphics_tracing.cpp
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <array>
+#include <iterator>
#include <memory>
#include <boost/range/algorithm/copy.hpp>
@@ -18,6 +21,7 @@
#include "core/hw/gpu.h"
#include "core/hw/lcd.h"
+#include "core/tracer/recorder.h"
#include "nihstro/float24.h"
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 371eb17a1..4748999ed 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -186,5 +186,5 @@ private:
#pragma pack()
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
-static_assert(std::is_trivially_copyable<BitField<0, 1, u32>>::value, "BitField must be trivially copyable");
+static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, "BitField must be trivially copyable");
#endif
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index 85f91e786..7f5de8df2 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -7,6 +7,7 @@
#include <intrin.h>
#endif
#include <initializer_list>
+#include <new>
#include <type_traits>
#include "common/common_types.h"
@@ -186,4 +187,4 @@ public:
typedef Common::BitSet<u8> BitSet8;
typedef Common::BitSet<u16> BitSet16;
typedef Common::BitSet<u32> BitSet32;
-typedef Common::BitSet<u64> BitSet64; \ No newline at end of file
+typedef Common::BitSet<u64> BitSet64;
diff --git a/src/common/code_block.h b/src/common/code_block.h
index 9ef7296d3..2fa4a0090 100644
--- a/src/common/code_block.h
+++ b/src/common/code_block.h
@@ -4,8 +4,10 @@
#pragma once
-#include "common_types.h"
-#include "memory_util.h"
+#include <cstddef>
+
+#include "common/common_types.h"
+#include "common/memory_util.h"
// Everything that needs to generate code should inherit from this.
// You get memory management for free, plus, you can use all emitter functions without
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index aa6aff7b9..ab3515683 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -4,6 +4,10 @@
#pragma once
+#if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM)
+#include <cstdlib> // for exit
+#endif
+
#include "common_types.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 3aac4fa46..c6a8694ce 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -7,9 +7,9 @@
#include <array>
#include <fstream>
#include <functional>
-#include <cstddef>
#include <cstdio>
#include <string>
+#include <type_traits>
#include <vector>
#include "common/common_types.h"
diff --git a/src/common/x64/emitter.h b/src/common/x64/emitter.h
index a33724146..60a77dfe1 100644
--- a/src/common/x64/emitter.h
+++ b/src/common/x64/emitter.h
@@ -17,6 +17,8 @@
#pragma once
+#include <cstddef>
+
#include "common/assert.h"
#include "common/bit_set.h"
#include "common/common_types.h"
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 53931a106..3fc1ab4ee 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -5,7 +5,6 @@
#pragma once
#include <new>
-#include <type_traits>
#include <utility>
#include "common/assert.h"
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index d67325506..5241dd3e7 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -3,6 +3,8 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+
+#include "core/hle/kernel/event.h"
#include "core/hle/service/ac_u.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -11,6 +13,28 @@
namespace AC_U {
/**
+ * AC_U::CloseAsync service function
+ * Inputs:
+ * 1 : Always 0x20
+ * 3 : Always 0
+ * 4 : Event handle, should be signaled when AC connection is closed
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void CloseAsync(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
+
+ if (evt) {
+ evt->name = "AC_U:close_event";
+ evt->Signal();
+ }
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_WARNING(Service_AC, "(STUBBED) called");
+}
+/**
* AC_U::GetWifiStatus service function
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
@@ -47,7 +71,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00010000, nullptr, "CreateDefaultConfig"},
{0x00040006, nullptr, "ConnectAsync"},
{0x00050002, nullptr, "GetConnectResult"},
- {0x00080004, nullptr, "CloseAsync"},
+ {0x00080004, CloseAsync, "CloseAsync"},
{0x00090002, nullptr, "GetCloseResult"},
{0x000A0000, nullptr, "GetLastErrorCode"},
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 233592d7f..b4c146e08 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -43,6 +43,8 @@ Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
/// Thread index into interrupt relay queue
u32 g_thread_id = 0;
+static bool gpu_right_acquired = false;
+
/// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(u32 thread_id) {
return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
@@ -370,6 +372,9 @@ static void UnregisterInterruptRelayQueue(Service::Interface* self) {
* @todo This probably does not belong in the GSP module, instead move to video_core
*/
void SignalInterrupt(InterruptId interrupt_id) {
+ if (!gpu_right_acquired) {
+ return;
+ }
if (nullptr == g_interrupt_event) {
LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!");
return;
@@ -624,6 +629,35 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) {
LOG_WARNING(Service_GSP, "called");
}
+/**
+ * GSP_GPU::AcquireRight service function
+ * Outputs:
+ * 1: Result code
+ */
+static void AcquireRight(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ gpu_right_acquired = true;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_GSP, "called");
+}
+
+/**
+ * GSP_GPU::ReleaseRight service function
+ * Outputs:
+ * 1: Result code
+ */
+static void ReleaseRight(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ gpu_right_acquired = false;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_GSP, "called");
+}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, WriteHWRegs, "WriteHWRegs"},
@@ -647,8 +681,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
{0x00140000, UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"},
{0x00150002, nullptr, "TryAcquireRight"},
- {0x00160042, nullptr, "AcquireRight"},
- {0x00170000, nullptr, "ReleaseRight"},
+ {0x00160042, AcquireRight, "AcquireRight"},
+ {0x00170000, ReleaseRight, "ReleaseRight"},
{0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
{0x00190000, nullptr, "SaveVramSysArea"},
{0x001A0000, nullptr, "RestoreVramSysArea"},
@@ -669,11 +703,13 @@ Interface::Interface() {
g_shared_memory = nullptr;
g_thread_id = 0;
+ gpu_right_acquired = false;
}
Interface::~Interface() {
g_interrupt_event = nullptr;
g_shared_memory = nullptr;
+ gpu_right_acquired = false;
}
} // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 55a993bb8..3b4b678a3 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -10,6 +10,7 @@
#include "common/bit_field.h"
#include "common/common_types.h"
+#include "core/hle/result.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp
index 47076a7b8..bc9c3413d 100644
--- a/src/core/hle/service/ndm/ndm.cpp
+++ b/src/core/hle/service/ndm/ndm.cpp
@@ -11,28 +11,217 @@
namespace Service {
namespace NDM {
-void SuspendDaemons(Service::Interface* self) {
+enum : u32 {
+ DEFAULT_RETRY_INTERVAL = 10,
+ DEFAULT_SCAN_INTERVAL = 30
+};
+
+static DaemonMask daemon_bit_mask = DaemonMask::Default;
+static DaemonMask default_daemon_bit_mask = DaemonMask::Default;
+static std::array<DaemonStatus, 4> daemon_status = { DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle };
+static ExclusiveState exclusive_state = ExclusiveState::None;
+static u32 scan_interval = DEFAULT_SCAN_INTERVAL;
+static u32 retry_interval = DEFAULT_RETRY_INTERVAL;
+static bool daemon_lock_enabled = false;
+
+void EnterExclusiveState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ exclusive_state = static_cast<ExclusiveState>(cmd_buff[1]);
+
+ cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void LeaveExclusiveState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ exclusive_state = ExclusiveState::None;
+
+ cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void QueryExclusiveMode(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
+ cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = static_cast<u32>(exclusive_state);
+ LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void LockState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ daemon_lock_enabled = true;
+
+ cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled);
+}
+
+void UnlockState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ daemon_lock_enabled = false;
+ cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled);
+}
+
+void SuspendDaemons(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 bit_mask = cmd_buff[1] & 0xF;
+ daemon_bit_mask = static_cast<DaemonMask>(static_cast<u32>(default_daemon_bit_mask) & ~bit_mask);
+ for (size_t index = 0; index < daemon_status.size(); ++index) {
+ if (bit_mask & (1 << index)) {
+ daemon_status[index] = DaemonStatus::Suspended;
+ }
+ }
+
+ cmd_buff[0] = IPC::MakeHeader(0x6, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask);
}
void ResumeDaemons(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 bit_mask = cmd_buff[1] & 0xF;
+ daemon_bit_mask = static_cast<DaemonMask>(static_cast<u32>(daemon_bit_mask) | bit_mask);
+ for (size_t index = 0; index < daemon_status.size(); ++index) {
+ if (bit_mask & (1 << index)) {
+ daemon_status[index] = DaemonStatus::Idle;
+ }
+ }
+
+ cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask);
+}
+
+void SuspendScheduler(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x8, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void ResumeScheduler(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void QueryStatus(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 daemon = cmd_buff[1] & 0xF;
- LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
+ cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = static_cast<u32>(daemon_status.at(daemon));
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X, daemon_status=0x%08X", daemon, cmd_buff[2]);
+}
+
+void GetDaemonDisableCount(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 daemon = cmd_buff[1] & 0xF;
+
+ cmd_buff[0] = IPC::MakeHeader(0xE, 3, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = 0;
+ cmd_buff[3] = 0;
+ LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X", daemon);
+}
+
+void GetSchedulerDisableCount(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0xF, 3, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = 0;
+ cmd_buff[3] = 0;
+ LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void SetScanInterval(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ scan_interval = cmd_buff[1];
+ cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval);
+}
+
+void GetScanInterval(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x11, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = scan_interval;
+ LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval);
+}
+
+void SetRetryInterval(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ retry_interval = cmd_buff[1];
+
+ cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval);
+}
+
+void GetRetryInterval(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x13, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = retry_interval;
+ LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval);
}
void OverrideDefaultDaemons(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 bit_mask = cmd_buff[1] & 0xF;
+ default_daemon_bit_mask = static_cast<DaemonMask>(bit_mask);
+ daemon_bit_mask = default_daemon_bit_mask;
+ for (size_t index = 0; index < daemon_status.size(); ++index) {
+ if (bit_mask & (1 << index)) {
+ daemon_status[index] = DaemonStatus::Idle;
+ }
+ }
- LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
+ cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void ResetDefaultDaemons(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ default_daemon_bit_mask = DaemonMask::Default;
+
+ cmd_buff[0] = IPC::MakeHeader(0x15, 1, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void GetDefaultDaemons(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ cmd_buff[2] = static_cast<u32>(default_daemon_bit_mask);
+ LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void ClearHalfAwakeMacFilter(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ cmd_buff[0] = IPC::MakeHeader(0x17, 1, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ LOG_WARNING(Service_NDM, "(STUBBED) called");
}
void Init() {
diff --git a/src/core/hle/service/ndm/ndm.h b/src/core/hle/service/ndm/ndm.h
index 734730f8c..5c2b968dc 100644
--- a/src/core/hle/service/ndm/ndm.h
+++ b/src/core/hle/service/ndm/ndm.h
@@ -12,10 +12,91 @@ class Interface;
namespace NDM {
+enum class Daemon : u32 {
+ Cec = 0,
+ Boss = 1,
+ Nim = 2,
+ Friend = 3
+};
+
+enum class DaemonMask : u32 {
+ None = 0,
+ Cec = (1 << static_cast<u32>(Daemon::Cec)),
+ Boss = (1 << static_cast<u32>(Daemon::Boss)),
+ Nim = (1 << static_cast<u32>(Daemon::Nim)),
+ Friend = (1 << static_cast<u32>(Daemon::Friend)),
+ Default = Cec | Friend,
+ All = Cec | Boss | Nim | Friend
+};
+
+enum class DaemonStatus : u32 {
+ Busy = 0,
+ Idle = 1,
+ Suspending = 2,
+ Suspended = 3
+};
+
+enum class ExclusiveState : u32 {
+ None = 0,
+ Infrastructure = 1,
+ LocalCommunications = 2,
+ Streetpass = 3,
+ StreetpassData = 4,
+};
+
+/**
+ * NDM::EnterExclusiveState service function
+ * Inputs:
+ * 0 : Header code [0x00010042]
+ * 1 : Exclusive State
+ * 2 : 0x20
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void EnterExclusiveState(Service::Interface* self);
+
+/**
+ * NDM::LeaveExclusiveState service function
+ * Inputs:
+ * 0 : Header code [0x00020002]
+ * 1 : 0x20
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void LeaveExclusiveState(Service::Interface* self);
+
+/**
+ * NDM::QueryExclusiveMode service function
+ * Inputs:
+ * 0 : Header code [0x00030000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Current Exclusive State
+ */
+void QueryExclusiveMode(Service::Interface* self);
+
+/**
+ * NDM::LockState service function
+ * Inputs:
+ * 0 : Header code [0x00040002]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void LockState(Service::Interface* self);
+
+/**
+ * NDM::UnlockState service function
+ * Inputs:
+ * 0 : Header code [0x00050002]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void UnlockState(Service::Interface* self);
+
/**
- * SuspendDaemons
+ * NDM::SuspendDaemons service function
* Inputs:
- * 0 : Command header (0x00020082)
+ * 0 : Header code [0x00060040]
* 1 : Daemon bit mask
* Outputs:
* 1 : Result, 0 on success, otherwise error code
@@ -23,9 +104,9 @@ namespace NDM {
void SuspendDaemons(Service::Interface* self);
/**
- * ResumeDaemons
+ * NDM::ResumeDaemons service function
* Inputs:
- * 0 : Command header (0x00020082)
+ * 0 : Header code [0x00070040]
* 1 : Daemon bit mask
* Outputs:
* 1 : Result, 0 on success, otherwise error code
@@ -33,15 +114,138 @@ void SuspendDaemons(Service::Interface* self);
void ResumeDaemons(Service::Interface* self);
/**
- * OverrideDefaultDaemons
+ * NDM::SuspendScheduler service function
* Inputs:
- * 0 : Command header (0x00020082)
+ * 0 : Header code [0x00080040]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void SuspendScheduler(Service::Interface* self);
+
+/**
+ * NDM::ResumeScheduler service function
+ * Inputs:
+ * 0 : Header code [0x00090000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void ResumeScheduler(Service::Interface* self);
+
+/**
+ * NDM::QueryStatus service function
+ * Inputs:
+ * 0 : Header code [0x000D0040]
+ * 1 : Daemon
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Daemon status
+ */
+void QueryStatus(Service::Interface* self);
+
+/**
+ * NDM::GetDaemonDisableCount service function
+ * Inputs:
+ * 0 : Header code [0x000E0040]
+ * 1 : Daemon
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Current process disable count
+ * 3 : Total disable count
+ */
+void GetDaemonDisableCount(Service::Interface* self);
+
+/**
+ * NDM::GetSchedulerDisableCount service function
+ * Inputs:
+ * 0 : Header code [0x000F0000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Current process disable count
+ * 3 : Total disable count
+ */
+void GetSchedulerDisableCount(Service::Interface* self);
+
+/**
+ * NDM::SetScanInterval service function
+ * Inputs:
+ * 0 : Header code [0x00100040]
+ * 1 : Interval (default = 30)
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void SetScanInterval(Service::Interface* self);
+
+/**
+ * NDM::GetScanInterval service function
+ * Inputs:
+ * 0 : Header code [0x00110000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Interval (default = 30)
+ */
+void GetScanInterval(Service::Interface* self);
+
+/**
+ * NDM::SetRetryInterval service function
+ * Inputs:
+ * 0 : Header code [0x00120040]
+ * 1 : Interval (default = 10)
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void SetRetryInterval(Service::Interface* self);
+
+/**
+ * NDM::GetRetryInterval service function
+ * Inputs:
+ * 0 : Header code [0x00130000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Interval (default = 10)
+ */
+void GetRetryInterval(Service::Interface* self);
+
+
+/**
+ * NDM::OverrideDefaultDaemons service function
+ * Inputs:
+ * 0 : Header code [0x00140040]
* 1 : Daemon bit mask
* Outputs:
* 1 : Result, 0 on success, otherwise error code
*/
void OverrideDefaultDaemons(Service::Interface* self);
+/**
+ * NDM::ResetDefaultDaemons service function
+ * Inputs:
+ * 0 : Header code [0x00150000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void ResetDefaultDaemons(Service::Interface* self);
+
+/**
+ * NDM::GetDefaultDaemons service function
+ * Inputs:
+ * 0 : Header code [0x00160000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Daemon bit mask
+ * Note:
+ * Gets the current default daemon bit mask. The default value is (DAEMONMASK_CEC | DAEMONMASK_FRIENDS)
+ */
+void GetDefaultDaemons(Service::Interface* self);
+
+/**
+ * NDM::ClearHalfAwakeMacFilter service function
+ * Inputs:
+ * 0 : Header code [0x00170000]
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ */
+void ClearHalfAwakeMacFilter(Service::Interface* self);
+
/// Initialize NDM service
void Init();
diff --git a/src/core/hle/service/ndm/ndm_u.cpp b/src/core/hle/service/ndm/ndm_u.cpp
index bf95cc7aa..3ff0744ee 100644
--- a/src/core/hle/service/ndm/ndm_u.cpp
+++ b/src/core/hle/service/ndm/ndm_u.cpp
@@ -9,29 +9,29 @@ namespace Service {
namespace NDM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010042, nullptr, "EnterExclusiveState"},
- {0x00020002, nullptr, "LeaveExclusiveState"},
- {0x00030000, nullptr, "QueryExclusiveMode"},
- {0x00040002, nullptr, "LockState"},
- {0x00050002, nullptr, "UnlockState"},
+ {0x00010042, EnterExclusiveState, "EnterExclusiveState"},
+ {0x00020002, LeaveExclusiveState, "LeaveExclusiveState"},
+ {0x00030000, QueryExclusiveMode, "QueryExclusiveMode"},
+ {0x00040002, LockState, "LockState"},
+ {0x00050002, UnlockState, "UnlockState"},
{0x00060040, SuspendDaemons, "SuspendDaemons"},
{0x00070040, ResumeDaemons, "ResumeDaemons"},
- {0x00080040, nullptr, "DisableWifiUsage"},
- {0x00090000, nullptr, "EnableWifiUsage"},
+ {0x00080040, SuspendScheduler, "SuspendScheduler"},
+ {0x00090000, ResumeScheduler, "ResumeScheduler"},
{0x000A0000, nullptr, "GetCurrentState"},
{0x000B0000, nullptr, "GetTargetState"},
{0x000C0000, nullptr, "<Stubbed>"},
- {0x000D0040, nullptr, "QueryStatus"},
- {0x000E0040, nullptr, "GetDaemonDisableCount"},
- {0x000F0000, nullptr, "GetSchedulerDisableCount"},
- {0x00100040, nullptr, "SetScanInterval"},
- {0x00110000, nullptr, "GetScanInterval"},
- {0x00120040, nullptr, "SetRetryInterval"},
- {0x00130000, nullptr, "GetRetryInterval"},
+ {0x000D0040, QueryStatus, "QueryStatus"},
+ {0x000E0040, GetDaemonDisableCount, "GetDaemonDisableCount"},
+ {0x000F0000, GetSchedulerDisableCount,"GetSchedulerDisableCount"},
+ {0x00100040, SetScanInterval, "SetScanInterval"},
+ {0x00110000, GetScanInterval, "GetScanInterval"},
+ {0x00120040, SetRetryInterval, "SetRetryInterval"},
+ {0x00130000, GetRetryInterval, "GetRetryInterval"},
{0x00140040, OverrideDefaultDaemons, "OverrideDefaultDaemons"},
- {0x00150000, nullptr, "ResetDefaultDaemons"},
- {0x00160000, nullptr, "GetDefaultDaemons"},
- {0x00170000, nullptr, "ClearHalfAwakeMacFilter"},
+ {0x00150000, ResetDefaultDaemons, "ResetDefaultDaemons"},
+ {0x00160000, GetDefaultDaemons, "GetDefaultDaemons"},
+ {0x00170000, ClearHalfAwakeMacFilter, "ClearHalfAwakeMacFilter"},
};
NDM_U_Interface::NDM_U_Interface() {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a9a1a3244..fb2aecbf2 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -859,6 +859,10 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
// TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
// what's the difference between them.
*out = process->heap_used + process->linear_heap_used + process->misc_memory_used;
+ if(*out % Memory::PAGE_SIZE != 0) {
+ LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
+ return ERR_MISALIGNED_SIZE;
+ }
break;
case 1:
case 3:
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index 3dd877fbf..57029c5e8 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -52,8 +52,6 @@ struct Regs {
return content[index];
}
-#undef ASSERT_MEMBER_SIZE
-
};
static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index eaf5c8461..77261eafe 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -4,6 +4,8 @@
#include "settings.h"
+#include "audio_core/audio_core.h"
+
#include "core/gdbstub/gdbstub.h"
#include "video_core/video_core.h"
@@ -20,6 +22,9 @@ void Apply() {
VideoCore::g_hw_renderer_enabled = values.use_hw_renderer;
VideoCore::g_shader_jit_enabled = values.use_shader_jit;
VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution;
+
+ AudioCore::SelectSink(values.sink_id);
+
}
} // namespace
diff --git a/src/core/settings.h b/src/core/settings.h
index d620d8461..ce2a31164 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -6,7 +6,8 @@
#include <string>
#include <array>
-#include <common/file_util.h>
+
+#include "common/common_types.h"
namespace Settings {
@@ -63,6 +64,9 @@ struct Values {
std::string log_filter;
+ // Audio
+ std::string sink_id;
+
// Debugging
bool use_gdbstub;
u16 gdbstub_port;
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h
index a42ccc45f..febf883c8 100644
--- a/src/core/tracer/recorder.h
+++ b/src/core/tracer/recorder.h
@@ -4,6 +4,7 @@
#pragma once
+#include <string>
#include <unordered_map>
#include <vector>
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 76cfd4f7d..581a37897 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -15,7 +15,7 @@ set(SRCS
shader/shader.cpp
shader/shader_interpreter.cpp
swrasterizer.cpp
- utils.cpp
+ vertex_loader.cpp
video_core.cpp
)
@@ -43,6 +43,7 @@ set(HEADERS
shader/shader_interpreter.h
swrasterizer.h
utils.h
+ vertex_loader.h
video_core.h
)
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 3d503486e..2bc747102 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -2,13 +2,24 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <array>
+#include <cstddef>
+
#include <boost/container/static_vector.hpp>
+#include <boost/container/vector.hpp>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/vector_math.h"
#include "video_core/clipper.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
#include "video_core/rasterizer.h"
-#include "video_core/shader/shader_interpreter.h"
+#include "video_core/shader/shader.h"
namespace Pica {
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 97ba8214e..be1a936b2 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -2,25 +2,32 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cmath>
-#include <boost/range/algorithm/fill.hpp>
+#include <array>
+#include <cstddef>
+#include <memory>
+#include <utility>
-#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "common/microprofile.h"
+#include "common/vector_math.h"
-#include "core/settings.h"
#include "core/hle/service/gsp_gpu.h"
#include "core/hw/gpu.h"
+#include "core/memory.h"
+#include "core/tracer/recorder.h"
-#include "video_core/clipper.h"
#include "video_core/command_processor.h"
+#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
#include "video_core/primitive_assembly.h"
+#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
+#include "video_core/shader/shader.h"
+#include "video_core/vertex_loader.h"
#include "video_core/video_core.h"
-#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/shader/shader_interpreter.h"
namespace Pica {
@@ -188,54 +195,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
#if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages());
#endif
-
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
- const auto& attribute_config = regs.vertex_attributes;
- const u32 base_address = attribute_config.GetPhysicalBaseAddress();
-
- // Information about internal vertex attributes
- u32 vertex_attribute_sources[16];
- boost::fill(vertex_attribute_sources, 0xdeadbeef);
- u32 vertex_attribute_strides[16] = {};
- Regs::VertexAttributeFormat vertex_attribute_formats[16] = {};
-
- u32 vertex_attribute_elements[16] = {};
- u32 vertex_attribute_element_size[16] = {};
-
- // Setup attribute data from loaders
- for (int loader = 0; loader < 12; ++loader) {
- const auto& loader_config = attribute_config.attribute_loaders[loader];
-
- u32 offset = 0;
-
- // TODO: What happens if a loader overwrites a previous one's data?
- for (unsigned component = 0; component < loader_config.component_count; ++component) {
- if (component >= 12) {
- LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component);
- continue;
- }
-
- u32 attribute_index = loader_config.GetComponent(component);
- if (attribute_index < 12) {
- int element_size = attribute_config.GetElementSizeInBytes(attribute_index);
- offset = Common::AlignUp(offset, element_size);
- vertex_attribute_sources[attribute_index] = base_address + loader_config.data_offset + offset;
- vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
- vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
- vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
- vertex_attribute_element_size[attribute_index] = element_size;
- offset += attribute_config.GetStride(attribute_index);
- } else if (attribute_index < 16) {
- // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, respectively
- offset = Common::AlignUp(offset, 4);
- offset += (attribute_index - 11) * 4;
- } else {
- UNREACHABLE(); // This is truly unreachable due to the number of bits for each component
- }
- }
- }
+ // Processes information about internal vertex attributes to figure out how a vertex is loaded.
+ // Later, these can be compiled and cached.
+ VertexLoader loader;
+ const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress();
+ loader.Setup(regs);
// Load vertices
bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed));
@@ -259,32 +226,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
}
}
- class {
- /// Combine overlapping and close ranges
- void SimplifyRanges() {
- for (auto it = ranges.begin(); it != ranges.end(); ++it) {
- // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
- auto it2 = std::next(it);
- while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
- it->second = std::max(it->second, it2->first + it2->second - it->first);
- it2 = ranges.erase(it2);
- }
- }
- }
-
- public:
- /// Record a particular memory access in the list
- void AddAccess(u32 paddr, u32 size) {
- // Create new range or extend existing one
- ranges[paddr] = std::max(ranges[paddr], size);
-
- // Simplify ranges...
- SimplifyRanges();
- }
-
- /// Map of accessed ranges (mapping start address to range size)
- std::map<u32, u32> ranges;
- } memory_accesses;
+ DebugUtils::MemoryAccessTracker memory_accesses;
// Simple circular-replacement vertex cache
// The size has been tuned for optimal balance between hit-rate and the cost of lookup
@@ -328,60 +270,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (!vertex_cache_hit) {
// Initialize data for the current vertex
Shader::InputVertex input;
-
- for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
- if (vertex_attribute_elements[i] != 0) {
- // Default attribute values set if array elements have < 4 components. This
- // is *not* carried over from the default attribute settings even if they're
- // enabled for this attribute.
- static const float24 zero = float24::FromFloat32(0.0f);
- static const float24 one = float24::FromFloat32(1.0f);
- input.attr[i] = Math::Vec4<float24>(zero, zero, zero, one);
-
- // Load per-vertex data from the loader arrays
- for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
- u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
- const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
-
- if (g_debug_context && Pica::g_debug_context->recorder) {
- memory_accesses.AddAccess(source_addr,
- (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
- : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
- }
-
- const float srcval =
- (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *reinterpret_cast<const s8*>(srcdata) :
- (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *reinterpret_cast<const u8*>(srcdata) :
- (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *reinterpret_cast<const s16*>(srcdata) :
- *reinterpret_cast<const float*>(srcdata);
-
- input.attr[i][comp] = float24::FromFloat32(srcval);
- LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f",
- comp, i, vertex, index,
- attribute_config.GetPhysicalBaseAddress(),
- vertex_attribute_sources[i] - base_address,
- vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
- input.attr[i][comp].ToFloat32());
- }
- } else if (attribute_config.IsDefaultAttribute(i)) {
- // Load the default attribute if we're configured to do so
- input.attr[i] = g_state.vs.default_attributes[i];
- LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
- i, vertex, index,
- input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
- input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
- } else {
- // TODO(yuriks): In this case, no data gets loaded and the vertex
- // remains with the last value it had. This isn't currently maintained
- // as global state, however, and so won't work in Citra yet.
- }
- }
+ loader.LoadVertex(base_address, index, vertex, input, memory_accesses);
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);
// Send to vertex shader
- output = Shader::Run(shader_unit, input, attribute_config.GetNumTotalAttributes());
+ output = Shader::Run(shader_unit, input, loader.GetNumTotalAttributes());
if (is_indexed) {
vertex_cache[vertex_cache_pos] = output;
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 178a566f7..fb20f81dd 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -4,35 +4,41 @@
#include <algorithm>
#include <condition_variable>
+#include <cstdint>
#include <cstring>
#include <fstream>
-#include <list>
#include <map>
#include <mutex>
+#include <stdexcept>
#include <string>
#ifdef HAVE_PNG
#include <png.h>
+#include <setjmp.h>
#endif
+#include <nihstro/bit_field.h>
#include <nihstro/float24.h>
#include <nihstro/shader_binary.h>
#include "common/assert.h"
+#include "common/bit_field.h"
#include "common/color.h"
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/vector_math.h"
-#include "core/settings.h"
-
+#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
+#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
+#include "video_core/shader/shader.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
-#include "video_core/debug_utils/debug_utils.h"
using nihstro::DVLBHeader;
using nihstro::DVLEHeader;
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 56f9bd958..be2d0301a 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -4,23 +4,33 @@
#pragma once
+#include <algorithm>
#include <array>
#include <condition_variable>
+#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <mutex>
+#include <string>
+#include <utility>
#include <vector>
+#include "common/common_types.h"
#include "common/vector_math.h"
-#include "core/tracer/recorder.h"
-
#include "video_core/pica.h"
-#include "video_core/shader/shader.h"
+
+namespace CiTrace {
+class Recorder;
+}
namespace Pica {
+namespace Shader {
+struct ShaderSetup;
+}
+
class DebugContext {
public:
enum class Event {
@@ -216,6 +226,36 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data);
void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages);
+/**
+ * Used in the vertex loader to merge access records. TODO: Investigate if actually useful.
+ */
+class MemoryAccessTracker {
+ /// Combine overlapping and close ranges
+ void SimplifyRanges() {
+ for (auto it = ranges.begin(); it != ranges.end(); ++it) {
+ // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
+ auto it2 = std::next(it);
+ while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
+ it->second = std::max(it->second, it2->first + it2->second - it->first);
+ it2 = ranges.erase(it2);
+ }
+ }
+ }
+
+public:
+ /// Record a particular memory access in the list
+ void AddAccess(u32 paddr, u32 size) {
+ // Create new range or extend existing one
+ ranges[paddr] = std::max(ranges[paddr], size);
+
+ // Simplify ranges...
+ SimplifyRanges();
+ }
+
+ /// Map of accessed ranges (mapping start address to range size)
+ std::map<u32, u32> ranges;
+};
+
} // namespace
} // namespace
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index ccbaf071b..be82cf4b5 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -3,10 +3,13 @@
// Refer to the license.txt file included.
#include <cstring>
+#include <iterator>
#include <unordered_map>
+#include <utility>
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/primitive_assembly.h"
#include "video_core/shader/shader.h"
namespace Pica {
@@ -480,7 +483,7 @@ std::string Regs::GetCommandName(int index) {
static std::unordered_map<u32, const char*> map;
if (map.empty()) {
- map.insert(begin(register_names), end(register_names));
+ map.insert(std::begin(register_names), std::end(register_names));
}
// Return empty string if no match is found
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index cf130d7f8..5891fb72a 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -5,10 +5,13 @@
#pragma once
#include <array>
-#include <cmath>
#include <cstddef>
#include <string>
+#ifndef _MSC_VER
+#include <type_traits> // for std::enable_if
+#endif
+
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
@@ -16,8 +19,6 @@
#include "common/vector_math.h"
#include "common/logging/log.h"
-#include "pica_types.h"
-
namespace Pica {
// Returns index corresponding to the Regs member labeled by field_name
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 323290054..bbecad850 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -4,6 +4,11 @@
#pragma once
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
#include "video_core/pica.h"
#include "video_core/primitive_assembly.h"
#include "video_core/shader/shader.h"
diff --git a/src/video_core/pica_types.h b/src/video_core/pica_types.h
index ecf45654b..3b7bfbdca 100644
--- a/src/video_core/pica_types.h
+++ b/src/video_core/pica_types.h
@@ -4,6 +4,7 @@
#pragma once
+#include <cmath>
#include <cstring>
#include "common/common_types.h"
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index ff3e2b862..68ea3c08a 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -6,8 +6,7 @@
#include "video_core/pica.h"
#include "video_core/primitive_assembly.h"
-#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/shader/shader_interpreter.h"
+#include "video_core/shader/shader.h"
namespace Pica {
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 9cf77b1f2..df67b9081 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -3,22 +3,28 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <array>
#include <cmath>
+#include "common/assert.h"
+#include "common/bit_field.h"
#include "common/color.h"
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/microprofile.h"
+#include "common/vector_math.h"
#include "core/memory.h"
#include "core/hw/gpu.h"
+#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
#include "video_core/rasterizer.h"
#include "video_core/utils.h"
-#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/shader/shader_interpreter.h"
+#include "video_core/shader/shader.h"
namespace Pica {
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index ccd497de0..3f451e062 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -2,10 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <atomic>
#include <memory>
-#include "core/settings.h"
-
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#include "video_core/swrasterizer.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a8c775c80..519d81aeb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,27 +2,28 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cstring>
#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
#include <glad/glad.h>
+#include "common/assert.h"
#include "common/color.h"
-#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
-#include "common/microprofile.h"
+#include "common/vector_math.h"
-#include "core/memory.h"
-#include "core/settings.h"
#include "core/hw/gpu.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
-#include "video_core/utils.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/pica_to_gl.h"
+#include "video_core/renderer_opengl/renderer_opengl.h"
static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
@@ -812,6 +813,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConf
if (wrap_s == TextureConfig::ClampToBorder || wrap_t == TextureConfig::ClampToBorder) {
if (border_color != config.border_color.raw) {
+ border_color = config.border_color.raw;
auto gl_color = PicaToGL::ColorRGBA8(border_color);
glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, gl_color.data());
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 8d6177e88..63ff7716d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -4,23 +4,33 @@
#pragma once
+#include <array>
#include <cstddef>
#include <cstring>
#include <memory>
#include <vector>
#include <unordered_map>
+#include <glad/glad.h>
+
+#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/hash.h"
+#include "common/vector_math.h"
+
+#include "core/hw/gpu.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
+#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/pica_to_gl.h"
-#include "video_core/renderer_opengl/renderer_opengl.h"
-#include "video_core/shader/shader_interpreter.h"
+#include "video_core/shader/shader.h"
+
+struct ScreenInfo;
/**
* This struct contains all state used to generate the GLSL shader program that emulates the current
@@ -39,36 +49,17 @@ struct PicaShaderConfig {
res.alpha_test_func = regs.output_merger.alpha_test.enable ?
regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
- // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling
- // the GetTevStages() function) because BitField explicitly disables copies.
-
- res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw;
- res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw;
- res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw;
- res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw;
- res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw;
- res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw;
-
- res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw;
- res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw;
- res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw;
- res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw;
- res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw;
- res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw;
-
- res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw;
- res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw;
- res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw;
- res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw;
- res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw;
- res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw;
-
- res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw;
- res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw;
- res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw;
- res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw;
- res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw;
- res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw;
+ // Copy tev stages
+ const auto& tev_stages = regs.GetTevStages();
+ DEBUG_ASSERT(res.tev_stages.size() == tev_stages.size());
+ for (size_t i = 0; i < tev_stages.size(); i++) {
+ const auto& tev_stage = tev_stages[i];
+ res.tev_stages[i].sources_raw = tev_stage.sources_raw;
+ res.tev_stages[i].modifiers_raw = tev_stage.modifiers_raw;
+ res.tev_stages[i].ops_raw = tev_stage.ops_raw;
+ res.tev_stages[i].const_color = tev_stage.const_color;
+ res.tev_stages[i].scales_raw = tev_stage.scales_raw;
+ }
res.combiner_buffer_input =
regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 55c2fb283..7efd0038a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -2,10 +2,19 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <atomic>
+#include <cstring>
+#include <iterator>
#include <unordered_set>
+#include <utility>
+#include <vector>
+#include <glad/glad.h>
+
+#include "common/bit_field.h"
#include "common/emu_window.h"
-#include "common/hash.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/vector_math.h"
@@ -15,7 +24,7 @@
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica_state.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
-#include "video_core/renderer_opengl/pica_to_gl.h"
+#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 893d51138..225596415 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -4,20 +4,26 @@
#pragma once
-#include <map>
+#include <array>
#include <memory>
#include <set>
+#include <tuple>
#include <boost/icl/interval_map.hpp>
+#include <glad/glad.h>
-#include "common/math_util.h"
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "core/hw/gpu.h"
#include "video_core/pica.h"
-#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
-#include "video_core/renderer_opengl/gl_state.h"
+
+namespace MathUtil {
+template <class T> struct Rectangle;
+}
struct CachedSurface;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 646b4eaaf..9011caa39 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -2,9 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+#include <cstddef>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/logging/log.h"
+
#include "video_core/pica.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
+#include "video_core/renderer_opengl/gl_shader_util.h"
using Pica::Regs;
using TevStageConfig = Regs::TevStageConfig;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 0ca9d2879..3eb07d57a 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -6,7 +6,7 @@
#include <string>
-#include "video_core/renderer_opengl/gl_rasterizer.h"
+struct PicaShaderConfig;
namespace GLShader {
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index e3f7a5868..dded3db46 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -2,9 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
#include <vector>
+#include <glad/glad.h>
+
#include "common/logging/log.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f04bdd8c5..02cd9f417 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "video_core/pica.h"
-#include "video_core/renderer_opengl/gl_resource_manager.h"
+#include <glad/glad.h>
+
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
+
#include "video_core/renderer_opengl/gl_state.h"
OpenGLState OpenGLState::cur_state;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 0f72e9004..24f20e47c 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -5,7 +5,6 @@
#pragma once
#include <glad/glad.h>
-#include <memory>
class OpenGLState {
public:
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index fd3617d77..976d1f364 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -4,9 +4,16 @@
#pragma once
+#include <array>
+#include <cstddef>
+
#include <glad/glad.h>
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/logging/log.h"
#include "video_core/pica.h"
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8f907593f..0e9a0be8b 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -5,23 +5,28 @@
#include <algorithm>
#include <cstddef>
#include <cstdlib>
+#include <memory>
+
+#include <glad/glad.h>
#include "common/assert.h"
+#include "common/bit_field.h"
#include "common/emu_window.h"
#include "common/logging/log.h"
#include "common/profiler_reporting.h"
+#include "common/synchronized_wrapper.h"
-#include "core/memory.h"
-#include "core/settings.h"
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
+#include "core/memory.h"
+#include "core/settings.h"
+#include "core/tracer/recorder.h"
-#include "video_core/video_core.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/renderer_opengl/gl_rasterizer.h"
-#include "video_core/renderer_opengl/gl_shader_util.h"
+#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
+#include "video_core/video_core.h"
static const char vertex_shader[] = R"(
#version 150 core
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 5ca5255ac..00e1044ab 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -8,6 +8,9 @@
#include <glad/glad.h>
+#include "common/common_types.h"
+#include "common/math_util.h"
+
#include "core/hw/gpu.h"
#include "video_core/renderer_base.h"
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 043e99190..356d87f13 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -2,26 +2,30 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <memory>
+#include <atomic>
+#include <cmath>
+#include <cstring>
#include <unordered_map>
+#include <utility>
#include <boost/range/algorithm/fill.hpp>
+#include "common/bit_field.h"
#include "common/hash.h"
+#include "common/logging/log.h"
#include "common/microprofile.h"
-#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
-#include "video_core/video_core.h"
-
-#include "shader.h"
-#include "shader_interpreter.h"
+#include "video_core/shader/shader.h"
+#include "video_core/shader/shader_interpreter.h"
#ifdef ARCHITECTURE_x86_64
-#include "shader_jit_x64.h"
+#include "video_core/shader/shader_jit_x64.h"
#endif // ARCHITECTURE_x86_64
+#include "video_core/video_core.h"
+
namespace Pica {
namespace Shader {
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 9c5bd97bd..56b83bfeb 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -4,17 +4,23 @@
#pragma once
+#include <array>
+#include <cstddef>
+#include <memory>
+#include <type_traits>
#include <vector>
#include <boost/container/static_vector.hpp>
-#include <nihstro/shader_binary.h>
+#include <nihstro/shader_bytecode.h>
+#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/vector_math.h"
#include "video_core/pica.h"
+#include "video_core/pica_types.h"
using nihstro::RegisterType;
using nihstro::SourceRegister;
@@ -25,7 +31,7 @@ namespace Pica {
namespace Shader {
struct InputVertex {
- Math::Vec4<float24> attr[16];
+ alignas(16) Math::Vec4<float24> attr[16];
};
struct OutputVertex {
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 9b978583e..7710f7fbc 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -2,12 +2,20 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <array>
+#include <cmath>
#include <numeric>
+
#include <nihstro/shader_bytecode.h>
-#include "common/file_util.h"
-#include "video_core/pica.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/vector_math.h"
+
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
#include "video_core/shader/shader.h"
#include "video_core/shader/shader_interpreter.h"
diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h
index 294bca50e..6048cdf3a 100644
--- a/src/video_core/shader/shader_interpreter.h
+++ b/src/video_core/shader/shader_interpreter.h
@@ -4,12 +4,12 @@
#pragma once
-#include "video_core/shader/shader.h"
-
namespace Pica {
namespace Shader {
+template <bool Debug> struct UnitState;
+
template<bool Debug>
void RunInterpreter(UnitState<Debug>& state);
diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp
index b7747fa42..99f6c51eb 100644
--- a/src/video_core/shader/shader_jit_x64.cpp
+++ b/src/video_core/shader/shader_jit_x64.cpp
@@ -3,8 +3,15 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <smmintrin.h>
+#include <cmath>
+#include <cstdint>
+#include <xmmintrin.h>
+#include <nihstro/shader_bytecode.h>
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "common/vector_math.h"
#include "common/x64/abi.h"
#include "common/x64/cpu_detect.h"
#include "common/x64/emitter.h"
@@ -13,6 +20,7 @@
#include "shader_jit_x64.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
namespace Pica {
diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h
index cd6280ade..30aa7ff30 100644
--- a/src/video_core/shader/shader_jit_x64.h
+++ b/src/video_core/shader/shader_jit_x64.h
@@ -4,14 +4,17 @@
#pragma once
+#include <array>
+#include <cstddef>
#include <utility>
#include <vector>
#include <nihstro/shader_bytecode.h>
+#include "common/bit_set.h"
+#include "common/common_types.h"
#include "common/x64/emitter.h"
-#include "video_core/pica.h"
#include "video_core/shader/shader.h"
using nihstro::Instruction;
diff --git a/src/video_core/swrasterizer.h b/src/video_core/swrasterizer.h
index 090f899bc..0a028b774 100644
--- a/src/video_core/swrasterizer.h
+++ b/src/video_core/swrasterizer.h
@@ -8,6 +8,12 @@
#include "video_core/rasterizer_interface.h"
+namespace Pica {
+namespace Shader {
+struct OutputVertex;
+}
+}
+
namespace VideoCore {
class SWRasterizer : public RasterizerInterface {
diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp
deleted file mode 100644
index 6e1ff5cf4..000000000
--- a/src/video_core/utils.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <cstdio>
-#include <cstring>
-
-#include "video_core/utils.h"
-
-namespace VideoCore {
-
-/**
- * Dumps a texture to TGA
- * @param filename String filename to dump texture to
- * @param width Width of texture in pixels
- * @param height Height of texture in pixels
- * @param raw_data Raw RGBA8 texture data to dump
- * @todo This should be moved to some general purpose/common code
- */
-void DumpTGA(std::string filename, short width, short height, u8* raw_data) {
- TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0};
- FILE* fout = fopen(filename.c_str(), "wb");
-
- fwrite(&hdr, sizeof(TGAHeader), 1, fout);
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- putc(raw_data[(3 * (y * width)) + (3 * x) + 0], fout); // b
- putc(raw_data[(3 * (y * width)) + (3 * x) + 1], fout); // g
- putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r
- }
- }
-
- fclose(fout);
-}
-} // namespace
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 4fa60a10e..7ce83a055 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -4,37 +4,10 @@
#pragma once
-#include <string>
-
#include "common/common_types.h"
namespace VideoCore {
-/// Structure for the TGA texture format (for dumping)
-struct TGAHeader {
- char idlength;
- char colormaptype;
- char datatypecode;
- short int colormaporigin;
- short int colormaplength;
- short int x_origin;
- short int y_origin;
- short width;
- short height;
- char bitsperpixel;
- char imagedescriptor;
-};
-
-/**
- * Dumps a texture to TGA
- * @param filename String filename to dump texture to
- * @param width Width of texture in pixels
- * @param height Height of texture in pixels
- * @param raw_data Raw RGBA8 texture data to dump
- * @todo This should be moved to some general purpose/common code
- */
-void DumpTGA(std::string filename, short width, short height, u8* raw_data);
-
/**
* Interleave the lower 3 bits of each coordinate to get the intra-block offsets, which are
* arranged in a Z-order curve. More details on the bit manipulation at:
diff --git a/src/video_core/vertex_loader.cpp b/src/video_core/vertex_loader.cpp
new file mode 100644
index 000000000..21ae52949
--- /dev/null
+++ b/src/video_core/vertex_loader.cpp
@@ -0,0 +1,140 @@
+#include <memory>
+
+#include <boost/range/algorithm/fill.hpp>
+
+#include "common/assert.h"
+#include "common/alignment.h"
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/vector_math.h"
+
+#include "core/memory.h"
+
+#include "video_core/debug_utils/debug_utils.h"
+#include "video_core/pica.h"
+#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
+#include "video_core/shader/shader.h"
+#include "video_core/vertex_loader.h"
+
+namespace Pica {
+
+void VertexLoader::Setup(const Pica::Regs& regs) {
+ const auto& attribute_config = regs.vertex_attributes;
+ num_total_attributes = attribute_config.GetNumTotalAttributes();
+
+ boost::fill(vertex_attribute_sources, 0xdeadbeef);
+
+ for (int i = 0; i < 16; i++) {
+ vertex_attribute_is_default[i] = attribute_config.IsDefaultAttribute(i);
+ }
+
+ // Setup attribute data from loaders
+ for (int loader = 0; loader < 12; ++loader) {
+ const auto& loader_config = attribute_config.attribute_loaders[loader];
+
+ u32 offset = 0;
+
+ // TODO: What happens if a loader overwrites a previous one's data?
+ for (unsigned component = 0; component < loader_config.component_count; ++component) {
+ if (component >= 12) {
+ LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component);
+ continue;
+ }
+
+ u32 attribute_index = loader_config.GetComponent(component);
+ if (attribute_index < 12) {
+ offset = Common::AlignUp(offset, attribute_config.GetElementSizeInBytes(attribute_index));
+ vertex_attribute_sources[attribute_index] = loader_config.data_offset + offset;
+ vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
+ vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
+ vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
+ offset += attribute_config.GetStride(attribute_index);
+ } else if (attribute_index < 16) {
+ // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, respectively
+ offset = Common::AlignUp(offset, 4);
+ offset += (attribute_index - 11) * 4;
+ } else {
+ UNREACHABLE(); // This is truly unreachable due to the number of bits for each component
+ }
+ }
+ }
+}
+
+void VertexLoader::LoadVertex(u32 base_address, int index, int vertex, Shader::InputVertex& input, DebugUtils::MemoryAccessTracker& memory_accesses) {
+ for (int i = 0; i < num_total_attributes; ++i) {
+ if (vertex_attribute_elements[i] != 0) {
+ // Load per-vertex data from the loader arrays
+ u32 source_addr = base_address + vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex;
+
+ if (g_debug_context && Pica::g_debug_context->recorder) {
+ memory_accesses.AddAccess(source_addr, vertex_attribute_elements[i] * (
+ (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
+ : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1));
+ }
+
+ switch (vertex_attribute_formats[i]) {
+ case Regs::VertexAttributeFormat::BYTE:
+ {
+ const s8* srcdata = reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
+ }
+ break;
+ }
+ case Regs::VertexAttributeFormat::UBYTE:
+ {
+ const u8* srcdata = reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
+ }
+ break;
+ }
+ case Regs::VertexAttributeFormat::SHORT:
+ {
+ const s16* srcdata = reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
+ }
+ break;
+ }
+ case Regs::VertexAttributeFormat::FLOAT:
+ {
+ const float* srcdata = reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
+ }
+ break;
+ }
+ }
+
+ // Default attribute values set if array elements have < 4 components. This
+ // is *not* carried over from the default attribute settings even if they're
+ // enabled for this attribute.
+ for (unsigned int comp = vertex_attribute_elements[i]; comp < 4; ++comp) {
+ input.attr[i][comp] = comp == 3 ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f);
+ }
+
+ LOG_TRACE(HW_GPU, "Loaded %d components of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f %f %f %f",
+ vertex_attribute_elements[i], i, vertex, index,
+ base_address,
+ vertex_attribute_sources[i],
+ vertex_attribute_strides[i] * vertex,
+ input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
+ } else if (vertex_attribute_is_default[i]) {
+ // Load the default attribute if we're configured to do so
+ input.attr[i] = g_state.vs.default_attributes[i];
+ LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
+ i, vertex, index,
+ input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
+ input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
+ } else {
+ // TODO(yuriks): In this case, no data gets loaded and the vertex
+ // remains with the last value it had. This isn't currently maintained
+ // as global state, however, and so won't work in Citra yet.
+ }
+ }
+}
+
+} // namespace Pica
diff --git a/src/video_core/vertex_loader.h b/src/video_core/vertex_loader.h
new file mode 100644
index 000000000..becf5a403
--- /dev/null
+++ b/src/video_core/vertex_loader.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "common/common_types.h"
+
+#include "video_core/pica.h"
+
+namespace Pica {
+
+namespace DebugUtils {
+class MemoryAccessTracker;
+}
+
+namespace Shader {
+class InputVertex;
+}
+
+class VertexLoader {
+public:
+ void Setup(const Pica::Regs& regs);
+ void LoadVertex(u32 base_address, int index, int vertex, Shader::InputVertex& input, DebugUtils::MemoryAccessTracker& memory_accesses);
+
+ int GetNumTotalAttributes() const { return num_total_attributes; }
+
+private:
+ u32 vertex_attribute_sources[16];
+ u32 vertex_attribute_strides[16] = {};
+ Regs::VertexAttributeFormat vertex_attribute_formats[16] = {};
+ u32 vertex_attribute_elements[16] = {};
+ bool vertex_attribute_is_default[16];
+ int num_total_attributes;
+};
+
+} // namespace Pica
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 855286173..c9975876d 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -4,12 +4,8 @@
#include <memory>
-#include "common/emu_window.h"
#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/settings.h"
-
#include "video_core/pica.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"