Compare commits

..

42 Commits

Author SHA1 Message Date
Lioncash
296e68fd43 service/prepo: Add missing header guard 2018-07-18 19:43:28 -04:00
bunnei
924c473bb3 Merge pull request #683 from DarkLordZach/touch
Touchscreen Support
2018-07-18 14:29:16 -07:00
Zach Hilman
c337272ca9 Fill in more fields in TouchScreenEntryTouch 2018-07-18 16:33:11 -04:00
Zach Hilman
f2f368014e Single touch support 2018-07-18 14:06:33 -04:00
bunnei
3d1e8f750c Merge pull request #681 from lioncash/const
game_list: Make containsAllWords a const member function
2018-07-18 10:02:58 -07:00
bunnei
e3da9fc367 Merge pull request #682 from lioncash/telemetry
Telemetry: Minor changes
2018-07-18 10:02:46 -07:00
bunnei
24a55bba42 Merge pull request #679 from lioncash/ctor
game_list: Remove unnecessary QString initialization in KeyReleaseEater
2018-07-17 22:18:39 -07:00
bunnei
b87a71b3fe Merge pull request #678 from lioncash/astc
astc: Minor changes
2018-07-17 22:06:20 -07:00
Lioncash
c65a8fafa0 telemetry: Remove unnecessary Field constructor
We can just take the value parameter by value which allows both moving
into it, and copies at the same time, depending on the calling code.
2018-07-18 00:32:35 -04:00
Lioncash
0aebe6b3d5 telemetry: Make operator== and operator!= const member functions of Field
These operators don't modify internal class state, so they can be made
const member functions. While we're at it, drop the unnecessary inline
keywords. Member functions that are defined in the class declaration are
already inline by default.
2018-07-18 00:28:47 -04:00
bunnei
7c3cc08957 Merge pull request #677 from bunnei/crop-fb
Implement buffer cropping and default to handheld mode
2018-07-17 21:26:35 -07:00
Lioncash
3575d367a4 telemetry: Default copy/move constructors and assignment operators
This provides the equivalent behavior, but without as much boilerplate.
While we're at it, explicitly default the move constructor, since we
have a move-assignment operator defined.
2018-07-18 00:25:12 -04:00
Lioncash
f4b98a857b game_list: Upper-case containsAllWords to ContainsAllWords()
This makes it consistent with most of the other private utility
functions.
2018-07-18 00:15:48 -04:00
Lioncash
c8f3fc9a4b game_list: Make containsAllWords a const member function
This doesn't actually modify the internal class state, so it can be a
const member function. While we're at it, amend the function to take
its arguments by const reference.
2018-07-18 00:13:04 -04:00
Lioncash
f4c69149f9 game_list: Remove unnecessary QString initialization in KeyReleaseEater
QString initializes to an empty string by default, so this does nothing
meaningful. While we're at it, use a constructor initializer list for
initializing the gamelist member variable.
2018-07-18 00:07:47 -04:00
Lioncash
6a03badcbc astc: Initialize vector size directly in Decompress
There's no need to perform a separate resize.
2018-07-17 23:58:14 -04:00
Lioncash
0f148548f3 astc: Mark functions as internally linked where applicable 2018-07-17 23:58:14 -04:00
Lioncash
c5803e30d3 astc: const-correctness changes where applicable
A few member functions didn't actually modify class state, so these can
be amended as necessary.
2018-07-17 23:58:14 -04:00
Lioncash
e3fadb9616 astc: Delete Bits' copy contstructor and assignment operator
This also potentially avoids warnings, considering the copy assignment
operator is supposed to have a return value.
2018-07-17 23:58:14 -04:00
Lioncash
4cd52a34b9 astc: In-class initialize member variables where appropriate 2018-07-17 23:58:10 -04:00
bunnei
03c2d049d4 settings: Turn docked mode off by default. 2018-07-17 22:52:25 -04:00
bunnei
49e5de9f03 vi: Change TransactionId::CancelBuffer to LOG_CRITICAL. 2018-07-17 22:47:35 -04:00
bunnei
0d1a99edf6 vi: Fix size for ListDisplays default display. 2018-07-17 22:18:14 -04:00
bunnei
c3dd456d51 vi: Partially implement buffer crop parameters. 2018-07-17 20:13:17 -04:00
bunnei
8e28af6f89 Merge pull request #675 from Subv/stencil
GPU: Added register definitions for the stencil parameters.
2018-07-17 15:53:00 -07:00
Subv
3d3b10adc7 GPU: Added register definitions for the stencil parameters. 2018-07-17 15:00:21 -05:00
Zach Hilman
69bfe075b5 General Filesystem and Save Data Fixes (#670) 2018-07-17 12:42:15 -07:00
bunnei
88a3140c9b Merge pull request #671 from MerryMage/clear-exclusive-state
scheduler: Clear exclusive state when switching contexts
2018-07-17 07:33:32 -07:00
bunnei
519035db3d Merge pull request #672 from SciresM/to_address_fix
svc:: Fix bug in svcWaitForAddress
2018-07-17 07:32:42 -07:00
bunnei
5f119bed56 Merge pull request #673 from bunnei/fix-buffer-queue-evt
nvflinger: Fix for BufferQueue event handling.
2018-07-17 07:07:57 -07:00
bunnei
170e19d4ea nvflinger: Fix for BufferQueue event handling. 2018-07-17 00:26:23 -04:00
Michael Scire
3b885691a1 Kernel/Arbiter: Fix bug in WaitIfLessThan 2018-07-16 20:55:53 -06:00
MerryMage
56cc1c11ec scheduler: Clear exclusive state when switching contexts 2018-07-16 11:24:00 +01:00
bunnei
f00ca69a81 Merge pull request #669 from lioncash/dynarmic
externals: Update dynarmic to dfdec79
2018-07-15 18:36:32 -07:00
Lioncash
0722adb471 externals: Update dynarmic to dfdec79 2018-07-15 16:11:45 -04:00
bunnei
068668780c Merge pull request #668 from jroweboy/controller-lag
HID: Update controllers less often
2018-07-15 13:06:28 -07:00
bunnei
04b9cde4f5 Merge pull request #664 from jroweboy/logging-stuff
Minor logging improvements
2018-07-15 12:58:52 -07:00
James Rowe
7d209b3c9f HID: Update controllers less often 2018-07-15 13:47:41 -06:00
James Rowe
497b81558e Logging: Dump all logs in the queue on close in debug mode 2018-07-15 13:02:09 -06:00
bunnei
98762e9601 Merge pull request #666 from bunnei/g8r8
gl_rasterizer_cache: Implement texture format G8R8.
2018-07-15 10:09:36 -07:00
bunnei
3a96670f2d gl_rasterizer_cache: Implement texture format G8R8. 2018-07-15 01:33:42 -04:00
James Rowe
6daebaaa57 Logging: Don't lock the queue for the duration of the write 2018-07-14 11:57:13 -06:00
35 changed files with 274 additions and 183 deletions

View File

@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <memory>
#include <thread>
@@ -83,8 +84,10 @@ private:
}
};
while (true) {
std::unique_lock<std::mutex> lock(message_mutex);
message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
{
std::unique_lock<std::mutex> lock(message_mutex);
message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
}
if (!running) {
break;
}
@@ -92,7 +95,7 @@ private:
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
constexpr int MAX_LOGS_TO_WRITE = 100;
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
int logs_written = 0;
while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
write_logs(entry);
@@ -282,4 +285,4 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
Impl::Instance().PushEntry(std::move(entry));
}
} // namespace Log
} // namespace Log

