refactor jpegdec implementation into libstrat (thanks again, Behemoth!)

This commit is contained in:
Michael Scire
2020-04-20 04:37:08 -07:00
parent 90d754f920
commit 6eb77e69c4
23 changed files with 780 additions and 261 deletions

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "decodersrv_decoder_server_object.hpp"
namespace ams::capsrv::server {
Result DecoderControlServerManager::Initialize() {
/* Create the objects. */
this->service_holder.emplace();
this->server_manager_holder.emplace();
/* Register the service. */
R_ABORT_UNLESS(this->server_manager_holder->RegisterServer<Service>(ServiceName, MaxSessions, sf::ServiceObjectTraits<Service>::SharedPointerHelper::GetEmptyDeleteSharedPointer(std::addressof(*this->service_holder))));
/* Initialize the idle event, we're idle initially. */
os::InitializeEvent(std::addressof(this->idle_event), true, os::EventClearMode_ManualClear);
return ResultSuccess();
}
void DecoderControlServerManager::Finalize() {
/* Check that the server is idle. */
AMS_ASSERT(os::TryWaitEvent(std::addressof(this->idle_event)));
/* Destroy the server. */
os::FinalizeEvent(std::addressof(this->idle_event));
this->server_manager_holder = std::nullopt;
this->service_holder = std::nullopt;
}
void DecoderControlServerManager::StartServer() {
this->server_manager_holder->ResumeProcessing();
}
void DecoderControlServerManager::StopServer() {
/* Request the server stop, and wait until it does. */
this->server_manager_holder->RequestStopProcessing();
os::WaitEvent(std::addressof(this->idle_event));
}
void DecoderControlServerManager::RunServer() {
/* Ensure that we are allowed to run. */
AMS_ABORT_UNLESS(os::TryWaitEvent(std::addressof(this->idle_event)));
/* Clear the event. */
os::ClearEvent(std::addressof(this->idle_event));
/* Process forever. */
this->server_manager_holder->LoopProcess();
/* Signal that we're idle again. */
os::SignalEvent(std::addressof(this->idle_event));
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
#include "decodersrv_decoder_control_service.hpp"
namespace ams::capsrv::server {
class DecoderControlServerManager {
public:
/* NOTE: Nintendo only allows one session. */
static constexpr inline size_t NumServers = 1;
static constexpr inline size_t MaxSessions = 2;
static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("caps:dc");
using Service = DecoderControlService;
using ServerOptions = sf::hipc::DefaultServerManagerOptions;
using ServerManager = sf::hipc::ServerManager<NumServers, ServerOptions, MaxSessions>;
private:
std::optional<Service> service_holder;
std::optional<ServerManager> server_manager_holder;
os::EventType idle_event;
public:
constexpr DecoderControlServerManager() : service_holder(), server_manager_holder(), idle_event{} { /* ... */ }
Result Initialize();
void Finalize();
void StartServer();
void StopServer();
void RunServer();
};
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "decodersrv_decoder_server_object.hpp"
#include "../jpeg/decodersrv_software_jpeg_decoder.hpp"
namespace ams::capsrv::server {
namespace {
Result DecodeJpegImpl(void *dst, size_t dst_size, const void *src_jpeg, size_t src_jpeg_size, u32 width, u32 height, const ScreenShotDecodeOption &option, void *work, size_t work_size) {
/* Clear the work memory. */
std::memset(work, 0, work_size);
ON_SCOPE_EXIT { std::memset(work, 0, work_size); };
/* Clear the output memory. */
std::memset(dst, 0, dst_size);
auto clear_guard = SCOPE_GUARD { std::memset(dst, 0, dst_size); };
/* Validate parameters. */
R_UNLESS(util::IsAligned(width, 0x10), capsrv::ResultAlbumOutOfRange());
R_UNLESS(util::IsAligned(height, 0x4), capsrv::ResultAlbumOutOfRange());
R_UNLESS(dst != nullptr, capsrv::ResultAlbumReadBufferShortage());
R_UNLESS(dst_size >= 4 * width * height, capsrv::ResultAlbumReadBufferShortage());
R_UNLESS(src_jpeg != nullptr, capsrv::ResultAlbumInvalidFileData());
R_UNLESS(src_jpeg_size != 0, capsrv::ResultAlbumInvalidFileData());
/* Create the input. */
const jpeg::SoftwareJpegDecoderInput decode_input = {
.jpeg = src_jpeg,
.jpeg_size = src_jpeg_size,
.width = width,
.height = height,
.fancy_upsampling = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableFancyUpsampling),
.block_smoothing = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableBlockSmoothing),
};
/* Create the output. */
s32 out_width = 0, out_height = 0;
jpeg::SoftwareJpegDecoderOutput decode_output = {
.out_width = std::addressof(out_width),
.out_height = std::addressof(out_height),
.dst = dst,
.dst_size = dst_size,
};
/* Decode the jpeg. */
R_TRY(jpeg::SoftwareJpegDecoder::DecodeRgba8(decode_output, decode_input, work, work_size));
/* We succeeded, so we shouldn't clear the output memory. */
clear_guard.Cancel();
return ResultSuccess();
}
}
Result DecoderControlService::DecodeJpeg(const sf::OutNonSecureBuffer &out, const sf::InBuffer &in, u32 width, u32 height, const ScreenShotDecodeOption &option) {
/* Get the work buffer. */
void *work = g_work_memory.jpeg_decoder_memory;
size_t work_size = sizeof(g_work_memory.jpeg_decoder_memory);
/* Call the decoder implementation. */
return DecodeJpegImpl(out.GetPointer(), out.GetSize(), in.GetPointer(), in.GetSize(), width, height, option, work, work_size);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::capsrv::server {
class DecoderControlService final : public sf::IServiceObject {
protected:
enum class CommandId {
DecodeJpeg = 3001,
};
public:
/* Actual commands. */
virtual Result DecodeJpeg(const sf::OutNonSecureBuffer &out, const sf::InBuffer &in, u32 width, u32 height, const ScreenShotDecodeOption &option);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(DecodeJpeg)
};
};
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "decodersrv_decoder_server_object.hpp"
namespace ams::capsrv::server {
/* Instantiate the decoder server globals in a single TU. */
DecoderWorkMemory g_work_memory;
DecoderControlServerManager g_decoder_control_server_manager;
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
#include "decodersrv_decoder_work_memory.hpp"
#include "decodersrv_decoder_control_server_manager.hpp"
namespace ams::capsrv::server {
extern DecoderWorkMemory g_work_memory;
extern DecoderControlServerManager g_decoder_control_server_manager;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::capsrv::server {
struct DecoderWorkMemory {
alignas(os::MemoryPageSize) u8 jpeg_decoder_memory[SoftwareJpegDecoderWorkMemorySize];
};
static_assert(sizeof(DecoderWorkMemory) == SoftwareJpegDecoderWorkMemorySize);
static_assert(alignof(DecoderWorkMemory) == os::MemoryPageSize);
static_assert(std::is_pod<DecoderWorkMemory>::value);
}