Merge branch 'master' into core-macros-1
This commit is contained in:
commit
f0ea96f144
|
@ -0,0 +1,15 @@
|
||||||
|
# List of environment variables to be shared with Docker containers
|
||||||
|
CI
|
||||||
|
TRAVIS
|
||||||
|
CONTINUOUS_INTEGRATION
|
||||||
|
TRAVIS_BRANCH
|
||||||
|
TRAVIS_BUILD_ID
|
||||||
|
TRAVIS_BUILD_NUMBER
|
||||||
|
TRAVIS_COMMIT
|
||||||
|
TRAVIS_JOB_ID
|
||||||
|
TRAVIS_JOB_NUMBER
|
||||||
|
TRAVIS_REPO_SLUG
|
||||||
|
TRAVIS_TAG
|
||||||
|
|
||||||
|
# citra specific flags
|
||||||
|
ENABLE_COMPATIBILITY_REPORTING
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash -ex
|
#!/bin/bash -ex
|
||||||
mkdir -p "$HOME/.ccache"
|
mkdir -p "$HOME/.ccache"
|
||||||
docker pull ubuntu:18.04
|
docker pull ubuntu:18.04
|
||||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux-frozen/docker.sh
|
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux-frozen/docker.sh
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/bash -ex
|
#!/bin/bash -ex
|
||||||
mkdir -p "$HOME/.ccache"
|
mkdir -p "$HOME/.ccache"
|
||||||
docker run -e ENABLE_COMPATIBILITY_REPORTING -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux/docker.sh
|
docker run --env-file .travis/common/travis-ci.env -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux/docker.sh
|
||||||
|
|
|
@ -9,7 +9,21 @@ echo -e "\e[1m\e[33mInstalling dependencies...\e[0m"
|
||||||
apk update
|
apk update
|
||||||
apk add build-base cmake python3-dev qt5-qttools-dev qt5-qtmultimedia-dev
|
apk add build-base cmake python3-dev qt5-qttools-dev qt5-qtmultimedia-dev
|
||||||
|
|
||||||
pip3 install transifex-client
|
pip3 install --upgrade pip transifex-client
|
||||||
|
|
||||||
|
cat << 'EOF' > /usr/bin/tx
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from txclib.cmdline import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||||
|
sys.exit(main())
|
||||||
|
EOF
|
||||||
|
|
||||||
echo -e "\e[1m\e[33mBuild tools information:\e[0m"
|
echo -e "\e[1m\e[33mBuild tools information:\e[0m"
|
||||||
cmake --version
|
cmake --version
|
||||||
|
|
|
@ -27,13 +27,14 @@ install:
|
||||||
- ps: |
|
- ps: |
|
||||||
if ($env:BUILD_TYPE -eq 'mingw') {
|
if ($env:BUILD_TYPE -eq 'mingw') {
|
||||||
$dependencies = "mingw64/mingw-w64-x86_64-qt5"
|
$dependencies = "mingw64/mingw-w64-x86_64-qt5"
|
||||||
|
C:\msys64\usr\bin\bash -lc "pacman -Syy"
|
||||||
# redirect err to null to prevent warnings from becoming errors
|
# redirect err to null to prevent warnings from becoming errors
|
||||||
# workaround to prevent pacman from failing due to cyclical dependencies
|
# workaround to prevent pacman from failing due to cyclical dependencies
|
||||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw64/mingw-w64-x86_64-freetype mingw64/mingw-w64-x86_64-fontconfig" 2> $null
|
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw64/mingw-w64-x86_64-freetype mingw64/mingw-w64-x86_64-fontconfig" 2> $null
|
||||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-SDL2-2.0.5-2-any.pkg.tar.xz" 2> $null
|
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-SDL2-2.0.5-2-any.pkg.tar.xz" 2> $null
|
||||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S $dependencies" 2> $null
|
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S $dependencies" 2> $null
|
||||||
# stick to cmake 3.9.6 since on lower versions it could happen that cmake generates a Makefile that links against gcc_eh
|
# freeze the cmake to a stable version, on version < 3.9.6 cmake may generate a Makefile links against gcc_eh instead of gcc_s_eh
|
||||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-cmake-3.9.6-1-any.pkg.tar.xz" 2> $null
|
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-cmake-3.11.1-2-any.pkg.tar.xz" 2> $null
|
||||||
}
|
}
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
|
|
|
@ -81,5 +81,5 @@ endif()
|
||||||
# Cubeb
|
# Cubeb
|
||||||
if(ENABLE_CUBEB)
|
if(ENABLE_CUBEB)
|
||||||
set(BUILD_TESTS OFF CACHE BOOL "")
|
set(BUILD_TESTS OFF CACHE BOOL "")
|
||||||
add_subdirectory(cubeb)
|
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5be140bcea453a00f7f2fec09fb9e37849d65d98
|
Subproject commit f320e7d92a33ee80ae42deef79da78cfc30868af
|
|
@ -1 +1 @@
|
||||||
Subproject commit d1d4705364031512cb89333aebc00b8d75a2f732
|
Subproject commit 4b350a354a21339052c7fff88832c3f81f5624be
|
|
@ -1 +1 @@
|
||||||
Subproject commit 019d2089bbadf70d73ba85aa8ea51490b071262c
|
Subproject commit 060181eaf273180d3a7e87349895bd0cb6ccbf4a
|
|
@ -155,14 +155,20 @@ void Config::ReadValues() {
|
||||||
sdl2_config->Get("Camera", "camera_outer_right_name", "blank");
|
sdl2_config->Get("Camera", "camera_outer_right_name", "blank");
|
||||||
Settings::values.camera_config[OuterRightCamera] =
|
Settings::values.camera_config[OuterRightCamera] =
|
||||||
sdl2_config->Get("Camera", "camera_outer_right_config", "");
|
sdl2_config->Get("Camera", "camera_outer_right_config", "");
|
||||||
|
Settings::values.camera_flip[OuterRightCamera] =
|
||||||
|
sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0);
|
||||||
Settings::values.camera_name[InnerCamera] =
|
Settings::values.camera_name[InnerCamera] =
|
||||||
sdl2_config->Get("Camera", "camera_inner_name", "blank");
|
sdl2_config->Get("Camera", "camera_inner_name", "blank");
|
||||||
Settings::values.camera_config[InnerCamera] =
|
Settings::values.camera_config[InnerCamera] =
|
||||||
sdl2_config->Get("Camera", "camera_inner_config", "");
|
sdl2_config->Get("Camera", "camera_inner_config", "");
|
||||||
|
Settings::values.camera_flip[InnerCamera] =
|
||||||
|
sdl2_config->GetInteger("Camera", "camera_inner_flip", 0);
|
||||||
Settings::values.camera_name[OuterLeftCamera] =
|
Settings::values.camera_name[OuterLeftCamera] =
|
||||||
sdl2_config->Get("Camera", "camera_outer_left_name", "blank");
|
sdl2_config->Get("Camera", "camera_outer_left_name", "blank");
|
||||||
Settings::values.camera_config[OuterLeftCamera] =
|
Settings::values.camera_config[OuterLeftCamera] =
|
||||||
sdl2_config->Get("Camera", "camera_outer_left_config", "");
|
sdl2_config->Get("Camera", "camera_outer_left_config", "");
|
||||||
|
Settings::values.camera_flip[OuterLeftCamera] =
|
||||||
|
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info");
|
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info");
|
||||||
|
|
|
@ -178,13 +178,19 @@ camera_outer_right_name =
|
||||||
# A config string for the right outer camera. Its meaning is defined by the camera engine
|
# A config string for the right outer camera. Its meaning is defined by the camera engine
|
||||||
camera_outer_right_config =
|
camera_outer_right_config =
|
||||||
|
|
||||||
|
# The image flip to apply
|
||||||
|
# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse
|
||||||
|
camera_outer_right_flip =
|
||||||
|
|
||||||
# ... for the left outer camera
|
# ... for the left outer camera
|
||||||
camera_outer_left_name =
|
camera_outer_left_name =
|
||||||
camera_outer_left_config =
|
camera_outer_left_config =
|
||||||
|
camera_outer_left_flip =
|
||||||
|
|
||||||
# ... for the inner camera
|
# ... for the inner camera
|
||||||
camera_inner_name =
|
camera_inner_name =
|
||||||
camera_inner_config =
|
camera_inner_config =
|
||||||
|
camera_inner_flip =
|
||||||
|
|
||||||
[Miscellaneous]
|
[Miscellaneous]
|
||||||
# A filter which removes logs below a certain logging level.
|
# A filter which removes logs below a certain logging level.
|
||||||
|
|
|
@ -13,8 +13,8 @@ add_executable(citra-qt
|
||||||
camera/camera_util.h
|
camera/camera_util.h
|
||||||
camera/still_image_camera.cpp
|
camera/still_image_camera.cpp
|
||||||
camera/still_image_camera.h
|
camera/still_image_camera.h
|
||||||
camera/qt_camera_factory.cpp
|
camera/qt_camera_base.cpp
|
||||||
camera/qt_camera_factory.h
|
camera/qt_camera_base.h
|
||||||
camera/qt_multimedia_camera.cpp
|
camera/qt_multimedia_camera.cpp
|
||||||
camera/qt_multimedia_camera.h
|
camera/qt_multimedia_camera.h
|
||||||
citra-qt.rc
|
citra-qt.rc
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include "citra_qt/camera/camera_util.h"
|
||||||
|
#include "citra_qt/camera/qt_camera_base.h"
|
||||||
|
|
||||||
|
namespace Camera {
|
||||||
|
|
||||||
|
QtCameraInterface::QtCameraInterface(const Service::CAM::Flip& flip) {
|
||||||
|
using namespace Service::CAM;
|
||||||
|
flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
|
||||||
|
flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtCameraInterface::SetFormat(Service::CAM::OutputFormat output_format) {
|
||||||
|
output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtCameraInterface::SetResolution(const Service::CAM::Resolution& resolution) {
|
||||||
|
width = resolution.width;
|
||||||
|
height = resolution.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtCameraInterface::SetFlip(Service::CAM::Flip flip) {
|
||||||
|
using namespace Service::CAM;
|
||||||
|
flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
|
||||||
|
flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtCameraInterface::SetEffect(Service::CAM::Effect effect) {
|
||||||
|
if (effect != Service::CAM::Effect::None) {
|
||||||
|
NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u16> QtCameraInterface::ReceiveFrame() {
|
||||||
|
return CameraUtil::ProcessImage(QtReceiveFrame(), width, height, output_rgb, flip_horizontal,
|
||||||
|
flip_vertical);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
|
||||||
|
int width, int height,
|
||||||
|
const Service::CAM::Flip& flip) {
|
||||||
|
std::unique_ptr<CameraInterface> camera = Create(config, flip);
|
||||||
|
|
||||||
|
if (camera->IsPreviewAvailable()) {
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
QMessageBox::critical(
|
||||||
|
nullptr, QObject::tr("Error"),
|
||||||
|
(config.empty() ? QObject::tr("Couldn't load the camera")
|
||||||
|
: QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Camera
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "core/frontend/camera/factory.h"
|
||||||
|
|
||||||
|
namespace Camera {
|
||||||
|
|
||||||
|
// Base class for camera interfaces of citra_qt
|
||||||
|
class QtCameraInterface : public CameraInterface {
|
||||||
|
public:
|
||||||
|
QtCameraInterface(const Service::CAM::Flip& flip);
|
||||||
|
void SetResolution(const Service::CAM::Resolution&) override;
|
||||||
|
void SetFlip(Service::CAM::Flip) override;
|
||||||
|
void SetEffect(Service::CAM::Effect) override;
|
||||||
|
void SetFormat(Service::CAM::OutputFormat) override;
|
||||||
|
std::vector<u16> ReceiveFrame() override;
|
||||||
|
virtual QImage QtReceiveFrame() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int width, height;
|
||||||
|
bool output_rgb;
|
||||||
|
bool flip_horizontal, flip_vertical;
|
||||||
|
bool basic_flip_horizontal, basic_flip_vertical;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for camera factories of citra_qt
|
||||||
|
class QtCameraFactory : public CameraFactory {
|
||||||
|
std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
|
||||||
|
const Service::CAM::Flip& flip) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Camera
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2018 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include "citra_qt/camera/qt_camera_factory.h"
|
|
||||||
|
|
||||||
namespace Camera {
|
|
||||||
|
|
||||||
std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
|
|
||||||
int width, int height) const {
|
|
||||||
std::unique_ptr<CameraInterface> camera = Create(config);
|
|
||||||
|
|
||||||
if (camera->IsPreviewAvailable()) {
|
|
||||||
return camera;
|
|
||||||
}
|
|
||||||
QMessageBox::critical(
|
|
||||||
nullptr, QObject::tr("Error"),
|
|
||||||
(config.empty() ? QObject::tr("Couldn't load the camera")
|
|
||||||
: QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Camera
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright 2018 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "core/frontend/camera/factory.h"
|
|
||||||
|
|
||||||
namespace Camera {
|
|
||||||
|
|
||||||
// Base class for camera factories of citra_qt
|
|
||||||
class QtCameraFactory : public CameraFactory {
|
|
||||||
std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
|
|
||||||
int height) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Camera
|
|
|
@ -46,8 +46,9 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
|
QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
|
||||||
: handler(QtMultimediaCameraHandler::GetHandler()) {
|
const Service::CAM::Flip& flip)
|
||||||
|
: QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler(camera_name)) {
|
||||||
if (handler->thread() == QThread::currentThread()) {
|
if (handler->thread() == QThread::currentThread()) {
|
||||||
handler->CreateCamera(camera_name);
|
handler->CreateCamera(camera_name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,10 +74,6 @@ void QtMultimediaCamera::StopCapture() {
|
||||||
handler->StopCamera();
|
handler->StopCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) {
|
|
||||||
output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
|
void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
|
||||||
const std::array<QCamera::FrameRateRange, 13> FrameRateList = {
|
const std::array<QCamera::FrameRateRange, 13> FrameRateList = {
|
||||||
/* Rate_15 */ QCamera::FrameRateRange(15, 15),
|
/* Rate_15 */ QCamera::FrameRateRange(15, 15),
|
||||||
|
@ -96,57 +93,49 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
|
||||||
|
|
||||||
auto framerate = FrameRateList[static_cast<int>(frame_rate)];
|
auto framerate = FrameRateList[static_cast<int>(frame_rate)];
|
||||||
|
|
||||||
|
if (handler->camera->supportedViewfinderFrameRateRanges().contains(framerate)) {
|
||||||
handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
|
handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
|
||||||
handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
|
handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
|
||||||
}
|
|
||||||
|
|
||||||
void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) {
|
|
||||||
width = resolution.width;
|
|
||||||
height = resolution.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
|
|
||||||
using namespace Service::CAM;
|
|
||||||
flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
|
|
||||||
flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
|
|
||||||
if (effect != Service::CAM::Effect::None) {
|
|
||||||
NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u16> QtMultimediaCamera::ReceiveFrame() {
|
QImage QtMultimediaCamera::QtReceiveFrame() {
|
||||||
QMutexLocker locker(&handler->camera_surface.mutex);
|
QMutexLocker locker(&handler->camera_surface.mutex);
|
||||||
return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height,
|
return handler->camera_surface.current_frame;
|
||||||
output_rgb, flip_horizontal, flip_vertical);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QtMultimediaCamera::IsPreviewAvailable() {
|
bool QtMultimediaCamera::IsPreviewAvailable() {
|
||||||
return handler->CameraAvailable();
|
return handler->CameraAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
|
std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(const std::string& config,
|
||||||
const std::string& config) const {
|
const Service::CAM::Flip& flip) {
|
||||||
return std::make_unique<QtMultimediaCamera>(config);
|
return std::make_unique<QtMultimediaCamera>(config, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers;
|
std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers;
|
||||||
|
|
||||||
std::array<bool, 3> QtMultimediaCameraHandler::status;
|
std::array<bool, 3> QtMultimediaCameraHandler::status;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>>
|
||||||
|
QtMultimediaCameraHandler::loaded;
|
||||||
|
|
||||||
void QtMultimediaCameraHandler::Init() {
|
void QtMultimediaCameraHandler::Init() {
|
||||||
for (auto& handler : handlers) {
|
for (auto& handler : handlers) {
|
||||||
handler = std::make_shared<QtMultimediaCameraHandler>();
|
handler = std::make_shared<QtMultimediaCameraHandler>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler() {
|
std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler(
|
||||||
|
const std::string& camera_name) {
|
||||||
|
if (loaded.count(camera_name)) {
|
||||||
|
return loaded.at(camera_name);
|
||||||
|
}
|
||||||
for (int i = 0; i < handlers.size(); i++) {
|
for (int i = 0; i < handlers.size(); i++) {
|
||||||
if (!status[i]) {
|
if (!status[i]) {
|
||||||
NGLOG_INFO(Service_CAM, "Successfully got handler {}", i);
|
NGLOG_INFO(Service_CAM, "Successfully got handler {}", i);
|
||||||
status[i] = true;
|
status[i] = true;
|
||||||
|
loaded.emplace(camera_name, handlers[i]);
|
||||||
return handlers[i];
|
return handlers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +150,12 @@ void QtMultimediaCameraHandler::ReleaseHandler(
|
||||||
NGLOG_INFO(Service_CAM, "Successfully released handler {}", i);
|
NGLOG_INFO(Service_CAM, "Successfully released handler {}", i);
|
||||||
status[i] = false;
|
status[i] = false;
|
||||||
handlers[i]->started = false;
|
handlers[i]->started = false;
|
||||||
|
for (auto it = loaded.begin(); it != loaded.end(); it++) {
|
||||||
|
if (it->second == handlers[i]) {
|
||||||
|
loaded.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +173,7 @@ void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) {
|
||||||
settings.setMinimumFrameRate(30);
|
settings.setMinimumFrameRate(30);
|
||||||
settings.setMaximumFrameRate(30);
|
settings.setMaximumFrameRate(30);
|
||||||
camera->setViewfinder(&camera_surface);
|
camera->setViewfinder(&camera_surface);
|
||||||
|
camera->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtMultimediaCameraHandler::StopCamera() {
|
void QtMultimediaCameraHandler::StopCamera() {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QAbstractVideoSurface>
|
#include <QAbstractVideoSurface>
|
||||||
#include <QCamera>
|
#include <QCamera>
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include "citra_qt/camera/camera_util.h"
|
#include "citra_qt/camera/camera_util.h"
|
||||||
#include "citra_qt/camera/qt_camera_factory.h"
|
#include "citra_qt/camera/qt_camera_base.h"
|
||||||
#include "core/frontend/camera/interface.h"
|
#include "core/frontend/camera/interface.h"
|
||||||
|
|
||||||
class GMainWindow;
|
class GMainWindow;
|
||||||
|
@ -36,30 +37,24 @@ private:
|
||||||
class QtMultimediaCameraHandler;
|
class QtMultimediaCameraHandler;
|
||||||
|
|
||||||
/// This class is only an interface. It just calls QtMultimediaCameraHandler.
|
/// This class is only an interface. It just calls QtMultimediaCameraHandler.
|
||||||
class QtMultimediaCamera final : public CameraInterface {
|
class QtMultimediaCamera final : public QtCameraInterface {
|
||||||
public:
|
public:
|
||||||
QtMultimediaCamera(const std::string& camera_name);
|
QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip);
|
||||||
~QtMultimediaCamera();
|
~QtMultimediaCamera();
|
||||||
void StartCapture() override;
|
void StartCapture() override;
|
||||||
void StopCapture() override;
|
void StopCapture() override;
|
||||||
void SetResolution(const Service::CAM::Resolution&) override;
|
|
||||||
void SetFlip(Service::CAM::Flip) override;
|
|
||||||
void SetEffect(Service::CAM::Effect) override;
|
|
||||||
void SetFormat(Service::CAM::OutputFormat) override;
|
|
||||||
void SetFrameRate(Service::CAM::FrameRate frame_rate) override;
|
void SetFrameRate(Service::CAM::FrameRate frame_rate) override;
|
||||||
std::vector<u16> ReceiveFrame() override;
|
QImage QtReceiveFrame() override;
|
||||||
bool IsPreviewAvailable() override;
|
bool IsPreviewAvailable() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<QtMultimediaCameraHandler> handler;
|
std::shared_ptr<QtMultimediaCameraHandler> handler;
|
||||||
int width, height;
|
|
||||||
bool output_rgb;
|
|
||||||
bool flip_horizontal, flip_vertical;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class QtMultimediaCameraFactory final : public QtCameraFactory {
|
class QtMultimediaCameraFactory final : public QtCameraFactory {
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
|
std::unique_ptr<CameraInterface> Create(const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QtMultimediaCameraHandler final : public QObject {
|
class QtMultimediaCameraHandler final : public QObject {
|
||||||
|
@ -68,7 +63,7 @@ class QtMultimediaCameraHandler final : public QObject {
|
||||||
public:
|
public:
|
||||||
/// Creates the global handler. Must be called in UI thread.
|
/// Creates the global handler. Must be called in UI thread.
|
||||||
static void Init();
|
static void Init();
|
||||||
static std::shared_ptr<QtMultimediaCameraHandler> GetHandler();
|
static std::shared_ptr<QtMultimediaCameraHandler> GetHandler(const std::string& camera_name);
|
||||||
static void ReleaseHandler(const std::shared_ptr<QtMultimediaCameraHandler>& handler);
|
static void ReleaseHandler(const std::shared_ptr<QtMultimediaCameraHandler>& handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +93,7 @@ private:
|
||||||
|
|
||||||
static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers;
|
static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers;
|
||||||
static std::array<bool, 3> status;
|
static std::array<bool, 3> status;
|
||||||
|
static std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>> loaded;
|
||||||
|
|
||||||
friend class QtMultimediaCamera; // For access to camera_surface (and camera)
|
friend class QtMultimediaCamera; // For access to camera_surface (and camera)
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,47 +5,36 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QThread>
|
||||||
#include "citra_qt/camera/still_image_camera.h"
|
#include "citra_qt/camera/still_image_camera.h"
|
||||||
|
|
||||||
namespace Camera {
|
namespace Camera {
|
||||||
|
|
||||||
StillImageCamera::StillImageCamera(QImage image_) : image(std::move(image_)) {}
|
StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
|
||||||
|
: QtCameraInterface(flip), image(std::move(image_)) {}
|
||||||
|
|
||||||
|
StillImageCamera::~StillImageCamera() {
|
||||||
|
StillImageCameraFactory::last_path.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void StillImageCamera::StartCapture() {}
|
void StillImageCamera::StartCapture() {}
|
||||||
|
|
||||||
void StillImageCamera::StopCapture() {}
|
void StillImageCamera::StopCapture() {}
|
||||||
|
|
||||||
void StillImageCamera::SetFormat(Service::CAM::OutputFormat output_format) {
|
QImage StillImageCamera::QtReceiveFrame() {
|
||||||
output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
|
return image;
|
||||||
}
|
|
||||||
|
|
||||||
void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution) {
|
|
||||||
width = resolution.width;
|
|
||||||
height = resolution.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StillImageCamera::SetFlip(Service::CAM::Flip flip) {
|
|
||||||
using namespace Service::CAM;
|
|
||||||
flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
|
|
||||||
flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StillImageCamera::SetEffect(Service::CAM::Effect effect) {
|
|
||||||
if (effect != Service::CAM::Effect::None) {
|
|
||||||
NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u16> StillImageCamera::ReceiveFrame() {
|
|
||||||
return CameraUtil::ProcessImage(image, width, height, output_rgb, flip_horizontal,
|
|
||||||
flip_vertical);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StillImageCamera::IsPreviewAvailable() {
|
bool StillImageCamera::IsPreviewAvailable() {
|
||||||
return !image.isNull();
|
return !image.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string StillImageCameraFactory::getFilePath() {
|
std::string StillImageCameraFactory::last_path;
|
||||||
|
|
||||||
|
const std::string StillImageCameraFactory::GetFilePath() const {
|
||||||
|
if (!last_path.empty()) {
|
||||||
|
return last_path;
|
||||||
|
}
|
||||||
QList<QByteArray> types = QImageReader::supportedImageFormats();
|
QList<QByteArray> types = QImageReader::supportedImageFormats();
|
||||||
QList<QString> temp_filters;
|
QList<QString> temp_filters;
|
||||||
for (QByteArray type : types) {
|
for (QByteArray type : types) {
|
||||||
|
@ -53,21 +42,29 @@ const std::string StillImageCameraFactory::getFilePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
|
QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
|
||||||
|
last_path =
|
||||||
return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter)
|
QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter).toStdString();
|
||||||
.toStdString();
|
return last_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config) const {
|
std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip) {
|
||||||
std::string real_config = config;
|
std::string real_config = config;
|
||||||
if (config.empty()) {
|
if (config.empty()) {
|
||||||
real_config = getFilePath();
|
// call GetFilePath() in UI thread (note: StillImageCameraFactory itself is initialized in
|
||||||
|
// UI thread, so we can just pass in "this" here)
|
||||||
|
if (thread() == QThread::currentThread()) {
|
||||||
|
real_config = GetFilePath();
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(this, "GetFilePath", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(std::string, real_config));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QImage image(QString::fromStdString(real_config));
|
QImage image(QString::fromStdString(real_config));
|
||||||
if (image.isNull()) {
|
if (image.isNull()) {
|
||||||
NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str());
|
NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str());
|
||||||
}
|
}
|
||||||
return std::make_unique<StillImageCamera>(image);
|
return std::make_unique<StillImageCamera>(image, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Camera
|
} // namespace Camera
|
||||||
|
|
|
@ -7,37 +7,39 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include "citra_qt/camera/camera_util.h"
|
#include "citra_qt/camera/camera_util.h"
|
||||||
#include "citra_qt/camera/qt_camera_factory.h"
|
#include "citra_qt/camera/qt_camera_base.h"
|
||||||
#include "core/frontend/camera/interface.h"
|
#include "core/frontend/camera/interface.h"
|
||||||
|
|
||||||
namespace Camera {
|
namespace Camera {
|
||||||
|
|
||||||
class StillImageCamera final : public CameraInterface {
|
class StillImageCamera final : public QtCameraInterface {
|
||||||
public:
|
public:
|
||||||
StillImageCamera(QImage image);
|
StillImageCamera(QImage image, const Service::CAM::Flip& flip);
|
||||||
|
~StillImageCamera();
|
||||||
void StartCapture() override;
|
void StartCapture() override;
|
||||||
void StopCapture() override;
|
void StopCapture() override;
|
||||||
void SetResolution(const Service::CAM::Resolution&) override;
|
|
||||||
void SetFlip(Service::CAM::Flip) override;
|
|
||||||
void SetEffect(Service::CAM::Effect) override;
|
|
||||||
void SetFormat(Service::CAM::OutputFormat) override;
|
|
||||||
void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
|
void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
|
||||||
std::vector<u16> ReceiveFrame() override;
|
QImage QtReceiveFrame() override;
|
||||||
bool IsPreviewAvailable() override;
|
bool IsPreviewAvailable() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QImage image;
|
QImage image;
|
||||||
int width, height;
|
|
||||||
bool output_rgb;
|
|
||||||
bool flip_horizontal, flip_vertical;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class StillImageCameraFactory final : public QtCameraFactory {
|
class StillImageCameraFactory final : public QObject, public QtCameraFactory {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
|
std::unique_ptr<CameraInterface> Create(const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip) override;
|
||||||
|
|
||||||
|
Q_INVOKABLE const std::string GetFilePath() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const std::string getFilePath();
|
/// Record the path chosen to avoid multiple prompt problem
|
||||||
|
static std::string last_path;
|
||||||
|
|
||||||
|
friend class StillImageCamera;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Camera
|
} // namespace Camera
|
||||||
|
|
|
@ -128,14 +128,19 @@ void Config::ReadValues() {
|
||||||
qt_config->value("camera_outer_right_name", "blank").toString().toStdString();
|
qt_config->value("camera_outer_right_name", "blank").toString().toStdString();
|
||||||
Settings::values.camera_config[OuterRightCamera] =
|
Settings::values.camera_config[OuterRightCamera] =
|
||||||
qt_config->value("camera_outer_right_config", "").toString().toStdString();
|
qt_config->value("camera_outer_right_config", "").toString().toStdString();
|
||||||
|
Settings::values.camera_flip[OuterRightCamera] =
|
||||||
|
qt_config->value("camera_outer_right_flip", "0").toInt();
|
||||||
Settings::values.camera_name[InnerCamera] =
|
Settings::values.camera_name[InnerCamera] =
|
||||||
qt_config->value("camera_inner_name", "blank").toString().toStdString();
|
qt_config->value("camera_inner_name", "blank").toString().toStdString();
|
||||||
Settings::values.camera_config[InnerCamera] =
|
Settings::values.camera_config[InnerCamera] =
|
||||||
qt_config->value("camera_inner_config", "").toString().toStdString();
|
qt_config->value("camera_inner_config", "").toString().toStdString();
|
||||||
|
Settings::values.camera_flip[InnerCamera] = qt_config->value("camera_inner_flip", "").toInt();
|
||||||
Settings::values.camera_name[OuterLeftCamera] =
|
Settings::values.camera_name[OuterLeftCamera] =
|
||||||
qt_config->value("camera_outer_left_name", "blank").toString().toStdString();
|
qt_config->value("camera_outer_left_name", "blank").toString().toStdString();
|
||||||
Settings::values.camera_config[OuterLeftCamera] =
|
Settings::values.camera_config[OuterLeftCamera] =
|
||||||
qt_config->value("camera_outer_left_config", "").toString().toStdString();
|
qt_config->value("camera_outer_left_config", "").toString().toStdString();
|
||||||
|
Settings::values.camera_flip[OuterLeftCamera] =
|
||||||
|
qt_config->value("camera_outer_left_flip", "").toInt();
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Data Storage");
|
qt_config->beginGroup("Data Storage");
|
||||||
|
@ -317,14 +322,17 @@ void Config::SaveValues() {
|
||||||
QString::fromStdString(Settings::values.camera_name[OuterRightCamera]));
|
QString::fromStdString(Settings::values.camera_name[OuterRightCamera]));
|
||||||
qt_config->setValue("camera_outer_right_config",
|
qt_config->setValue("camera_outer_right_config",
|
||||||
QString::fromStdString(Settings::values.camera_config[OuterRightCamera]));
|
QString::fromStdString(Settings::values.camera_config[OuterRightCamera]));
|
||||||
|
qt_config->setValue("camera_outer_right_flip", Settings::values.camera_flip[OuterRightCamera]);
|
||||||
qt_config->setValue("camera_inner_name",
|
qt_config->setValue("camera_inner_name",
|
||||||
QString::fromStdString(Settings::values.camera_name[InnerCamera]));
|
QString::fromStdString(Settings::values.camera_name[InnerCamera]));
|
||||||
qt_config->setValue("camera_inner_config",
|
qt_config->setValue("camera_inner_config",
|
||||||
QString::fromStdString(Settings::values.camera_config[InnerCamera]));
|
QString::fromStdString(Settings::values.camera_config[InnerCamera]));
|
||||||
|
qt_config->setValue("camera_inner_flip", Settings::values.camera_flip[InnerCamera]);
|
||||||
qt_config->setValue("camera_outer_left_name",
|
qt_config->setValue("camera_outer_left_name",
|
||||||
QString::fromStdString(Settings::values.camera_name[OuterLeftCamera]));
|
QString::fromStdString(Settings::values.camera_name[OuterLeftCamera]));
|
||||||
qt_config->setValue("camera_outer_left_config",
|
qt_config->setValue("camera_outer_left_config",
|
||||||
QString::fromStdString(Settings::values.camera_config[OuterLeftCamera]));
|
QString::fromStdString(Settings::values.camera_config[OuterLeftCamera]));
|
||||||
|
qt_config->setValue("camera_outer_left_flip", Settings::values.camera_flip[OuterLeftCamera]);
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Data Storage");
|
qt_config->beginGroup("Data Storage");
|
||||||
|
|
|
@ -27,14 +27,7 @@ ConfigureCamera::ConfigureCamera(QWidget* parent)
|
||||||
// Load settings
|
// Load settings
|
||||||
camera_name = Settings::values.camera_name;
|
camera_name = Settings::values.camera_name;
|
||||||
camera_config = Settings::values.camera_config;
|
camera_config = Settings::values.camera_config;
|
||||||
for (auto&& item : camera_name) {
|
camera_flip = Settings::values.camera_flip;
|
||||||
if (item == "opencv") {
|
|
||||||
QMessageBox::critical(this, tr("Error"),
|
|
||||||
tr("Sorry, Citra has removed support for OpenCV cameras.\n\nYour "
|
|
||||||
"existing OpenCV cameras have been replaced with Blank."));
|
|
||||||
item = "blank";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
|
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
|
||||||
for (const QCameraInfo& cameraInfo : cameras) {
|
for (const QCameraInfo& cameraInfo : cameras) {
|
||||||
ui->system_camera->addItem(cameraInfo.deviceName());
|
ui->system_camera->addItem(cameraInfo.deviceName());
|
||||||
|
@ -98,6 +91,8 @@ void ConfigureCamera::connectEvents() {
|
||||||
connect(ui->system_camera,
|
connect(ui->system_camera,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||||
[=] { stopPreviewing(); });
|
[=] { stopPreviewing(); });
|
||||||
|
connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, [=] { stopPreviewing(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCamera::updateCameraMode() {
|
void ConfigureCamera::updateCameraMode() {
|
||||||
|
@ -148,6 +143,8 @@ void ConfigureCamera::updateImageSourceUI() {
|
||||||
}
|
}
|
||||||
ui->system_camera_label->setHidden(image_source != 2);
|
ui->system_camera_label->setHidden(image_source != 2);
|
||||||
ui->system_camera->setHidden(image_source != 2);
|
ui->system_camera->setHidden(image_source != 2);
|
||||||
|
ui->camera_flip_label->setHidden(image_source == 0);
|
||||||
|
ui->camera_flip->setHidden(image_source == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCamera::recordConfig() {
|
void ConfigureCamera::recordConfig() {
|
||||||
|
@ -166,10 +163,12 @@ void ConfigureCamera::recordConfig() {
|
||||||
if (current_selected == CameraPosition::RearBoth) {
|
if (current_selected == CameraPosition::RearBoth) {
|
||||||
camera_name[0] = camera_name[2] = implementation;
|
camera_name[0] = camera_name[2] = implementation;
|
||||||
camera_config[0] = camera_config[2] = config;
|
camera_config[0] = camera_config[2] = config;
|
||||||
|
camera_flip[0] = camera_flip[2] = ui->camera_flip->currentIndex();
|
||||||
} else if (current_selected != CameraPosition::Null) {
|
} else if (current_selected != CameraPosition::Null) {
|
||||||
int index = static_cast<int>(current_selected);
|
int index = static_cast<int>(current_selected);
|
||||||
camera_name[index] = implementation;
|
camera_name[index] = implementation;
|
||||||
camera_config[index] = config;
|
camera_config[index] = config;
|
||||||
|
camera_flip[index] = ui->camera_flip->currentIndex();
|
||||||
}
|
}
|
||||||
current_selected = getCameraSelection();
|
current_selected = getCameraSelection();
|
||||||
}
|
}
|
||||||
|
@ -187,9 +186,9 @@ void ConfigureCamera::startPreviewing() {
|
||||||
ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" +
|
ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" +
|
||||||
QString::number(preview_height));
|
QString::number(preview_height));
|
||||||
// Load previewing camera
|
// Load previewing camera
|
||||||
previewing_camera =
|
previewing_camera = Camera::CreateCameraPreview(
|
||||||
Camera::CreateCameraPreview(camera_name[camera_selection], camera_config[camera_selection],
|
camera_name[camera_selection], camera_config[camera_selection], preview_width,
|
||||||
preview_width, preview_height);
|
preview_height, static_cast<Service::CAM::Flip>(camera_flip[camera_selection]));
|
||||||
if (!previewing_camera) {
|
if (!previewing_camera) {
|
||||||
stopPreviewing();
|
stopPreviewing();
|
||||||
return;
|
return;
|
||||||
|
@ -262,6 +261,7 @@ void ConfigureCamera::setConfiguration() {
|
||||||
} else {
|
} else {
|
||||||
ui->camera_file->setText(QString::fromStdString(camera_config[index]));
|
ui->camera_file->setText(QString::fromStdString(camera_config[index]));
|
||||||
}
|
}
|
||||||
|
ui->camera_flip->setCurrentIndex(camera_flip[index]);
|
||||||
updateImageSourceUI();
|
updateImageSourceUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +288,7 @@ void ConfigureCamera::applyConfiguration() {
|
||||||
stopPreviewing();
|
stopPreviewing();
|
||||||
Settings::values.camera_name = camera_name;
|
Settings::values.camera_name = camera_name;
|
||||||
Settings::values.camera_config = camera_config;
|
Settings::values.camera_config = camera_config;
|
||||||
|
Settings::values.camera_flip = camera_flip;
|
||||||
Settings::Apply();
|
Settings::Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ private:
|
||||||
std::unique_ptr<Ui::ConfigureCamera> ui;
|
std::unique_ptr<Ui::ConfigureCamera> ui;
|
||||||
std::array<std::string, 3> camera_name;
|
std::array<std::string, 3> camera_name;
|
||||||
std::array<std::string, 3> camera_config;
|
std::array<std::string, 3> camera_config;
|
||||||
|
std::array<int, 3> camera_flip;
|
||||||
int timer_id = 0;
|
int timer_id = 0;
|
||||||
int preview_width = 0;
|
int preview_width = 0;
|
||||||
int preview_height = 0;
|
int preview_height = 0;
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ConfigureCamera</class>
|
<class>ConfigureCamera</class>
|
||||||
<widget class="QWidget" name="ConfigureCamera">
|
<widget class="QWidget" name="ConfigureCamera">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
@ -127,7 +137,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="image_source">
|
<widget class="QComboBox" name="image_source">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Select where the image of the emulated camera come from. It may be an image or a real camera.</string>
|
<string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -179,6 +189,9 @@
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select the system camera to use</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Camera:</string>
|
<string>Camera:</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -186,6 +199,21 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="system_camera">
|
<widget class="QComboBox" name="system_camera">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>250</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select the system camera to use</string>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><Default></string>
|
<string><Default></string>
|
||||||
|
@ -195,8 +223,70 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="camera_flip_label">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select the image flip to apply</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Flip:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="camera_flip">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>800</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select the image flip to apply</string>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Horizontal</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Vertical</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reverse</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="prompt_before_load">
|
<widget class="QCheckBox" name="prompt_before_load">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select an image file every time before the camera is loaded</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Prompt before load</string>
|
<string>Prompt before load</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -173,14 +173,20 @@ public:
|
||||||
&extension);
|
&extension);
|
||||||
QString title = data(TitleRole).toString();
|
QString title = data(TitleRole).toString();
|
||||||
QString second_name = QString::fromStdString(filename + extension);
|
QString second_name = QString::fromStdString(filename + extension);
|
||||||
static QRegExp installed_system_pattern(
|
static QRegExp installed_pattern(
|
||||||
QString::fromStdString(
|
QString::fromStdString(
|
||||||
FileUtil::GetUserPath(D_SDMC_IDX) +
|
FileUtil::GetUserPath(D_SDMC_IDX) +
|
||||||
"Nintendo "
|
"Nintendo "
|
||||||
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/"
|
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/"
|
||||||
"title/000400(0|1)0/[0-9a-f]{8}/content/")
|
"title/0004000(0|e)/[0-9a-f]{8}/content/")
|
||||||
.replace("\\", "\\\\"));
|
.replace("\\", "\\\\"));
|
||||||
if (installed_system_pattern.exactMatch(QString::fromStdString(path))) {
|
static QRegExp system_pattern(
|
||||||
|
QString::fromStdString(FileUtil::GetUserPath(D_NAND_IDX) +
|
||||||
|
"00000000000000000000000000000000/"
|
||||||
|
"title/00040010/[0-9a-f]{8}/content/")
|
||||||
|
.replace("\\", "\\\\"));
|
||||||
|
if (installed_pattern.exactMatch(QString::fromStdString(path)) ||
|
||||||
|
system_pattern.exactMatch(QString::fromStdString(path))) {
|
||||||
// Use a different mechanism for system / installed titles showing program ID
|
// Use a different mechanism for system / installed titles showing program ID
|
||||||
second_name = QString("%1-%2")
|
second_name = QString("%1-%2")
|
||||||
.arg(data(ProgramIdRole).toULongLong(), 16, 16, QChar('0'))
|
.arg(data(ProgramIdRole).toULongLong(), 16, 16, QChar('0'))
|
||||||
|
|
|
@ -3866,6 +3866,8 @@ SWI_INST : {
|
||||||
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
||||||
num_instrs = 0;
|
num_instrs = 0;
|
||||||
Kernel::CallSVC(inst_cream->num & 0xFFFF);
|
Kernel::CallSVC(inst_cream->num & 0xFFFF);
|
||||||
|
// The kernel would call ERET to get here, which clears exclusive memory state.
|
||||||
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->Reg[15] += cpu->GetInstructionSize();
|
cpu->Reg[15] += cpu->GetInstructionSize();
|
||||||
|
|
|
@ -17,28 +17,29 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
|
||||||
factories[name] = std::move(factory);
|
factories[name] = std::move(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config) {
|
std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip) {
|
||||||
auto pair = factories.find(name);
|
auto pair = factories.find(name);
|
||||||
if (pair != factories.end()) {
|
if (pair != factories.end()) {
|
||||||
return pair->second->Create(config);
|
return pair->second->Create(config, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != "blank") {
|
if (name != "blank") {
|
||||||
NGLOG_ERROR(Service_CAM, "Unknown camera \"{}\"", name);
|
NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
|
||||||
}
|
}
|
||||||
return std::make_unique<BlankCamera>();
|
return std::make_unique<BlankCamera>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
|
std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
|
||||||
const std::string& config, int width,
|
const std::string& config, int width,
|
||||||
int height) {
|
int height, const Service::CAM::Flip& flip) {
|
||||||
auto pair = factories.find(name);
|
auto pair = factories.find(name);
|
||||||
if (pair != factories.end()) {
|
if (pair != factories.end()) {
|
||||||
return pair->second->CreatePreview(config, width, height);
|
return pair->second->CreatePreview(config, width, height, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != "blank") {
|
if (name != "blank") {
|
||||||
NGLOG_ERROR(Service_CAM, "Unknown camera \"{}\"", name);
|
NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
|
||||||
}
|
}
|
||||||
return std::make_unique<BlankCamera>();
|
return std::make_unique<BlankCamera>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,22 +18,26 @@ public:
|
||||||
* Creates a camera object based on the configuration string.
|
* Creates a camera object based on the configuration string.
|
||||||
* @param config Configuration string to create the camera. The implementation can decide the
|
* @param config Configuration string to create the camera. The implementation can decide the
|
||||||
* meaning of this string.
|
* meaning of this string.
|
||||||
|
* @param flip The image flip to apply
|
||||||
* @returns a unique_ptr to the created camera object.
|
* @returns a unique_ptr to the created camera object.
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<CameraInterface> Create(const std::string& config) const = 0;
|
virtual std::unique_ptr<CameraInterface> Create(const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a camera object for preview based on the configuration string.
|
* Creates a camera object for preview based on the configuration string.
|
||||||
* @param config Configuration string to create the camera. The implementation can decide the
|
* @param config Configuration string to create the camera. The implementation can decide the
|
||||||
* meaning of this string.
|
* meaning of this string.
|
||||||
|
* @param flip The image flip to apply
|
||||||
* @returns a unique_ptr to the created camera object.
|
* @returns a unique_ptr to the created camera object.
|
||||||
* Note: The default implementation for this is to call Create(). Derived classes may have other
|
* Note: The default implementation for this is to call Create(). Derived classes may have other
|
||||||
* Implementations. For example, A dialog may be used instead of NGLOG_ERROR when error
|
* Implementations. For example, A dialog may be used instead of NGLOG_ERROR when error
|
||||||
* occurs.
|
* occurs.
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
|
virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
|
||||||
int height) const {
|
int height,
|
||||||
return Create(config);
|
const Service::CAM::Flip& flip) {
|
||||||
|
return Create(config, flip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +54,8 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
|
||||||
* @param config Configuration string to create the camera. The meaning of this string is
|
* @param config Configuration string to create the camera. The meaning of this string is
|
||||||
* defined by the factory.
|
* defined by the factory.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config);
|
std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
|
||||||
|
const Service::CAM::Flip& flip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a camera from the factory for previewing.
|
* Creates a camera from the factory for previewing.
|
||||||
|
@ -60,6 +65,6 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
|
std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
|
||||||
const std::string& config, int width,
|
const std::string& config, int width,
|
||||||
int height);
|
int height, const Service::CAM::Flip& flip);
|
||||||
|
|
||||||
} // namespace Camera
|
} // namespace Camera
|
||||||
|
|
|
@ -404,7 +404,7 @@ void ReceiveProperty(Service::Interface* self) {
|
||||||
|
|
||||||
cmd_buff[0] = IPC::MakeHeader(0x16, 0x2, 0x2);
|
cmd_buff[0] = IPC::MakeHeader(0x16, 0x2, 0x2);
|
||||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||||
cmd_buff[2] = 0; // stub 0 (32 bit value)
|
cmd_buff[2] = buff_size; // Should be actual number of read bytes.
|
||||||
cmd_buff[3] = (buff_size << 4 | 0xC);
|
cmd_buff[3] = (buff_size << 4 | 0xC);
|
||||||
cmd_buff[4] = buff_addr;
|
cmd_buff[4] = buff_addr;
|
||||||
|
|
||||||
|
|
|
@ -1041,8 +1041,9 @@ void Module::ReloadCameraDevices() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::LoadCameraImplementation(CameraConfig& camera, int camera_id) {
|
void Module::LoadCameraImplementation(CameraConfig& camera, int camera_id) {
|
||||||
camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id],
|
camera.impl = Camera::CreateCamera(
|
||||||
Settings::values.camera_config[camera_id]);
|
Settings::values.camera_name[camera_id], Settings::values.camera_config[camera_id],
|
||||||
|
static_cast<Service::CAM::Flip>(Settings::values.camera_flip[camera_id]));
|
||||||
camera.impl->SetFlip(camera.contexts[0].flip);
|
camera.impl->SetFlip(camera.contexts[0].flip);
|
||||||
camera.impl->SetEffect(camera.contexts[0].effect);
|
camera.impl->SetEffect(camera.contexts[0].effect);
|
||||||
camera.impl->SetFormat(camera.contexts[0].format);
|
camera.impl->SetFormat(camera.contexts[0].format);
|
||||||
|
|
|
@ -140,6 +140,7 @@ struct Values {
|
||||||
// Camera
|
// Camera
|
||||||
std::array<std::string, Service::CAM::NumCameras> camera_name;
|
std::array<std::string, Service::CAM::NumCameras> camera_name;
|
||||||
std::array<std::string, Service::CAM::NumCameras> camera_config;
|
std::array<std::string, Service::CAM::NumCameras> camera_config;
|
||||||
|
std::array<int, Service::CAM::NumCameras> camera_flip;
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
bool use_gdbstub;
|
bool use_gdbstub;
|
||||||
|
|
|
@ -68,7 +68,7 @@ const JitFunction instr_table[64] = {
|
||||||
nullptr, // unknown
|
nullptr, // unknown
|
||||||
&JitShader::Compile_NOP, // nop
|
&JitShader::Compile_NOP, // nop
|
||||||
&JitShader::Compile_END, // end
|
&JitShader::Compile_END, // end
|
||||||
nullptr, // break
|
&JitShader::Compile_BREAKC, // breakc
|
||||||
&JitShader::Compile_CALL, // call
|
&JitShader::Compile_CALL, // call
|
||||||
&JitShader::Compile_CALLC, // callc
|
&JitShader::Compile_CALLC, // callc
|
||||||
&JitShader::Compile_CALLU, // callu
|
&JitShader::Compile_CALLU, // callu
|
||||||
|
@ -580,10 +580,30 @@ void JitShader::Compile_RSQ(Instruction instr) {
|
||||||
void JitShader::Compile_NOP(Instruction instr) {}
|
void JitShader::Compile_NOP(Instruction instr) {}
|
||||||
|
|
||||||
void JitShader::Compile_END(Instruction instr) {
|
void JitShader::Compile_END(Instruction instr) {
|
||||||
|
// Save conditional code
|
||||||
|
mov(byte[STATE + offsetof(UnitState, conditional_code[0])], COND0.cvt8());
|
||||||
|
mov(byte[STATE + offsetof(UnitState, conditional_code[1])], COND1.cvt8());
|
||||||
|
|
||||||
|
// Save address/loop registers
|
||||||
|
sar(ADDROFFS_REG_0, 4);
|
||||||
|
sar(ADDROFFS_REG_1, 4);
|
||||||
|
sar(LOOPCOUNT_REG, 4);
|
||||||
|
mov(dword[STATE + offsetof(UnitState, address_registers[0])], ADDROFFS_REG_0.cvt32());
|
||||||
|
mov(dword[STATE + offsetof(UnitState, address_registers[1])], ADDROFFS_REG_1.cvt32());
|
||||||
|
mov(dword[STATE + offsetof(UnitState, address_registers[2])], LOOPCOUNT_REG);
|
||||||
|
|
||||||
ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8, 16);
|
ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8, 16);
|
||||||
ret();
|
ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitShader::Compile_BREAKC(Instruction instr) {
|
||||||
|
Compile_Assert(looping, "BREAKC must be inside a LOOP");
|
||||||
|
if (looping) {
|
||||||
|
Compile_EvaluateCondition(instr);
|
||||||
|
jnz(*loop_break_label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JitShader::Compile_CALL(Instruction instr) {
|
void JitShader::Compile_CALL(Instruction instr) {
|
||||||
// Push offset of the return
|
// Push offset of the return
|
||||||
push(qword, (instr.flow_control.dest_offset + instr.flow_control.num_instructions));
|
push(qword, (instr.flow_control.dest_offset + instr.flow_control.num_instructions));
|
||||||
|
@ -727,11 +747,14 @@ void JitShader::Compile_LOOP(Instruction instr) {
|
||||||
Label l_loop_start;
|
Label l_loop_start;
|
||||||
L(l_loop_start);
|
L(l_loop_start);
|
||||||
|
|
||||||
|
loop_break_label = Xbyak::Label();
|
||||||
Compile_Block(instr.flow_control.dest_offset + 1);
|
Compile_Block(instr.flow_control.dest_offset + 1);
|
||||||
|
|
||||||
add(LOOPCOUNT_REG, LOOPINC); // Increment LOOPCOUNT_REG by Z-component
|
add(LOOPCOUNT_REG, LOOPINC); // Increment LOOPCOUNT_REG by Z-component
|
||||||
sub(LOOPCOUNT, 1); // Increment loop count by 1
|
sub(LOOPCOUNT, 1); // Increment loop count by 1
|
||||||
jnz(l_loop_start); // Loop if not equal
|
jnz(l_loop_start); // Loop if not equal
|
||||||
|
L(*loop_break_label);
|
||||||
|
loop_break_label = boost::none;
|
||||||
|
|
||||||
looping = false;
|
looping = false;
|
||||||
}
|
}
|
||||||
|
@ -885,10 +908,17 @@ void JitShader::Compile(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>* program_
|
||||||
mov(UNIFORMS, ABI_PARAM1);
|
mov(UNIFORMS, ABI_PARAM1);
|
||||||
mov(STATE, ABI_PARAM2);
|
mov(STATE, ABI_PARAM2);
|
||||||
|
|
||||||
// Zero address/loop registers
|
// Load address/loop registers
|
||||||
xor_(ADDROFFS_REG_0.cvt32(), ADDROFFS_REG_0.cvt32());
|
movsxd(ADDROFFS_REG_0, dword[STATE + offsetof(UnitState, address_registers[0])]);
|
||||||
xor_(ADDROFFS_REG_1.cvt32(), ADDROFFS_REG_1.cvt32());
|
movsxd(ADDROFFS_REG_1, dword[STATE + offsetof(UnitState, address_registers[1])]);
|
||||||
xor_(LOOPCOUNT_REG, LOOPCOUNT_REG);
|
mov(LOOPCOUNT_REG, dword[STATE + offsetof(UnitState, address_registers[2])]);
|
||||||
|
shl(ADDROFFS_REG_0, 4);
|
||||||
|
shl(ADDROFFS_REG_1, 4);
|
||||||
|
shl(LOOPCOUNT_REG, 4);
|
||||||
|
|
||||||
|
// Load conditional code
|
||||||
|
mov(COND0, byte[STATE + offsetof(UnitState, conditional_code[0])]);
|
||||||
|
mov(COND1, byte[STATE + offsetof(UnitState, conditional_code[1])]);
|
||||||
|
|
||||||
// Used to set a register to one
|
// Used to set a register to one
|
||||||
static const __m128 one = {1.f, 1.f, 1.f, 1.f};
|
static const __m128 one = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <nihstro/shader_bytecode.h>
|
#include <nihstro/shader_bytecode.h>
|
||||||
#include <xbyak.h>
|
#include <xbyak.h>
|
||||||
#include "common/bit_set.h"
|
#include "common/bit_set.h"
|
||||||
|
@ -58,6 +59,7 @@ public:
|
||||||
void Compile_MOV(Instruction instr);
|
void Compile_MOV(Instruction instr);
|
||||||
void Compile_NOP(Instruction instr);
|
void Compile_NOP(Instruction instr);
|
||||||
void Compile_END(Instruction instr);
|
void Compile_END(Instruction instr);
|
||||||
|
void Compile_BREAKC(Instruction instr);
|
||||||
void Compile_CALL(Instruction instr);
|
void Compile_CALL(Instruction instr);
|
||||||
void Compile_CALLC(Instruction instr);
|
void Compile_CALLC(Instruction instr);
|
||||||
void Compile_CALLU(Instruction instr);
|
void Compile_CALLU(Instruction instr);
|
||||||
|
@ -119,6 +121,10 @@ private:
|
||||||
/// Mapping of Pica VS instructions to pointers in the emitted code
|
/// Mapping of Pica VS instructions to pointers in the emitted code
|
||||||
std::array<Xbyak::Label, MAX_PROGRAM_CODE_LENGTH> instruction_labels;
|
std::array<Xbyak::Label, MAX_PROGRAM_CODE_LENGTH> instruction_labels;
|
||||||
|
|
||||||
|
/// Label pointing to the end of the current LOOP block. Used by the BREAKC instruction to break
|
||||||
|
/// out of the loop.
|
||||||
|
boost::optional<Xbyak::Label> loop_break_label;
|
||||||
|
|
||||||
/// Offsets in code where a return needs to be inserted
|
/// Offsets in code where a return needs to be inserted
|
||||||
std::vector<unsigned> return_offsets;
|
std::vector<unsigned> return_offsets;
|
||||||
|
|
||||||
|
|
Reference in New Issue