View File

@@ -94,4 +94,11 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
}
bool Filter::IsDebug() const {
return std::any_of(class_levels.begin(), class_levels.end(), [](const Level& l) {
return static_cast<u8>(l) <= static_cast<u8>(Level::Debug);
});
}
} // namespace Log

View File

@@ -47,6 +47,9 @@ public:
/// Matches class/level combination against the filter, returning true if it passed.
bool CheckMessage(Class log_class, Level level) const;
/// Returns true if any logging classes are set to debug
bool IsDebug() const;
private:
std::array<Level, (size_t)Class::Count> class_levels;
};

View File

@@ -52,27 +52,14 @@ public:
template <typename T>
class Field : public FieldInterface {
public:
Field(FieldType type, std::string name, const T& value)
: name(std::move(name)), type(type), value(value) {}
Field(FieldType type, std::string name, T&& value)
Field(FieldType type, std::string name, T value)
: name(std::move(name)), type(type), value(std::move(value)) {}
Field(const Field& other) : Field(other.type, other.name, other.value) {}
Field(const Field&) = default;
Field& operator=(const Field&) = default;
Field& operator=(const Field& other) {
type = other.type;
name = other.name;
value = other.value;
return *this;
}
Field& operator=(Field&& other) {
type = other.type;
name = std::move(other.name);
value = std::move(other.value);
return *this;
}
Field(Field&&) = default;
Field& operator=(Field&& other) = default;
void Accept(VisitorInterface& visitor) const override;
@@ -94,11 +81,11 @@ public:
return value;
}
inline bool operator==(const Field<T>& other) {
bool operator==(const Field& other) const {
return (type == other.type) && (name == other.name) && (value == other.value);
}
inline bool operator!=(const Field<T>& other) {
bool operator!=(const Field& other) const {
return !(*this == other);
}

View File

@@ -116,6 +116,8 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
};

View File

@@ -226,6 +226,10 @@ void ARM_Dynarmic::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic::ClearExclusiveState() {
jit->ClearExclusiveState();
}
void ARM_Dynarmic::PageTableChanged() {
jit = MakeJit(cb);
current_page_table = Memory::GetCurrentPageTable();

View File

@@ -39,6 +39,7 @@ public:
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void PageTableChanged() override;

View File

@@ -263,6 +263,8 @@ void ARM_Unicorn::PrepareReschedule() {
CHECKED(uc_emu_stop(uc));
}
void ARM_Unicorn::ClearExclusiveState() {}
void ARM_Unicorn::ClearInstructionCache() {}
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {

View File

@@ -31,6 +31,7 @@ public:
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ExecuteInstructions(int num_instructions);
void Run() override;
void Step() override;

View File

@@ -115,7 +115,7 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
s32 updated_value;
if (waiting_threads.size() == 0) {
updated_value = value - 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value + 1;
} else {
updated_value = value;
@@ -140,7 +140,9 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool
s32 cur_value = static_cast<s32>(Memory::Read32(address));
if (cur_value < value) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
if (should_decrement) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
}
} else {
return ERR_INVALID_STATE;
}

View File

@@ -29,7 +29,8 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
const std::string& reason, u64 timeout,
WakeupCallback&& callback) {
WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->wakeup_callback =
@@ -41,7 +42,12 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
return true;
};
auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
if (!event) {
// Create event if not provided
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
}
event->Clear();
thread->status = THREADSTATUS_WAIT_HLE_EVENT;
thread->wait_objects = {event};
event->AddWaitingThread(thread);

View File

@@ -118,10 +118,12 @@ public:
* @param callback Callback to be invoked when the thread is resumed. This callback must write
* the entire command response once again, regardless of the state of it before this function
* was called.
* @param event Event to use to wake up the thread. If unspecified, an event will be created.
* @returns Event that when signaled will resume the thread and call the callback function.
*/
SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
u64 timeout, WakeupCallback&& callback);
u64 timeout, WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event = nullptr);
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);

View File

@@ -85,6 +85,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
cpu_core->LoadContext(new_thread->context);
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
cpu_core->ClearExclusiveState();
} else {
current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because

View File

@@ -5,6 +5,7 @@
#include <atomic>
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
@@ -18,9 +19,9 @@ namespace Service::HID {
// Updating period for each HID device.
// TODO(shinyquagsire23): These need better values.
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
@@ -63,7 +64,8 @@ private:
std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
// TODO(shinyquagsire23): gyro, touch, mouse, keyboard
touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device);
// TODO(shinyquagsire23): gyro, mouse, keyboard
}
void UpdatePadCallback(u64 userdata, int cycles_late) {
@@ -151,8 +153,6 @@ private:
}
}
// TODO(bunnei): Properly implement the touch screen, the below will just write empty data
TouchScreen& touchscreen = mem.touchscreen;
const u64 last_entry = touchscreen.header.latest_entry;
const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size();
@@ -164,7 +164,26 @@ private:
touchscreen.header.max_entry_index = touchscreen.entries.size();
touchscreen.header.timestamp = timestamp;
touchscreen.entries[curr_entry].header.timestamp = sample_counter;
touchscreen.entries[curr_entry].header.num_touches = 0;
TouchScreenEntryTouch touch_entry{};
auto [x, y, pressed] = touch_device->GetStatus();
touch_entry.timestamp = timestamp;
touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
touch_entry.touch_index = 0;
// TODO(DarkLordZach): Maybe try to derive these from EmuWindow?
touch_entry.diameter_x = 15;
touch_entry.diameter_y = 15;
touch_entry.angle = 0;
// TODO(DarkLordZach): Implement multi-touch support
if (pressed) {
touchscreen.entries[curr_entry].header.num_touches = 1;
touchscreen.entries[curr_entry].touches[0] = touch_entry;
} else {
touchscreen.entries[curr_entry].header.num_touches = 0;
}
// TODO(shinyquagsire23): Properly implement mouse
Mouse& mouse = mem.mouse;
@@ -250,6 +269,7 @@ private:
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
std::unique_ptr<Input::TouchDevice> touch_device;
};
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {

View File

@@ -18,7 +18,8 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector
}
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) {
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect) {
VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
LOG_WARNING(Service,
"Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
@@ -26,7 +27,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
const Tegra::FramebufferConfig framebuffer{
addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform};
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
transform, crop_rect};
Core::System::GetInstance().perf_stats.EndGameFrame();

View File

@@ -7,6 +7,7 @@
#include <memory>
#include <vector>
#include "common/common_types.h"
#include "common/math_util.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -23,7 +24,8 @@ public:
/// Performs a screen flip, drawing the buffer pointed to by the handle.
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
NVFlinger::BufferQueue::BufferTransformFlags transform);
NVFlinger::BufferQueue::BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect);
private:
std::shared_ptr<nvmap> nvmap_dev;

View File

@@ -13,8 +13,8 @@ namespace Service {
namespace NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
native_handle->Signal();
buffer_wait_event =
Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
}
void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
@@ -26,10 +26,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
queue.emplace_back(buffer);
if (buffer_wait_event) {
buffer_wait_event->Signal();
}
buffer_wait_event->Signal();
}
boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -48,8 +45,6 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
return boost::none;
}
buffer_wait_event = nullptr;
itr->status = Buffer::Status::Dequeued;
return itr->slot;
}
@@ -62,13 +57,15 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
return itr->igbp_buffer;
}
void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform) {
void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect) {
auto itr = std::find_if(queue.begin(), queue.end(),
[&](const Buffer& buffer) { return buffer.slot == slot; });
ASSERT(itr != queue.end());
ASSERT(itr->status == Buffer::Status::Dequeued);
itr->status = Buffer::Status::Queued;
itr->transform = transform;
itr->crop_rect = crop_rect;
}
boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
@@ -88,9 +85,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
ASSERT(itr->status == Buffer::Status::Acquired);
itr->status = Buffer::Status::Free;
if (buffer_wait_event) {
buffer_wait_event->Signal();
}
buffer_wait_event->Signal();
}
u32 BufferQueue::Query(QueryType type) {
@@ -106,10 +101,5 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event) {
ASSERT_MSG(!buffer_wait_event, "buffer_wait_event only supports a single waiting thread!");
buffer_wait_event = std::move(wait_event);
}
} // namespace NVFlinger
} // namespace Service

View File

@@ -6,6 +6,7 @@
#include <vector>
#include <boost/optional.hpp>
#include "common/math_util.h"
#include "common/swap.h"
#include "core/hle/kernel/event.h"
@@ -68,23 +69,24 @@ public:
Status status = Status::Free;
IGBPBuffer igbp_buffer;
BufferTransformFlags transform;
MathUtil::Rectangle<int> crop_rect;
};
void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
boost::optional<u32> DequeueBuffer(u32 width, u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform);
void QueueBuffer(u32 slot, BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect);
boost::optional<const Buffer&> AcquireBuffer();
void ReleaseBuffer(u32 slot);
u32 Query(QueryType type);
void SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event);
u32 GetId() const {
return id;
}
Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const {
return native_handle;
Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const {
return buffer_wait_event;
}
private:
@@ -92,9 +94,6 @@ private:
u64 layer_id;
std::vector<Buffer> queue;
Kernel::SharedPtr<Kernel::Event> native_handle;
/// Used to signal waiting thread when no buffers are available
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
};

View File

@@ -149,12 +149,10 @@ void NVFlinger::Compose() {
ASSERT(nvdisp);
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform);
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform,
buffer->crop_rect);
buffer_queue->ReleaseBuffer(buffer->slot);
// TODO(Subv): Figure out when we should actually signal this event.
buffer_queue->GetNativeHandle()->Signal();
}
}

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include "core/hle/kernel/event.h"

View File

@@ -7,6 +7,7 @@
#include <memory>
#include <boost/optional.hpp>
#include "common/alignment.h"
#include "common/math_util.h"
#include "common/scope_exit.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
@@ -27,8 +28,8 @@ struct DisplayInfo {
char display_name[0x40]{"Default"};
u64 unknown_1{1};
u64 unknown_2{1};
u64 width{1920};
u64 height{1080};
u64 width{1280};
u64 height{720};
};
static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
@@ -327,8 +328,8 @@ public:
protected:
void SerializeData() override {
// TODO(Subv): Figure out what this value means, writing non-zero here will make libnx try
// to read an IGBPBuffer object from the parcel.
// TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
// try to read an IGBPBuffer object from the parcel.
Write<u32_le>(1);
WriteObject(buffer);
Write<u32_le>(0);
@@ -360,8 +361,8 @@ public:
INSERT_PADDING_WORDS(3);
u32_le timestamp;
s32_le is_auto_timestamp;
s32_le crop_left;
s32_le crop_top;
s32_le crop_left;
s32_le crop_right;
s32_le crop_bottom;
s32_le scaling_mode;
@@ -370,6 +371,10 @@ public:
INSERT_PADDING_WORDS(2);
u32_le fence_is_valid;
std::array<Fence, 2> fences;
MathUtil::Rectangle<int> GetCropRect() const {
return {crop_left, crop_top, crop_right, crop_bottom};
}
};
static_assert(sizeof(Data) == 80, "ParcelData has wrong size");
@@ -495,7 +500,7 @@ private:
ctx.WriteBuffer(response.Serialize());
} else {
// Wait the current thread until a buffer becomes available
auto wait_event = ctx.SleepClientThread(
ctx.SleepClientThread(
Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1,
[=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
ThreadWakeupReason reason) {
@@ -506,8 +511,8 @@ private:
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
});
buffer_queue->SetBufferWaitEvent(std::move(wait_event));
},
buffer_queue->GetBufferWaitEvent());
}
} else if (transaction == TransactionId::RequestBuffer) {
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
@@ -519,7 +524,8 @@ private:
} else if (transaction == TransactionId::QueueBuffer) {
IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue->QueueBuffer(request.data.slot, request.data.transform);
buffer_queue->QueueBuffer(request.data.slot, request.data.transform,
request.data.GetCropRect());
IGBPQueueBufferResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize());
@@ -532,7 +538,7 @@ private:
IGBPQueryResponseParcel response{value};
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::CancelBuffer) {
LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
} else {
ASSERT_MSG(false, "Unimplemented");
}
@@ -565,7 +571,7 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(buffer_queue->GetNativeHandle());
rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
}
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;

View File

@@ -520,7 +520,18 @@ public:
u32 enable[NumRenderTargets];
} blend;
INSERT_PADDING_WORDS(0xB);
struct {
u32 enable;
u32 front_op_fail;
u32 front_op_zfail;
u32 front_op_zpass;
u32 front_func_func;
u32 front_func_ref;
u32 front_func_mask;
u32 front_mask;
} stencil;
INSERT_PADDING_WORDS(0x3);
union {
BitField<4, 1, u32> triangle_rast_flip;
@@ -556,7 +567,17 @@ public:
}
} tic;
INSERT_PADDING_WORDS(0x21);
INSERT_PADDING_WORDS(0x5);
struct {
u32 enable;
u32 back_op_fail;
u32 back_op_zfail;
u32 back_op_zpass;
u32 back_func_func;
} stencil_two_side;
INSERT_PADDING_WORDS(0x17);
union {
BitField<2, 1, u32> coord_origin;
@@ -851,10 +872,12 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
ASSERT_REG_POSITION(depth_test_func, 0x4C3);
ASSERT_REG_POSITION(blend, 0x4CF);
ASSERT_REG_POSITION(stencil, 0x4E0);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side, 0x565);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);

View File

@@ -67,6 +67,7 @@ struct FramebufferConfig {
using TransformFlags = Service::NVFlinger::BufferQueue::BufferTransformFlags;
TransformFlags transform_flags;
MathUtil::Rectangle<int> crop_rect;
};
namespace Engines {

View File

@@ -105,6 +105,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -196,8 +197,9 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>,
MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::Z24S8>,
MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::Z16>,
};
static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
@@ -217,7 +219,8 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::ABGR8>,
nullptr,
MortonCopy<false, PixelFormat::G8R8>,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32F>,
@@ -274,10 +277,10 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
S8Z24 input_pixel{};
Z24S8 output_pixel{};
const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)};
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
const size_t offset{4 * (y * width + x)};
const size_t offset{bpp * (y * width + x)};
std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24));
output_pixel.s8.Assign(input_pixel.s8);
output_pixel.z24.Assign(input_pixel.z24);
@@ -285,6 +288,19 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
}
}
}
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8)};
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
const size_t offset{bpp * (y * width + x)};
const u8 temp{data[offset]};
data[offset] = data[offset + 1];
data[offset + 1] = temp;
}
}
}
/**
* Helper function to perform software conversion (as needed) when loading a buffer from Switch
* memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
@@ -305,6 +321,11 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
// Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24.
ConvertS8Z24ToZ24S8(data, width, height);
break;
case PixelFormat::G8R8:
// Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8.
ConvertG8R8ToR8G8(data, width, height);
break;
}
}

View File

@@ -37,14 +37,15 @@ struct SurfaceParams {
DXN1 = 11, // This is also known as BC4
BC7U = 12,
ASTC_2D_4X4 = 13,
G8R8 = 14,
MaxColorFormat,
// DepthStencil formats
Z24S8 = 14,
S8Z24 = 15,
Z32F = 16,
Z16 = 17,
Z24S8 = 15,
S8Z24 = 16,
Z32F = 17,
Z16 = 18,
MaxDepthStencilFormat,
@@ -96,6 +97,7 @@ struct SurfaceParams {
4, // DXN1
4, // BC7U
4, // ASTC_2D_4X4
1, // G8R8
1, // Z24S8
1, // S8Z24
1, // Z32F
@@ -125,6 +127,7 @@ struct SurfaceParams {
64, // DXN1
128, // BC7U
32, // ASTC_2D_4X4
16, // G8R8
32, // Z24S8
32, // S8Z24
32, // Z32F
@@ -186,6 +189,8 @@ struct SurfaceParams {
return PixelFormat::A1B5G5R5;
case Tegra::Texture::TextureFormat::R8:
return PixelFormat::R8;
case Tegra::Texture::TextureFormat::G8R8:
return PixelFormat::G8R8;
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
return PixelFormat::RGBA16F;
case Tegra::Texture::TextureFormat::BF10GF11RF11:
@@ -223,6 +228,8 @@ struct SurfaceParams {
return Tegra::Texture::TextureFormat::A1B5G5R5;
case PixelFormat::R8:
return Tegra::Texture::TextureFormat::R8;
case PixelFormat::G8R8:
return Tegra::Texture::TextureFormat::G8R8;
case PixelFormat::RGBA16F:
return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
case PixelFormat::R11FG11FB10F:

View File

@@ -154,6 +154,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
// Framebuffer orientation handling
framebuffer_transform_flags = framebuffer.transform_flags;
framebuffer_crop_rect = framebuffer.crop_rect;
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
// only allows rows to have a memory alignement of 4.
@@ -320,11 +321,24 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
}
}
ASSERT_MSG(framebuffer_crop_rect.top == 0, "Unimplemented");
ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented");
// Scale the output by the crop width/height. This is commonly used with 1280x720 rendering
// (e.g. handheld mode) on a 1920x1080 framebuffer.
f32 scale_u = 1.f, scale_v = 1.f;
if (framebuffer_crop_rect.GetWidth() > 0) {
scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / screen_info.texture.width;
}
if (framebuffer_crop_rect.GetHeight() > 0) {
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) / screen_info.texture.height;
}
std::array<ScreenRectVertex, 4> vertices = {{
ScreenRectVertex(x, y, texcoords.top, left),
ScreenRectVertex(x + w, y, texcoords.bottom, left),
ScreenRectVertex(x, y + h, texcoords.top, right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, right),
ScreenRectVertex(x, y, texcoords.top * scale_u, left * scale_v),
ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left * scale_v),
ScreenRectVertex(x, y + h, texcoords.top * scale_u, right * scale_v),
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
}};
state.texture_units[0].texture_2d = screen_info.display_texture;

View File

@@ -97,4 +97,5 @@ private:
/// Used for transforming the framebuffer orientation
Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
MathUtil::Rectangle<int> framebuffer_crop_rect;
};

View File

@@ -25,16 +25,15 @@
class BitStream {
public:
BitStream(unsigned char* ptr, int nBits = 0, int start_offset = 0)
: m_BitsWritten(0), m_BitsRead(0), m_NumBits(nBits), m_CurByte(ptr),
m_NextBit(start_offset % 8), done(false) {}
explicit BitStream(unsigned char* ptr, int nBits = 0, int start_offset = 0)
: m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {}
~BitStream() = default;
int GetBitsWritten() const {
return m_BitsWritten;
}
~BitStream() {}
void WriteBitsR(unsigned int val, unsigned int nBits) {
for (unsigned int i = 0; i < nBits; i++) {
WriteBit((val >> (nBits - i - 1)) & 1);
@@ -95,33 +94,28 @@ private:
done = done || ++m_BitsWritten >= m_NumBits;
}
int m_BitsWritten;
int m_BitsWritten = 0;
const int m_NumBits;
unsigned char* m_CurByte;
int m_NextBit;
int m_BitsRead;
int m_NextBit = 0;
int m_BitsRead = 0;
bool done;
bool done = false;
};
template <typename IntType>
class Bits {
private:
const IntType& m_Bits;
// Don't copy
Bits() {}
Bits(const Bits&) {}
Bits& operator=(const Bits&) {}
public:
explicit Bits(IntType& v) : m_Bits(v) {}
explicit Bits(const IntType& v) : m_Bits(v) {}
uint8_t operator[](uint32_t bitPos) {
Bits(const Bits&) = delete;
Bits& operator=(const Bits&) = delete;
uint8_t operator[](uint32_t bitPos) const {
return static_cast<uint8_t>((m_Bits >> bitPos) & 1);
}
IntType operator()(uint32_t start, uint32_t end) {
IntType operator()(uint32_t start, uint32_t end) const {
if (start == end) {
return (*this)[start];
} else if (start > end) {
@@ -133,6 +127,9 @@ public:
uint64_t mask = (1 << (end - start + 1)) - 1;
return (m_Bits >> start) & mask;
}
private:
const IntType& m_Bits;
};
enum EIntegerEncoding { eIntegerEncoding_JustBits, eIntegerEncoding_Quint, eIntegerEncoding_Trit };
@@ -186,12 +183,12 @@ public:
m_QuintValue = val;
}
bool MatchesEncoding(const IntegerEncodedValue& other) {
bool MatchesEncoding(const IntegerEncodedValue& other) const {
return m_Encoding == other.m_Encoding && m_NumBits == other.m_NumBits;
}
// Returns the number of bits required to encode nVals values.
uint32_t GetBitLength(uint32_t nVals) {
uint32_t GetBitLength(uint32_t nVals) const {
uint32_t totalBits = m_NumBits * nVals;
if (m_Encoding == eIntegerEncoding_Trit) {
totalBits += (nVals * 8 + 4) / 5;
@@ -382,19 +379,15 @@ private:
namespace ASTCC {
struct TexelWeightParams {
uint32_t m_Width;
uint32_t m_Height;
bool m_bDualPlane;
uint32_t m_MaxWeight;
bool m_bError;
bool m_bVoidExtentLDR;
bool m_bVoidExtentHDR;
uint32_t m_Width = 0;
uint32_t m_Height = 0;
bool m_bDualPlane = false;
uint32_t m_MaxWeight = 0;
bool m_bError = false;
bool m_bVoidExtentLDR = false;
bool m_bVoidExtentHDR = false;
TexelWeightParams() {
memset(this, 0, sizeof(*this));
}
uint32_t GetPackedBitSize() {
uint32_t GetPackedBitSize() const {
// How many indices do we have?
uint32_t nIdxs = m_Height * m_Width;
if (m_bDualPlane) {
@@ -413,7 +406,7 @@ struct TexelWeightParams {
}
};
TexelWeightParams DecodeBlockInfo(BitStream& strm) {
static TexelWeightParams DecodeBlockInfo(BitStream& strm) {
TexelWeightParams params;
// Read the entire block mode all at once
@@ -612,8 +605,8 @@ TexelWeightParams DecodeBlockInfo(BitStream& strm) {
return params;
}
void FillVoidExtentLDR(BitStream& strm, uint32_t* const outBuf, uint32_t blockWidth,
uint32_t blockHeight) {
static void FillVoidExtentLDR(BitStream& strm, uint32_t* const outBuf, uint32_t blockWidth,
uint32_t blockHeight) {
// Don't actually care about the void extent, just read the bits...
for (int i = 0; i < 4; ++i) {
strm.ReadBits(13);
@@ -628,23 +621,25 @@ void FillVoidExtentLDR(BitStream& strm, uint32_t* const outBuf, uint32_t blockWi
uint32_t rgba = (r >> 8) | (g & 0xFF00) | (static_cast<uint32_t>(b) & 0xFF00) << 8 |
(static_cast<uint32_t>(a) & 0xFF00) << 16;
for (uint32_t j = 0; j < blockHeight; j++)
for (uint32_t j = 0; j < blockHeight; j++) {
for (uint32_t i = 0; i < blockWidth; i++) {
outBuf[j * blockWidth + i] = rgba;
}
}
}
void FillError(uint32_t* outBuf, uint32_t blockWidth, uint32_t blockHeight) {
for (uint32_t j = 0; j < blockHeight; j++)
static void FillError(uint32_t* outBuf, uint32_t blockWidth, uint32_t blockHeight) {
for (uint32_t j = 0; j < blockHeight; j++) {
for (uint32_t i = 0; i < blockWidth; i++) {
outBuf[j * blockWidth + i] = 0xFFFF00FF;
}
}
}
// Replicates low numBits such that [(toBit - 1):(toBit - 1 - fromBit)]
// is the same as [(numBits - 1):0] and repeats all the way down.
template <typename IntType>
IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) {
static IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) {
if (numBits == 0)
return 0;
if (toBit == 0)
@@ -668,27 +663,15 @@ IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) {
class Pixel {
protected:
typedef int16_t ChannelType;
uint8_t m_BitDepth[4];
int16_t color[4];
using ChannelType = int16_t;
uint8_t m_BitDepth[4] = {8, 8, 8, 8};
int16_t color[4] = {};
public:
Pixel() {
for (int i = 0; i < 4; i++) {
m_BitDepth[i] = 8;
color[i] = 0;
}
}
Pixel(ChannelType a, ChannelType r, ChannelType g, ChannelType b, unsigned bitDepth = 8) {
for (int i = 0; i < 4; i++)
m_BitDepth[i] = bitDepth;
color[0] = a;
color[1] = r;
color[2] = g;
color[3] = b;
}
Pixel() = default;
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{a, r, g, b} {}
// Changes the depth of each pixel. This scales the values to
// the appropriate bit depth by either truncating the least
@@ -807,8 +790,8 @@ public:
}
};
void DecodeColorValues(uint32_t* out, uint8_t* data, uint32_t* modes, const uint32_t nPartitions,
const uint32_t nBitsForColorData) {
static void DecodeColorValues(uint32_t* out, uint8_t* data, const uint32_t* modes,
const uint32_t nPartitions, const uint32_t nBitsForColorData) {
// First figure out how many color values we have
uint32_t nValues = 0;
for (uint32_t i = 0; i < nPartitions; i++) {
@@ -844,8 +827,7 @@ void DecodeColorValues(uint32_t* out, uint8_t* data, uint32_t* modes, const uint
// Once we have the decoded values, we need to dequantize them to the 0-255 range
// This procedure is outlined in ASTC spec C.2.13
uint32_t outIdx = 0;
std::vector<IntegerEncodedValue>::const_iterator itr;
for (itr = decodedColorValues.begin(); itr != decodedColorValues.end(); itr++) {
for (auto itr = decodedColorValues.begin(); itr != decodedColorValues.end(); ++itr) {
// Have we already decoded all that we need?
if (outIdx >= nValues) {
break;
@@ -978,7 +960,7 @@ void DecodeColorValues(uint32_t* out, uint8_t* data, uint32_t* modes, const uint
}
}
uint32_t UnquantizeTexelWeight(const IntegerEncodedValue& val) {
static uint32_t UnquantizeTexelWeight(const IntegerEncodedValue& val) {
uint32_t bitval = val.GetBitValue();
uint32_t bitlen = val.BaseBitLength();
@@ -1067,17 +1049,18 @@ uint32_t UnquantizeTexelWeight(const IntegerEncodedValue& val) {
return result;
}
void UnquantizeTexelWeights(uint32_t out[2][144], std::vector<IntegerEncodedValue>& weights,
const TexelWeightParams& params, const uint32_t blockWidth,
const uint32_t blockHeight) {
static void UnquantizeTexelWeights(uint32_t out[2][144],
const std::vector<IntegerEncodedValue>& weights,
const TexelWeightParams& params, const uint32_t blockWidth,
const uint32_t blockHeight) {
uint32_t weightIdx = 0;
uint32_t unquantized[2][144];
std::vector<IntegerEncodedValue>::const_iterator itr;
for (itr = weights.begin(); itr != weights.end(); itr++) {
for (auto itr = weights.begin(); itr != weights.end(); ++itr) {
unquantized[0][weightIdx] = UnquantizeTexelWeight(*itr);
if (params.m_bDualPlane) {
itr++;
++itr;
unquantized[1][weightIdx] = UnquantizeTexelWeight(*itr);
if (itr == weights.end()) {
break;
@@ -1261,8 +1244,8 @@ static inline uint32_t Select2DPartition(int32_t seed, int32_t x, int32_t y, int
}
// Section C.2.14
void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const uint32_t*& colorValues,
uint32_t colorEndpointMode) {
static void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const uint32_t*& colorValues,
uint32_t colorEndpointMode) {
#define READ_UINT_VALUES(N) \
uint32_t v[N]; \
for (uint32_t i = 0; i < N; i++) { \
@@ -1382,8 +1365,8 @@ void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const uint32_t*& colorValues,
#undef READ_INT_VALUES
}
void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth, const uint32_t blockHeight,
uint32_t* outBuf) {
static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
const uint32_t blockHeight, uint32_t* outBuf) {
BitStream strm(inBuf);
TexelWeightParams weightParams = DecodeBlockInfo(strm);
@@ -1617,8 +1600,7 @@ namespace Tegra::Texture::ASTC {
std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
uint32_t block_width, uint32_t block_height) {
uint32_t blockIdx = 0;
std::vector<uint8_t> outData;
outData.resize(height * width * 4);
std::vector<uint8_t> outData(height * width * 4);
for (uint32_t j = 0; j < height; j += block_height) {
for (uint32_t i = 0; i < width; i += block_width) {

View File

@@ -62,6 +62,7 @@ u32 BytesPerPixel(TextureFormat format) {
return 4;
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::G8R8:
return 2;
case TextureFormat::R8:
return 1;
@@ -112,6 +113,7 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::R8:
case TextureFormat::G8R8:
case TextureFormat::R16_G16_B16_A16:
case TextureFormat::R32_G32_B32_A32:
case TextureFormat::BF10GF11RF11:
@@ -167,6 +169,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::R8:
case TextureFormat::G8R8:
case TextureFormat::BF10GF11RF11:
case TextureFormat::R32_G32_B32_A32:
// TODO(Subv): For the time being just forward the same data without any decoding.

View File

@@ -97,7 +97,7 @@ void Config::ReadValues() {
qt_config->endGroup();
qt_config->beginGroup("System");
Settings::values.use_docked_mode = qt_config->value("use_docked_mode", true).toBool();
Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");

View File

@@ -17,10 +17,7 @@
#include "game_list_p.h"
#include "ui_settings.h"
GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) {
this->gamelist = gamelist;
edit_filter_text_old = "";
}
GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
// EventFilter in order to process systemkeys while editing the searchfield
bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
@@ -141,10 +138,12 @@ GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} {
* @param userinput String containing all words getting checked
* @return true if the haystack contains all words of userinput
*/
bool GameList::containsAllWords(QString haystack, QString userinput) {
QStringList userinput_split = userinput.split(" ", QString::SplitBehavior::SkipEmptyParts);
bool GameList::ContainsAllWords(const QString& haystack, const QString& userinput) const {
const QStringList userinput_split =
userinput.split(' ', QString::SplitBehavior::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(),
[haystack](QString s) { return haystack.contains(s); });
[&haystack](const QString& s) { return haystack.contains(s); });
}
// Event in order to filter the gamelist after editing the searchfield
@@ -178,7 +177,7 @@ void GameList::onTextChanged(const QString& newText) {
// The search is case insensitive because of toLower()
// I decided not to use Qt::CaseInsensitive in containsAllWords to prevent
// multiple conversions of edit_filter_text for each game in the gamelist
if (containsAllWords(file_name.append(" ").append(file_title), edit_filter_text) ||
if (ContainsAllWords(file_name.append(' ').append(file_title), edit_filter_text) ||
(file_programmid.count() == 16 && edit_filter_text.contains(file_programmid))) {
tree_view->setRowHidden(i, root_index, false);
++result_count;

View File

@@ -89,7 +89,7 @@ private:
void PopupContextMenu(const QPoint& menu_location);
void RefreshGameDirectory();
bool containsAllWords(QString haystack, QString userinput);
bool ContainsAllWords(const QString& haystack, const QString& userinput) const;
SearchField* search_field;
GMainWindow* main_window = nullptr;

View File

@@ -110,7 +110,7 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
// System
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", true);
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
// Miscellaneous
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");

View File

@@ -163,7 +163,7 @@ use_virtual_sd =
[System]
# Whether the system is docked
# 1 (default): Yes, 0: No
# 1: Yes, 0 (default): No
use_docked_mode =
# The system region that yuzu will use during emulation