Compare commits
44 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
534abf9d97 | ||
|
|
424e90f0f5 | ||
|
|
e12a07079e | ||
|
|
fcc5ffdfdd | ||
|
|
4cafc24a4e | ||
|
|
68c44ca0ee | ||
|
|
e858a72a22 | ||
|
|
4db8acd30a | ||
|
|
b8c1dca62f | ||
|
|
0eb39922f6 | ||
|
|
0af7e93763 | ||
|
|
6ff7906ddc | ||
|
|
ce722e317b | ||
|
|
6f6bba3ff1 | ||
|
|
d7298ec262 | ||
|
|
66f4f86a82 | ||
|
|
63a70c253e | ||
|
|
9e74d6238e | ||
|
|
5926fbd3d7 | ||
|
|
eb2633f3ef | ||
|
|
639ebb39f6 | ||
|
|
cb3c50eacc | ||
|
|
094f6003e0 | ||
|
|
98b940052c | ||
|
|
e5ee0afe6f | ||
|
|
a70ad9b5bb | ||
|
|
3f81c38c6d | ||
|
|
c68aa65226 | ||
|
|
ecfbe7d9c8 | ||
|
|
a1fb8a331f | ||
|
|
a921d22545 | ||
|
|
ee07041b3a | ||
|
|
9c977d2215 | ||
|
|
f2c7b5dcd6 | ||
|
|
d37da52cb3 | ||
|
|
969326bd58 | ||
|
|
224071a652 | ||
|
|
249341d08f | ||
|
|
261a4f0311 | ||
|
|
ca4bf671ce | ||
|
|
28e90fa0e0 | ||
|
|
0a93b45b6a | ||
|
|
3d486fffed | ||
|
|
436acbb630 |
@@ -1,5 +1,5 @@
|
||||
# CMake 3.6 required for FindBoost to define IMPORTED libs properly on unknown Boost versions
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
include(DownloadExternals)
|
||||
@@ -187,8 +187,8 @@ find_package(Threads REQUIRED)
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if (MSVC14 AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.5")
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.8")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
@@ -220,7 +220,7 @@ if (YUZU_USE_BUNDLED_UNICORN)
|
||||
if (MSVC)
|
||||
message(STATUS "unicorn not found, falling back to bundled")
|
||||
# Detect toolchain and platform
|
||||
if (MSVC14 AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
set(UNICORN_VER "unicorn-yuzu")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
|
||||
@@ -279,7 +279,7 @@ endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
if (MSVC14 AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.10.0-msvc2015_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
@@ -303,7 +303,7 @@ endif()
|
||||
# ======================================
|
||||
|
||||
IF (APPLE)
|
||||
FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
|
||||
find_library(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
|
||||
@@ -26,6 +26,18 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params,
|
||||
QueueMixedBuffer(2);
|
||||
}
|
||||
|
||||
u32 AudioRenderer::GetSampleRate() const {
|
||||
return worker_params.sample_rate;
|
||||
}
|
||||
|
||||
u32 AudioRenderer::GetSampleCount() const {
|
||||
return worker_params.sample_count;
|
||||
}
|
||||
|
||||
u32 AudioRenderer::GetMixBufferCount() const {
|
||||
return worker_params.mix_buffer_count;
|
||||
}
|
||||
|
||||
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
|
||||
// Copy UpdateDataHeader struct
|
||||
UpdateDataHeader config{};
|
||||
|
||||
@@ -26,7 +26,7 @@ enum class PlayState : u8 {
|
||||
struct AudioRendererParameter {
|
||||
u32_le sample_rate;
|
||||
u32_le sample_count;
|
||||
u32_le unknown_8;
|
||||
u32_le mix_buffer_count;
|
||||
u32_le unknown_c;
|
||||
u32_le voice_count;
|
||||
u32_le sink_count;
|
||||
@@ -160,6 +160,9 @@ public:
|
||||
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
|
||||
void QueueMixedBuffer(Buffer::Tag tag);
|
||||
void ReleaseAndQueueBuffers();
|
||||
u32 GetSampleRate() const;
|
||||
u32 GetSampleCount() const;
|
||||
u32 GetMixBufferCount() const;
|
||||
|
||||
private:
|
||||
class VoiceState {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#include "audio_core/cubeb_sink.h"
|
||||
#include "audio_core/stream.h"
|
||||
@@ -66,6 +67,8 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock{queue_mutex};
|
||||
|
||||
queue.reserve(queue.size() + samples.size() * GetNumChannels());
|
||||
|
||||
if (is_6_channel) {
|
||||
@@ -94,6 +97,7 @@ private:
|
||||
u32 num_channels{};
|
||||
bool is_6_channel{};
|
||||
|
||||
std::mutex queue_mutex;
|
||||
std::vector<s16> queue;
|
||||
|
||||
static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||
@@ -153,6 +157,8 @@ long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const v
|
||||
return {};
|
||||
}
|
||||
|
||||
std::lock_guard lock{impl->queue_mutex};
|
||||
|
||||
const size_t frames_to_write{
|
||||
std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))};
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ System::ResultStatus System::SingleStep() {
|
||||
return RunLoop(false);
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||
app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read));
|
||||
|
||||
if (!app_loader) {
|
||||
@@ -151,7 +151,7 @@ Cpu& System::CpuCore(size_t core_index) {
|
||||
return *cpu_cores[core_index];
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(EmuWindow& emu_window) {
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
CoreTiming::Init();
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/gpu.h"
|
||||
|
||||
class EmuWindow;
|
||||
class ARM_Interface;
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
@@ -99,7 +102,7 @@ public:
|
||||
* @param filepath String path to the executable application to load on the host file system.
|
||||
* @returns ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
ResultStatus Load(EmuWindow& emu_window, const std::string& filepath);
|
||||
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
|
||||
|
||||
/**
|
||||
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
||||
@@ -227,7 +230,7 @@ private:
|
||||
* input.
|
||||
* @return ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
ResultStatus Init(EmuWindow& emu_window);
|
||||
ResultStatus Init(Frontend::EmuWindow& emu_window);
|
||||
|
||||
/// RealVfsFilesystem instance
|
||||
FileSys::VirtualFilesystem virtual_filesystem;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace Loader {
|
||||
enum class ResultStatus;
|
||||
enum class ResultStatus : u16;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "partition_filesystem.h"
|
||||
|
||||
namespace Loader {
|
||||
enum class ResultStatus;
|
||||
enum class ResultStatus : u16;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
|
||||
public std::enable_shared_from_this<TouchState> {
|
||||
public:
|
||||
@@ -108,3 +110,5 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
|
||||
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "common/common_types.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
/**
|
||||
* Abstraction class used to provide an interface between emulation code and the frontend
|
||||
* (e.g. SDL, QGLWidget, GLFW, etc...).
|
||||
@@ -166,3 +168,5 @@ private:
|
||||
*/
|
||||
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -71,6 +71,14 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
|
||||
const u32 object_id{context.GetDomainMessageHeader()->object_id};
|
||||
switch (domain_message_header->command) {
|
||||
case IPC::DomainMessageHeader::CommandType::SendMessage:
|
||||
if (object_id > domain_request_handlers.size()) {
|
||||
LOG_CRITICAL(IPC,
|
||||
"object_id {} is too big! This probably means a recent service call "
|
||||
"to {} needed to return a new interface!",
|
||||
object_id, name);
|
||||
UNREACHABLE();
|
||||
return RESULT_SUCCESS; // Ignore error if asserts are off
|
||||
}
|
||||
return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
|
||||
|
||||
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
|
||||
|
||||
@@ -20,9 +20,9 @@ public:
|
||||
explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params)
|
||||
: ServiceFramework("IAudioRenderer") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetAudioRendererSampleRate"},
|
||||
{1, nullptr, "GetAudioRendererSampleCount"},
|
||||
{2, nullptr, "GetAudioRendererMixBufferCount"},
|
||||
{0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
|
||||
{1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
|
||||
{2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
|
||||
{3, nullptr, "GetAudioRendererState"},
|
||||
{4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
|
||||
{5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
|
||||
@@ -45,6 +45,27 @@ private:
|
||||
system_event->Signal();
|
||||
}
|
||||
|
||||
void GetAudioRendererSampleRate(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleRate());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetAudioRendererSampleCount(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetSampleCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(renderer->GetMixBufferCount());
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -169,7 +190,8 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||
{1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
|
||||
{2, &AudRenU::GetAudioDevice, "GetAudioDevice"},
|
||||
{3, nullptr, "OpenAudioRendererAuto"},
|
||||
{4, nullptr, "GetAudioDeviceServiceWithRevisionInfo"},
|
||||
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo,
|
||||
"GetAudioDeviceServiceWithRevisionInfo"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -189,7 +211,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
|
||||
|
||||
u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
|
||||
u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
|
||||
buffer_sz += params.unknown_c * 1024;
|
||||
buffer_sz += 0x940 * (params.unknown_c + 1);
|
||||
buffer_sz += 0x3F0 * params.voice_count;
|
||||
@@ -197,7 +219,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10);
|
||||
buffer_sz +=
|
||||
Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
|
||||
(params.unknown_8 + 6),
|
||||
(params.mix_buffer_count + 6),
|
||||
0x40);
|
||||
|
||||
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
|
||||
@@ -253,6 +275,16 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
}
|
||||
|
||||
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<Audio::IAudioDevice>();
|
||||
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
|
||||
// based on the current revision
|
||||
}
|
||||
|
||||
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
|
||||
u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
|
||||
switch (feature) {
|
||||
|
||||
@@ -22,6 +22,7 @@ private:
|
||||
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioDevice(Kernel::HLERequestContext& ctx);
|
||||
void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
enum class AudioFeatures : u32 {
|
||||
Splitter,
|
||||
|
||||
@@ -9,10 +9,110 @@
|
||||
|
||||
namespace Service::Friend {
|
||||
|
||||
class IFriendService final : public ServiceFramework<IFriendService> {
|
||||
public:
|
||||
IFriendService() : ServiceFramework("IFriendService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetCompletionEvent"},
|
||||
{1, nullptr, "Cancel"},
|
||||
{10100, nullptr, "GetFriendListIds"},
|
||||
{10101, nullptr, "GetFriendList"},
|
||||
{10102, nullptr, "UpdateFriendInfo"},
|
||||
{10110, nullptr, "GetFriendProfileImage"},
|
||||
{10200, nullptr, "SendFriendRequestForApplication"},
|
||||
{10211, nullptr, "AddFacedFriendRequestForApplication"},
|
||||
{10400, nullptr, "GetBlockedUserListIds"},
|
||||
{10500, nullptr, "GetProfileList"},
|
||||
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
||||
{10601, &IFriendService::DeclareCloseOnlinePlaySession,
|
||||
"DeclareCloseOnlinePlaySession"},
|
||||
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
|
||||
{10700, nullptr, "GetPlayHistoryRegistrationKey"},
|
||||
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
|
||||
{10702, nullptr, "AddPlayHistory"},
|
||||
{11000, nullptr, "GetProfileImageUrl"},
|
||||
{20100, nullptr, "GetFriendCount"},
|
||||
{20101, nullptr, "GetNewlyFriendCount"},
|
||||
{20102, nullptr, "GetFriendDetailedInfo"},
|
||||
{20103, nullptr, "SyncFriendList"},
|
||||
{20104, nullptr, "RequestSyncFriendList"},
|
||||
{20110, nullptr, "LoadFriendSetting"},
|
||||
{20200, nullptr, "GetReceivedFriendRequestCount"},
|
||||
{20201, nullptr, "GetFriendRequestList"},
|
||||
{20300, nullptr, "GetFriendCandidateList"},
|
||||
{20301, nullptr, "GetNintendoNetworkIdInfo"},
|
||||
{20302, nullptr, "GetSnsAccountLinkage"},
|
||||
{20303, nullptr, "GetSnsAccountProfile"},
|
||||
{20304, nullptr, "GetSnsAccountFriendList"},
|
||||
{20400, nullptr, "GetBlockedUserList"},
|
||||
{20401, nullptr, "SyncBlockedUserList"},
|
||||
{20500, nullptr, "GetProfileExtraList"},
|
||||
{20501, nullptr, "GetRelationship"},
|
||||
{20600, nullptr, "GetUserPresenceView"},
|
||||
{20700, nullptr, "GetPlayHistoryList"},
|
||||
{20701, nullptr, "GetPlayHistoryStatistics"},
|
||||
{20800, nullptr, "LoadUserSetting"},
|
||||
{20801, nullptr, "SyncUserSetting"},
|
||||
{20900, nullptr, "RequestListSummaryOverlayNotification"},
|
||||
{21000, nullptr, "GetExternalApplicationCatalog"},
|
||||
{30100, nullptr, "DropFriendNewlyFlags"},
|
||||
{30101, nullptr, "DeleteFriend"},
|
||||
{30110, nullptr, "DropFriendNewlyFlag"},
|
||||
{30120, nullptr, "ChangeFriendFavoriteFlag"},
|
||||
{30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
|
||||
{30200, nullptr, "SendFriendRequest"},
|
||||
{30201, nullptr, "SendFriendRequestWithApplicationInfo"},
|
||||
{30202, nullptr, "CancelFriendRequest"},
|
||||
{30203, nullptr, "AcceptFriendRequest"},
|
||||
{30204, nullptr, "RejectFriendRequest"},
|
||||
{30205, nullptr, "ReadFriendRequest"},
|
||||
{30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
|
||||
{30211, nullptr, "AddFacedFriendRequest"},
|
||||
{30212, nullptr, "CancelFacedFriendRequest"},
|
||||
{30213, nullptr, "GetFacedFriendRequestProfileImage"},
|
||||
{30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
|
||||
{30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
|
||||
{30216, nullptr, "ResendFacedFriendRequest"},
|
||||
{30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
|
||||
{30300, nullptr, "GetSnsAccountLinkPageUrl"},
|
||||
{30301, nullptr, "UnlinkSnsAccount"},
|
||||
{30400, nullptr, "BlockUser"},
|
||||
{30401, nullptr, "BlockUserWithApplicationInfo"},
|
||||
{30402, nullptr, "UnblockUser"},
|
||||
{30500, nullptr, "GetProfileExtraFromFriendCode"},
|
||||
{30700, nullptr, "DeletePlayHistory"},
|
||||
{30810, nullptr, "ChangePresencePermission"},
|
||||
{30811, nullptr, "ChangeFriendRequestReception"},
|
||||
{30812, nullptr, "ChangePlayLogPermission"},
|
||||
{30820, nullptr, "IssueFriendCode"},
|
||||
{30830, nullptr, "ClearPlayLog"},
|
||||
{49900, nullptr, "DeleteNetworkServiceAccountCache"},
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
|
||||
// Stub used by Splatoon 2
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
|
||||
// Stub used by Retro City Rampage
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
};
|
||||
|
||||
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called");
|
||||
rb.PushIpcInterface<IFriendService>();
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
|
||||
@@ -291,6 +291,7 @@ private:
|
||||
class Hid final : public ServiceFramework<Hid> {
|
||||
public:
|
||||
Hid() : ServiceFramework("hid") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
|
||||
{1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
|
||||
@@ -333,15 +334,13 @@ public:
|
||||
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
|
||||
{103, &Hid::ActivateNpad, "ActivateNpad"},
|
||||
{104, nullptr, "DeactivateNpad"},
|
||||
{106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
|
||||
"AcquireNpadStyleSetUpdateEventHandle"},
|
||||
{107, nullptr, "DisconnectNpad"},
|
||||
{106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
|
||||
{107, &Hid::DisconnectNpad, "DisconnectNpad"},
|
||||
{108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
|
||||
{109, nullptr, "ActivateNpadWithRevision"},
|
||||
{120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
|
||||
{121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
|
||||
{122, &Hid::SetNpadJoyAssignmentModeSingleByDefault,
|
||||
"SetNpadJoyAssignmentModeSingleByDefault"},
|
||||
{122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
|
||||
{123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
|
||||
{124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
|
||||
{125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
|
||||
@@ -398,6 +397,8 @@ public:
|
||||
{1000, nullptr, "SetNpadCommunicationMode"},
|
||||
{1001, nullptr, "GetNpadCommunicationMode"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
|
||||
@@ -496,6 +497,12 @@ private:
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void DisconnectNpad(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -126,7 +126,7 @@ constexpr std::array<const char*, 36> RESULT_MESSAGES{
|
||||
};
|
||||
|
||||
std::string GetMessageForResultStatus(ResultStatus status) {
|
||||
return GetMessageForResultStatus(static_cast<size_t>(status));
|
||||
return GetMessageForResultStatus(static_cast<u16>(status));
|
||||
}
|
||||
|
||||
std::string GetMessageForResultStatus(u16 status) {
|
||||
|
||||
@@ -56,7 +56,7 @@ FileType GuessFromFilename(const std::string& name);
|
||||
std::string GetFileTypeString(FileType type);
|
||||
|
||||
/// Return type for functions in Loader namespace
|
||||
enum class ResultStatus {
|
||||
enum class ResultStatus : u16 {
|
||||
Success,
|
||||
ErrorAlreadyLoaded,
|
||||
ErrorNotImplemented,
|
||||
|
||||
@@ -357,6 +357,27 @@ public:
|
||||
OneMinusConstantColor = 0x62,
|
||||
ConstantAlpha = 0x63,
|
||||
OneMinusConstantAlpha = 0x64,
|
||||
|
||||
// These values are used by Nouveau and some games.
|
||||
ZeroGL = 0x4000,
|
||||
OneGL = 0x4001,
|
||||
SourceColorGL = 0x4300,
|
||||
OneMinusSourceColorGL = 0x4301,
|
||||
SourceAlphaGL = 0x4302,
|
||||
OneMinusSourceAlphaGL = 0x4303,
|
||||
DestAlphaGL = 0x4304,
|
||||
OneMinusDestAlphaGL = 0x4305,
|
||||
DestColorGL = 0x4306,
|
||||
OneMinusDestColorGL = 0x4307,
|
||||
SourceAlphaSaturateGL = 0x4308,
|
||||
ConstantColorGL = 0xc001,
|
||||
OneMinusConstantColorGL = 0xc002,
|
||||
ConstantAlphaGL = 0xc003,
|
||||
OneMinusConstantAlphaGL = 0xc004,
|
||||
Source1ColorGL = 0xc900,
|
||||
OneMinusSource1ColorGL = 0xc901,
|
||||
Source1AlphaGL = 0xc902,
|
||||
OneMinusSource1AlphaGL = 0xc903,
|
||||
};
|
||||
|
||||
u32 separate_alpha;
|
||||
|
||||
@@ -200,6 +200,14 @@ enum class IMinMaxExchange : u64 {
|
||||
XHi = 3,
|
||||
};
|
||||
|
||||
enum class XmadMode : u64 {
|
||||
None = 0,
|
||||
CLo = 1,
|
||||
CHi = 2,
|
||||
CSfu = 3,
|
||||
CBcc = 4,
|
||||
};
|
||||
|
||||
enum class FlowCondition : u64 {
|
||||
Always = 0xF,
|
||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||
@@ -456,6 +464,18 @@ union Instruction {
|
||||
}
|
||||
} bra;
|
||||
|
||||
union {
|
||||
BitField<20, 16, u64> imm20_16;
|
||||
BitField<36, 1, u64> product_shift_left;
|
||||
BitField<37, 1, u64> merge_37;
|
||||
BitField<48, 1, u64> sign_a;
|
||||
BitField<49, 1, u64> sign_b;
|
||||
BitField<50, 3, XmadMode> mode;
|
||||
BitField<52, 1, u64> high_b;
|
||||
BitField<53, 1, u64> high_a;
|
||||
BitField<56, 1, u64> merge_56;
|
||||
} xmad;
|
||||
|
||||
union {
|
||||
BitField<20, 14, u64> offset;
|
||||
BitField<34, 5, u64> index;
|
||||
@@ -593,6 +613,7 @@ public:
|
||||
IntegerSetPredicate,
|
||||
PredicateSetPredicate,
|
||||
Conversion,
|
||||
Xmad,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
@@ -782,10 +803,10 @@ private:
|
||||
INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"),
|
||||
INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"),
|
||||
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
|
||||
INST("0011011-00------", Id::XMAD_IMM, Type::Arithmetic, "XMAD_IMM"),
|
||||
INST("0100111---------", Id::XMAD_CR, Type::Arithmetic, "XMAD_CR"),
|
||||
INST("010100010-------", Id::XMAD_RC, Type::Arithmetic, "XMAD_RC"),
|
||||
INST("0101101100------", Id::XMAD_RR, Type::Arithmetic, "XMAD_RR"),
|
||||
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
|
||||
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
|
||||
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
|
||||
INST("0101101100------", Id::XMAD_RR, Type::Xmad, "XMAD_RR"),
|
||||
};
|
||||
#undef INST
|
||||
std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
|
||||
|
||||
@@ -70,6 +70,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
|
||||
case RenderTargetFormat::RG8_SNORM:
|
||||
return 2;
|
||||
case RenderTargetFormat::R8_UNORM:
|
||||
case RenderTargetFormat::R8_UINT:
|
||||
return 1;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format));
|
||||
|
||||
@@ -42,6 +42,7 @@ enum class RenderTargetFormat : u32 {
|
||||
R16_UINT = 0xF1,
|
||||
R16_FLOAT = 0xF2,
|
||||
R8_UNORM = 0xF3,
|
||||
R8_UINT = 0xF6,
|
||||
};
|
||||
|
||||
enum class DepthFormat : u32 {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
RendererBase::RendererBase(EmuWindow& window) : render_window{window} {
|
||||
RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
|
||||
RefreshBaseSettings();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
@@ -21,7 +23,7 @@ struct RendererSettings {
|
||||
|
||||
class RendererBase : NonCopyable {
|
||||
public:
|
||||
explicit RendererBase(EmuWindow& window);
|
||||
explicit RendererBase(Core::Frontend::EmuWindow& window);
|
||||
virtual ~RendererBase();
|
||||
|
||||
/// Swap buffers (render frame)
|
||||
@@ -59,7 +61,7 @@ protected:
|
||||
/// Refreshes settings specific to the rasterizer.
|
||||
void RefreshRasterizerSetting();
|
||||
|
||||
EmuWindow& render_window; ///< Reference to the render window handle.
|
||||
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
|
||||
std::unique_ptr<RasterizerInterface> rasterizer;
|
||||
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
|
||||
int m_current_frame = 0; ///< Current frame, should be set by the renderer
|
||||
|
||||
@@ -36,30 +36,21 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
|
||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
|
||||
|
||||
RasterizerOpenGL::RasterizerOpenGL(EmuWindow& window) : emu_window{window} {
|
||||
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window)
|
||||
: emu_window{window}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) {
|
||||
// Create sampler objects
|
||||
for (size_t i = 0; i < texture_samplers.size(); ++i) {
|
||||
texture_samplers[i].Create();
|
||||
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
|
||||
}
|
||||
|
||||
// Create SSBOs
|
||||
for (size_t stage = 0; stage < ssbos.size(); ++stage) {
|
||||
for (size_t buffer = 0; buffer < ssbos[stage].size(); ++buffer) {
|
||||
ssbos[stage][buffer].Create();
|
||||
state.draw.const_buffers[stage][buffer].ssbo = ssbos[stage][buffer].handle;
|
||||
}
|
||||
}
|
||||
|
||||
GLint ext_num;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
|
||||
for (GLint i = 0; i < ext_num; i++) {
|
||||
const std::string_view extension{
|
||||
reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
|
||||
|
||||
if (extension == "GL_ARB_buffer_storage") {
|
||||
has_ARB_buffer_storage = true;
|
||||
} else if (extension == "GL_ARB_direct_state_access") {
|
||||
if (extension == "GL_ARB_direct_state_access") {
|
||||
has_ARB_direct_state_access = true;
|
||||
} else if (extension == "GL_ARB_separate_shader_objects") {
|
||||
has_ARB_separate_shader_objects = true;
|
||||
@@ -86,47 +77,31 @@ RasterizerOpenGL::RasterizerOpenGL(EmuWindow& window) : emu_window{window} {
|
||||
|
||||
hw_vao.Create();
|
||||
|
||||
stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER);
|
||||
stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2);
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
state.draw.vertex_buffer = stream_buffer.GetHandle();
|
||||
|
||||
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
|
||||
state.draw.shader_program = 0;
|
||||
state.draw.vertex_array = hw_vao.handle;
|
||||
state.Apply();
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle());
|
||||
|
||||
for (unsigned index = 0; index < uniform_buffers.size(); ++index) {
|
||||
auto& buffer = uniform_buffers[index];
|
||||
buffer.Create();
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, buffer.handle);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(GLShader::MaxwellUniformData), nullptr,
|
||||
GL_STREAM_COPY);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer.handle);
|
||||
}
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer.GetHandle());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
||||
|
||||
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
|
||||
}
|
||||
|
||||
RasterizerOpenGL::~RasterizerOpenGL() {
|
||||
if (stream_buffer != nullptr) {
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
state.Apply();
|
||||
stream_buffer->Release();
|
||||
}
|
||||
}
|
||||
RasterizerOpenGL::~RasterizerOpenGL() {}
|
||||
|
||||
std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
|
||||
GLintptr buffer_offset) {
|
||||
MICROPROFILE_SCOPE(OpenGL_VAO);
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
|
||||
|
||||
state.draw.vertex_array = hw_vao.handle;
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
state.draw.vertex_buffer = stream_buffer.GetHandle();
|
||||
state.Apply();
|
||||
|
||||
// Upload all guest vertex arrays sequentially to our buffer
|
||||
@@ -141,16 +116,15 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
|
||||
ASSERT(end > start);
|
||||
u64 size = end - start + 1;
|
||||
|
||||
// Copy vertex array data
|
||||
Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size);
|
||||
GLintptr vertex_buffer_offset;
|
||||
std::tie(array_ptr, buffer_offset, vertex_buffer_offset) =
|
||||
UploadMemory(array_ptr, buffer_offset, start, size);
|
||||
|
||||
// Bind the vertex array to the buffer at the current offset.
|
||||
glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride);
|
||||
glBindVertexBuffer(index, stream_buffer.GetHandle(), vertex_buffer_offset,
|
||||
vertex_array.stride);
|
||||
|
||||
ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented");
|
||||
|
||||
array_ptr += size;
|
||||
buffer_offset += size;
|
||||
}
|
||||
|
||||
// Use the vertex array as-is, assumes that the data is formatted correctly for OpenGL.
|
||||
@@ -201,22 +175,12 @@ static GLShader::ProgramCode GetShaderProgramCode(Maxwell::ShaderProgram program
|
||||
return program_code;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
|
||||
// Helper function for uploading uniform data
|
||||
const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
|
||||
if (has_ARB_direct_state_access) {
|
||||
glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size);
|
||||
} else {
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, handle);
|
||||
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size);
|
||||
}
|
||||
};
|
||||
|
||||
std::pair<u8*, GLintptr> RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
|
||||
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
||||
|
||||
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
|
||||
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
|
||||
u32 current_constbuffer_bindpoint = uniform_buffers.size();
|
||||
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
|
||||
u32 current_texture_bindpoint = 0;
|
||||
|
||||
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
||||
@@ -228,22 +192,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::tie(buffer_ptr, buffer_offset) =
|
||||
AlignBuffer(buffer_ptr, buffer_offset, static_cast<size_t>(uniform_buffer_alignment));
|
||||
|
||||
const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
|
||||
|
||||
GLShader::MaxwellUniformData ubo{};
|
||||
ubo.SetFromRegs(gpu.state.shader_stages[stage]);
|
||||
std::memcpy(buffer_ptr, &ubo, sizeof(ubo));
|
||||
|
||||
// Flush the buffer so that the GPU can see the data we just wrote.
|
||||
glFlushMappedBufferRange(GL_ARRAY_BUFFER, buffer_offset, sizeof(ubo));
|
||||
// Bind the buffer
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, stage, stream_buffer.GetHandle(), buffer_offset,
|
||||
sizeof(ubo));
|
||||
|
||||
// Upload uniform data as one UBO per stage
|
||||
const GLintptr ubo_offset = buffer_offset;
|
||||
copy_buffer(uniform_buffers[stage].handle, ubo_offset,
|
||||
sizeof(GLShader::MaxwellUniformData));
|
||||
|
||||
buffer_ptr += sizeof(GLShader::MaxwellUniformData);
|
||||
buffer_offset += sizeof(GLShader::MaxwellUniformData);
|
||||
buffer_ptr += sizeof(ubo);
|
||||
buffer_offset += sizeof(ubo);
|
||||
|
||||
GLShader::ShaderSetup setup{GetShaderProgramCode(program)};
|
||||
GLShader::ShaderEntries shader_resources;
|
||||
@@ -282,9 +245,9 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
|
||||
static_cast<Maxwell::ShaderStage>(stage));
|
||||
|
||||
// Configure the const buffers for this shader stage.
|
||||
current_constbuffer_bindpoint =
|
||||
SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
|
||||
current_constbuffer_bindpoint, shader_resources.const_buffer_entries);
|
||||
std::tie(buffer_ptr, buffer_offset, current_constbuffer_bindpoint) = SetupConstBuffers(
|
||||
buffer_ptr, buffer_offset, static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
|
||||
current_constbuffer_bindpoint, shader_resources.const_buffer_entries);
|
||||
|
||||
// Configure the textures for this shader stage.
|
||||
current_texture_bindpoint =
|
||||
@@ -299,6 +262,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
|
||||
}
|
||||
|
||||
shader_program_manager->UseTrivialGeometryShader();
|
||||
|
||||
return {buffer_ptr, buffer_offset};
|
||||
}
|
||||
|
||||
size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
|
||||
@@ -432,6 +397,31 @@ void RasterizerOpenGL::Clear() {
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<u8*, GLintptr> RasterizerOpenGL::AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset,
|
||||
size_t alignment) {
|
||||
// Align the offset, not the mapped pointer
|
||||
GLintptr offset_aligned =
|
||||
static_cast<GLintptr>(Common::AlignUp(static_cast<size_t>(buffer_offset), alignment));
|
||||
return {buffer_ptr + (offset_aligned - buffer_offset), offset_aligned};
|
||||
}
|
||||
|
||||
std::tuple<u8*, GLintptr, GLintptr> RasterizerOpenGL::UploadMemory(u8* buffer_ptr,
|
||||
GLintptr buffer_offset,
|
||||
Tegra::GPUVAddr gpu_addr,
|
||||
size_t size, size_t alignment) {
|
||||
std::tie(buffer_ptr, buffer_offset) = AlignBuffer(buffer_ptr, buffer_offset, alignment);
|
||||
GLintptr uploaded_offset = buffer_offset;
|
||||
|
||||
const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
|
||||
const boost::optional<VAddr> cpu_addr{memory_manager->GpuToCpuAddress(gpu_addr)};
|
||||
Memory::ReadBlock(*cpu_addr, buffer_ptr, size);
|
||||
|
||||
buffer_ptr += size;
|
||||
buffer_offset += size;
|
||||
|
||||
return {buffer_ptr, buffer_offset, uploaded_offset};
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::DrawArrays() {
|
||||
if (accelerate_draw == AccelDraw::Disabled)
|
||||
return;
|
||||
@@ -456,7 +446,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
|
||||
const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
|
||||
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
state.draw.vertex_buffer = stream_buffer.GetHandle();
|
||||
state.Apply();
|
||||
|
||||
size_t buffer_size = CalculateVertexArraysSize();
|
||||
@@ -466,41 +456,31 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
}
|
||||
|
||||
// Uniform space for the 5 shader stages
|
||||
buffer_size = Common::AlignUp<size_t>(buffer_size, 4) +
|
||||
sizeof(GLShader::MaxwellUniformData) * Maxwell::MaxShaderStage;
|
||||
buffer_size =
|
||||
Common::AlignUp<size_t>(buffer_size, 4) +
|
||||
(sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage;
|
||||
|
||||
// Add space for at least 18 constant buffers
|
||||
buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment);
|
||||
|
||||
u8* buffer_ptr;
|
||||
GLintptr buffer_offset;
|
||||
std::tie(buffer_ptr, buffer_offset) =
|
||||
stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4);
|
||||
std::tie(buffer_ptr, buffer_offset, std::ignore) =
|
||||
stream_buffer.Map(static_cast<GLsizeiptr>(buffer_size), 4);
|
||||
u8* buffer_ptr_base = buffer_ptr;
|
||||
|
||||
u8* offseted_buffer;
|
||||
std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset);
|
||||
|
||||
offseted_buffer =
|
||||
reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
|
||||
buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
|
||||
std::tie(buffer_ptr, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset);
|
||||
|
||||
// If indexed mode, copy the index buffer
|
||||
GLintptr index_buffer_offset = 0;
|
||||
if (is_indexed) {
|
||||
const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager;
|
||||
const boost::optional<VAddr> index_data_addr{
|
||||
memory_manager->GpuToCpuAddress(regs.index_array.StartAddress())};
|
||||
Memory::ReadBlock(*index_data_addr, offseted_buffer, index_buffer_size);
|
||||
|
||||
index_buffer_offset = buffer_offset;
|
||||
offseted_buffer += index_buffer_size;
|
||||
buffer_offset += index_buffer_size;
|
||||
std::tie(buffer_ptr, buffer_offset, index_buffer_offset) = UploadMemory(
|
||||
buffer_ptr, buffer_offset, regs.index_array.StartAddress(), index_buffer_size);
|
||||
}
|
||||
|
||||
offseted_buffer =
|
||||
reinterpret_cast<u8*>(Common::AlignUp(reinterpret_cast<size_t>(offseted_buffer), 4));
|
||||
buffer_offset = Common::AlignUp<size_t>(buffer_offset, 4);
|
||||
std::tie(buffer_ptr, buffer_offset) = SetupShaders(buffer_ptr, buffer_offset);
|
||||
|
||||
SetupShaders(offseted_buffer, buffer_offset);
|
||||
|
||||
stream_buffer->Unmap();
|
||||
stream_buffer.Unmap(buffer_ptr - buffer_ptr_base);
|
||||
|
||||
shader_program_manager->ApplyTo(state);
|
||||
state.Apply();
|
||||
@@ -647,36 +627,23 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||
}
|
||||
}
|
||||
|
||||
u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,
|
||||
u32 current_bindpoint,
|
||||
const std::vector<GLShader::ConstBufferEntry>& entries) {
|
||||
std::tuple<u8*, GLintptr, u32> RasterizerOpenGL::SetupConstBuffers(
|
||||
u8* buffer_ptr, GLintptr buffer_offset, Maxwell::ShaderStage stage, GLuint program,
|
||||
u32 current_bindpoint, const std::vector<GLShader::ConstBufferEntry>& entries) {
|
||||
const auto& gpu = Core::System::GetInstance().GPU();
|
||||
const auto& maxwell3d = gpu.Maxwell3D();
|
||||
|
||||
// Reset all buffer draw state for this stage.
|
||||
for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
|
||||
buffer.bindpoint = 0;
|
||||
buffer.enabled = false;
|
||||
}
|
||||
|
||||
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
|
||||
const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
|
||||
|
||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||
const auto& used_buffer = entries[bindpoint];
|
||||
const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
|
||||
auto& buffer_draw_state =
|
||||
state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()];
|
||||
|
||||
if (!buffer.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer_draw_state.enabled = true;
|
||||
buffer_draw_state.bindpoint = current_bindpoint + bindpoint;
|
||||
|
||||
boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address);
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if (used_buffer.IsIndirect()) {
|
||||
@@ -698,25 +665,26 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
|
||||
size = Common::AlignUp(size, sizeof(GLvec4));
|
||||
ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
|
||||
|
||||
std::vector<u8> data(size);
|
||||
Memory::ReadBlock(*addr, data.data(), data.size());
|
||||
GLintptr const_buffer_offset;
|
||||
std::tie(buffer_ptr, buffer_offset, const_buffer_offset) =
|
||||
UploadMemory(buffer_ptr, buffer_offset, buffer.address, size,
|
||||
static_cast<size_t>(uniform_buffer_alignment));
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, buffer_draw_state.ssbo);
|
||||
glBufferData(GL_UNIFORM_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, current_bindpoint + bindpoint,
|
||||
stream_buffer.GetHandle(), const_buffer_offset, size);
|
||||
|
||||
// Now configure the bindpoint of the buffer inside the shader
|
||||
const std::string buffer_name = used_buffer.GetName();
|
||||
const GLuint index =
|
||||
glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str());
|
||||
if (index != GL_INVALID_INDEX) {
|
||||
glUniformBlockBinding(program, index, buffer_draw_state.bindpoint);
|
||||
glUniformBlockBinding(program, index, current_bindpoint + bindpoint);
|
||||
}
|
||||
}
|
||||
|
||||
state.Apply();
|
||||
|
||||
return current_bindpoint + static_cast<u32>(entries.size());
|
||||
return {buffer_ptr, buffer_offset, current_bindpoint + static_cast<u32>(entries.size())};
|
||||
}
|
||||
|
||||
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
@@ -21,12 +22,15 @@
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
|
||||
class EmuWindow;
|
||||
struct ScreenInfo;
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
}
|
||||
|
||||
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
|
||||
public:
|
||||
explicit RasterizerOpenGL(EmuWindow& renderer);
|
||||
explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer);
|
||||
~RasterizerOpenGL() override;
|
||||
|
||||
void DrawArrays() override;
|
||||
@@ -97,9 +101,10 @@ private:
|
||||
* @param entries Vector describing the buffers that are actually used in the guest shader.
|
||||
* @returns The next available bindpoint for use in the next shader stage.
|
||||
*/
|
||||
u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, GLuint program,
|
||||
u32 current_bindpoint,
|
||||
const std::vector<GLShader::ConstBufferEntry>& entries);
|
||||
std::tuple<u8*, GLintptr, u32> SetupConstBuffers(
|
||||
u8* buffer_ptr, GLintptr buffer_offset, Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
||||
GLuint program, u32 current_bindpoint,
|
||||
const std::vector<GLShader::ConstBufferEntry>& entries);
|
||||
|
||||
/*
|
||||
* Configures the current textures to use for the draw command.
|
||||
@@ -136,7 +141,6 @@ private:
|
||||
/// Syncs the blend state to match the guest state
|
||||
void SyncBlendState();
|
||||
|
||||
bool has_ARB_buffer_storage = false;
|
||||
bool has_ARB_direct_state_access = false;
|
||||
bool has_ARB_separate_shader_objects = false;
|
||||
bool has_ARB_vertex_attrib_binding = false;
|
||||
@@ -145,29 +149,31 @@ private:
|
||||
|
||||
RasterizerCacheOpenGL res_cache;
|
||||
|
||||
EmuWindow& emu_window;
|
||||
Core::Frontend::EmuWindow& emu_window;
|
||||
|
||||
std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
|
||||
OGLVertexArray sw_vao;
|
||||
OGLVertexArray hw_vao;
|
||||
|
||||
std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
|
||||
std::array<std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers>,
|
||||
Tegra::Engines::Maxwell3D::Regs::MaxShaderStage>
|
||||
ssbos;
|
||||
|
||||
static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
|
||||
std::unique_ptr<OGLStreamBuffer> stream_buffer;
|
||||
OGLStreamBuffer stream_buffer;
|
||||
OGLBuffer uniform_buffer;
|
||||
OGLFramebuffer framebuffer;
|
||||
GLint uniform_buffer_alignment;
|
||||
|
||||
size_t CalculateVertexArraysSize() const;
|
||||
|
||||
std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset);
|
||||
|
||||
std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
|
||||
std::pair<u8*, GLintptr> SetupShaders(u8* buffer_ptr, GLintptr buffer_offset);
|
||||
|
||||
void SetupShaders(u8* buffer_ptr, GLintptr buffer_offset);
|
||||
std::pair<u8*, GLintptr> AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset, size_t alignment);
|
||||
|
||||
std::tuple<u8*, GLintptr, GLintptr> UploadMemory(u8* buffer_ptr, GLintptr buffer_offset,
|
||||
Tegra::GPUVAddr gpu_addr, size_t size,
|
||||
size_t alignment = 4);
|
||||
|
||||
enum class AccelDraw { Disabled, Arrays, Indexed };
|
||||
AccelDraw accelerate_draw = AccelDraw::Disabled;
|
||||
|
||||
@@ -99,6 +99,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
|
||||
false}, // A2B10G10R10
|
||||
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8
|
||||
{GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
|
||||
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
|
||||
{GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
|
||||
false}, // R11FG11FB10F
|
||||
@@ -233,26 +234,27 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
|
||||
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
|
||||
SurfaceParams::MaxPixelFormat>
|
||||
morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::ABGR8U>, MortonCopy<true, PixelFormat::ABGR8S>,
|
||||
MortonCopy<true, PixelFormat::B5G6R5>, MortonCopy<true, PixelFormat::A2B10G10R10>,
|
||||
MortonCopy<true, PixelFormat::A1B5G5R5>, MortonCopy<true, PixelFormat::R8>,
|
||||
MortonCopy<true, PixelFormat::RGBA16F>, MortonCopy<true, PixelFormat::R11FG11FB10F>,
|
||||
MortonCopy<true, PixelFormat::RGBA32UI>, MortonCopy<true, PixelFormat::DXT1>,
|
||||
MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>,
|
||||
MortonCopy<true, PixelFormat::DXN1>, MortonCopy<true, PixelFormat::DXN2UNORM>,
|
||||
MortonCopy<true, PixelFormat::DXN2SNORM>, MortonCopy<true, PixelFormat::BC7U>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_4X4>, MortonCopy<true, PixelFormat::G8R8>,
|
||||
MortonCopy<true, PixelFormat::BGRA8>, MortonCopy<true, PixelFormat::RGBA32F>,
|
||||
MortonCopy<true, PixelFormat::RG32F>, MortonCopy<true, PixelFormat::R32F>,
|
||||
MortonCopy<true, PixelFormat::R16F>, MortonCopy<true, PixelFormat::R16UNORM>,
|
||||
MortonCopy<true, PixelFormat::R16S>, MortonCopy<true, PixelFormat::R16UI>,
|
||||
MortonCopy<true, PixelFormat::R16I>, MortonCopy<true, PixelFormat::RG16>,
|
||||
MortonCopy<true, PixelFormat::RG16F>, MortonCopy<true, PixelFormat::RG16UI>,
|
||||
MortonCopy<true, PixelFormat::RG16I>, MortonCopy<true, PixelFormat::RG16S>,
|
||||
MortonCopy<true, PixelFormat::RGB32F>, MortonCopy<true, PixelFormat::SRGBA8>,
|
||||
MortonCopy<true, PixelFormat::RG8S>, MortonCopy<true, PixelFormat::Z24S8>,
|
||||
MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>,
|
||||
MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z32FS8>,
|
||||
MortonCopy<true, PixelFormat::ABGR8U>, MortonCopy<true, PixelFormat::ABGR8S>,
|
||||
MortonCopy<true, PixelFormat::B5G6R5>, MortonCopy<true, PixelFormat::A2B10G10R10>,
|
||||
MortonCopy<true, PixelFormat::A1B5G5R5>, MortonCopy<true, PixelFormat::R8>,
|
||||
MortonCopy<true, PixelFormat::R8UI>, MortonCopy<true, PixelFormat::RGBA16F>,
|
||||
MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>,
|
||||
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
|
||||
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
|
||||
MortonCopy<true, PixelFormat::DXN2UNORM>, MortonCopy<true, PixelFormat::DXN2SNORM>,
|
||||
MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
|
||||
MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>,
|
||||
MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>,
|
||||
MortonCopy<true, PixelFormat::R32F>, MortonCopy<true, PixelFormat::R16F>,
|
||||
MortonCopy<true, PixelFormat::R16UNORM>, MortonCopy<true, PixelFormat::R16S>,
|
||||
MortonCopy<true, PixelFormat::R16UI>, MortonCopy<true, PixelFormat::R16I>,
|
||||
MortonCopy<true, PixelFormat::RG16>, MortonCopy<true, PixelFormat::RG16F>,
|
||||
MortonCopy<true, PixelFormat::RG16UI>, MortonCopy<true, PixelFormat::RG16I>,
|
||||
MortonCopy<true, PixelFormat::RG16S>, MortonCopy<true, PixelFormat::RGB32F>,
|
||||
MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::RG8S>,
|
||||
MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>,
|
||||
MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>,
|
||||
MortonCopy<true, PixelFormat::Z32FS8>,
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
|
||||
@@ -264,6 +266,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
|
||||
MortonCopy<false, PixelFormat::A2B10G10R10>,
|
||||
MortonCopy<false, PixelFormat::A1B5G5R5>,
|
||||
MortonCopy<false, PixelFormat::R8>,
|
||||
MortonCopy<false, PixelFormat::R8UI>,
|
||||
MortonCopy<false, PixelFormat::RGBA16F>,
|
||||
MortonCopy<false, PixelFormat::R11FG11FB10F>,
|
||||
MortonCopy<false, PixelFormat::RGBA32UI>,
|
||||
|
||||
@@ -29,44 +29,45 @@ struct SurfaceParams {
|
||||
A2B10G10R10 = 3,
|
||||
A1B5G5R5 = 4,
|
||||
R8 = 5,
|
||||
RGBA16F = 6,
|
||||
R11FG11FB10F = 7,
|
||||
RGBA32UI = 8,
|
||||
DXT1 = 9,
|
||||
DXT23 = 10,
|
||||
DXT45 = 11,
|
||||
DXN1 = 12, // This is also known as BC4
|
||||
DXN2UNORM = 13,
|
||||
DXN2SNORM = 14,
|
||||
BC7U = 15,
|
||||
ASTC_2D_4X4 = 16,
|
||||
G8R8 = 17,
|
||||
BGRA8 = 18,
|
||||
RGBA32F = 19,
|
||||
RG32F = 20,
|
||||
R32F = 21,
|
||||
R16F = 22,
|
||||
R16UNORM = 23,
|
||||
R16S = 24,
|
||||
R16UI = 25,
|
||||
R16I = 26,
|
||||
RG16 = 27,
|
||||
RG16F = 28,
|
||||
RG16UI = 29,
|
||||
RG16I = 30,
|
||||
RG16S = 31,
|
||||
RGB32F = 32,
|
||||
SRGBA8 = 33,
|
||||
RG8S = 34,
|
||||
R8UI = 6,
|
||||
RGBA16F = 7,
|
||||
R11FG11FB10F = 8,
|
||||
RGBA32UI = 9,
|
||||
DXT1 = 10,
|
||||
DXT23 = 11,
|
||||
DXT45 = 12,
|
||||
DXN1 = 13, // This is also known as BC4
|
||||
DXN2UNORM = 14,
|
||||
DXN2SNORM = 15,
|
||||
BC7U = 16,
|
||||
ASTC_2D_4X4 = 17,
|
||||
G8R8 = 18,
|
||||
BGRA8 = 19,
|
||||
RGBA32F = 20,
|
||||
RG32F = 21,
|
||||
R32F = 22,
|
||||
R16F = 23,
|
||||
R16UNORM = 24,
|
||||
R16S = 25,
|
||||
R16UI = 26,
|
||||
R16I = 27,
|
||||
RG16 = 28,
|
||||
RG16F = 29,
|
||||
RG16UI = 30,
|
||||
RG16I = 31,
|
||||
RG16S = 32,
|
||||
RGB32F = 33,
|
||||
SRGBA8 = 34,
|
||||
RG8S = 35,
|
||||
|
||||
MaxColorFormat,
|
||||
|
||||
// DepthStencil formats
|
||||
Z24S8 = 35,
|
||||
S8Z24 = 36,
|
||||
Z32F = 37,
|
||||
Z16 = 38,
|
||||
Z32FS8 = 39,
|
||||
Z24S8 = 36,
|
||||
S8Z24 = 37,
|
||||
Z32F = 38,
|
||||
Z16 = 39,
|
||||
Z32FS8 = 40,
|
||||
|
||||
MaxDepthStencilFormat,
|
||||
|
||||
@@ -110,6 +111,7 @@ struct SurfaceParams {
|
||||
1, // A2B10G10R10
|
||||
1, // A1B5G5R5
|
||||
1, // R8
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
@@ -161,6 +163,7 @@ struct SurfaceParams {
|
||||
32, // A2B10G10R10
|
||||
16, // A1B5G5R5
|
||||
8, // R8
|
||||
8, // R8UI
|
||||
64, // RGBA16F
|
||||
32, // R11FG11FB10F
|
||||
128, // RGBA32UI
|
||||
@@ -250,6 +253,8 @@ struct SurfaceParams {
|
||||
return PixelFormat::RGBA32UI;
|
||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||
return PixelFormat::R8;
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
return PixelFormat::R8UI;
|
||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||
return PixelFormat::RG16F;
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
@@ -301,7 +306,15 @@ struct SurfaceParams {
|
||||
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
||||
return PixelFormat::A1B5G5R5;
|
||||
case Tegra::Texture::TextureFormat::R8:
|
||||
return PixelFormat::R8;
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::R8;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R8UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::G8R8:
|
||||
return PixelFormat::G8R8;
|
||||
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
||||
@@ -435,6 +448,7 @@ struct SurfaceParams {
|
||||
return ComponentType::Float;
|
||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
case Tegra::RenderTargetFormat::R16_UINT:
|
||||
return ComponentType::UInt;
|
||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||
|
||||
@@ -356,13 +356,13 @@ public:
|
||||
* @param reg The register to use as the source value.
|
||||
*/
|
||||
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
|
||||
std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
|
||||
std::string dest = GetOutputAttribute(attribute);
|
||||
std::string src = GetRegisterAsFloat(reg);
|
||||
|
||||
if (!dest.empty()) {
|
||||
// Can happen with unknown/unimplemented output attributes, in which case we ignore the
|
||||
// instruction for now.
|
||||
shader.AddLine(dest + " = " + src + ';');
|
||||
shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,6 +376,8 @@ public:
|
||||
return value;
|
||||
} else if (type == GLSLRegister::Type::Integer) {
|
||||
return "floatBitsToInt(" + value + ')';
|
||||
} else if (type == GLSLRegister::Type::UnsignedInteger) {
|
||||
return "floatBitsToUint(" + value + ')';
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@@ -1630,6 +1632,99 @@ private:
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::Xmad: {
|
||||
ASSERT_MSG(!instr.xmad.sign_a, "Unimplemented");
|
||||
ASSERT_MSG(!instr.xmad.sign_b, "Unimplemented");
|
||||
|
||||
std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
|
||||
std::string op_b;
|
||||
std::string op_c;
|
||||
|
||||
// TODO(bunnei): Needs to be fixed once op_a or op_b is signed
|
||||
ASSERT_MSG(instr.xmad.sign_a == instr.xmad.sign_b, "Unimplemented");
|
||||
const bool is_signed{instr.xmad.sign_a == 1};
|
||||
|
||||
bool is_merge{};
|
||||
switch (opcode->GetId()) {
|
||||
case OpCode::Id::XMAD_CR: {
|
||||
is_merge = instr.xmad.merge_56;
|
||||
op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
|
||||
instr.xmad.sign_b ? GLSLRegister::Type::Integer
|
||||
: GLSLRegister::Type::UnsignedInteger);
|
||||
op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::XMAD_RR: {
|
||||
is_merge = instr.xmad.merge_37;
|
||||
op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.xmad.sign_b);
|
||||
op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::XMAD_RC: {
|
||||
op_b += regs.GetRegisterAsInteger(instr.gpr39, 0, instr.xmad.sign_b);
|
||||
op_c += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
|
||||
is_signed ? GLSLRegister::Type::Integer
|
||||
: GLSLRegister::Type::UnsignedInteger);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::XMAD_IMM: {
|
||||
is_merge = instr.xmad.merge_37;
|
||||
op_b += std::to_string(instr.xmad.imm20_16);
|
||||
op_c += regs.GetRegisterAsInteger(instr.gpr39, 0, is_signed);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->GetName());
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bunnei): Ensure this is right with signed operands
|
||||
if (instr.xmad.high_a) {
|
||||
op_a = "((" + op_a + ") >> 16)";
|
||||
} else {
|
||||
op_a = "((" + op_a + ") & 0xFFFF)";
|
||||
}
|
||||
|
||||
std::string src2 = '(' + op_b + ')'; // Preserve original source 2
|
||||
if (instr.xmad.high_b) {
|
||||
op_b = '(' + src2 + " >> 16)";
|
||||
} else {
|
||||
op_b = '(' + src2 + " & 0xFFFF)";
|
||||
}
|
||||
|
||||
std::string product = '(' + op_a + " * " + op_b + ')';
|
||||
if (instr.xmad.product_shift_left) {
|
||||
product = '(' + product + " << 16)";
|
||||
}
|
||||
|
||||
switch (instr.xmad.mode) {
|
||||
case Tegra::Shader::XmadMode::None:
|
||||
break;
|
||||
case Tegra::Shader::XmadMode::CLo:
|
||||
op_c = "((" + op_c + ") & 0xFFFF)";
|
||||
break;
|
||||
case Tegra::Shader::XmadMode::CHi:
|
||||
op_c = "((" + op_c + ") >> 16)";
|
||||
break;
|
||||
case Tegra::Shader::XmadMode::CBcc:
|
||||
op_c = "((" + op_c + ") + (" + src2 + "<< 16))";
|
||||
break;
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled XMAD mode: {}",
|
||||
static_cast<u32>(instr.xmad.mode.Value()));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
std::string sum{'(' + product + " + " + op_c + ')'};
|
||||
if (is_merge) {
|
||||
sum = "((" + sum + " & 0xFFFF) | (" + src2 + "<< 16))";
|
||||
}
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
switch (opcode->GetId()) {
|
||||
case OpCode::Id::EXIT: {
|
||||
@@ -1667,7 +1762,15 @@ private:
|
||||
}
|
||||
case OpCode::Id::KIL: {
|
||||
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
||||
|
||||
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
|
||||
// about unexecuted instructions that may follow this.
|
||||
shader.AddLine("if (true) {");
|
||||
++shader.scope;
|
||||
shader.AddLine("discard;");
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::BRA: {
|
||||
|
||||
@@ -203,21 +203,6 @@ void OpenGLState::Apply() const {
|
||||
}
|
||||
}
|
||||
|
||||
// Constbuffers
|
||||
for (std::size_t stage = 0; stage < draw.const_buffers.size(); ++stage) {
|
||||
for (std::size_t buffer_id = 0; buffer_id < draw.const_buffers[stage].size(); ++buffer_id) {
|
||||
const auto& current = cur_state.draw.const_buffers[stage][buffer_id];
|
||||
const auto& new_state = draw.const_buffers[stage][buffer_id];
|
||||
|
||||
if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint ||
|
||||
current.ssbo != new_state.ssbo) {
|
||||
if (new_state.enabled) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, new_state.bindpoint, new_state.ssbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
|
||||
|
||||
@@ -119,12 +119,6 @@ public:
|
||||
GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
|
||||
GLuint shader_program; // GL_CURRENT_PROGRAM
|
||||
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
|
||||
struct ConstBufferConfig {
|
||||
bool enabled = false;
|
||||
GLuint bindpoint;
|
||||
GLuint ssbo;
|
||||
};
|
||||
std::array<std::array<ConstBufferConfig, Regs::MaxConstBuffers>, 5> const_buffers;
|
||||
} draw;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -9,174 +9,91 @@
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
|
||||
class OrphanBuffer : public OGLStreamBuffer {
|
||||
public:
|
||||
explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {}
|
||||
~OrphanBuffer() override;
|
||||
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
|
||||
: gl_target(target), buffer_size(size) {
|
||||
gl_buffer.Create();
|
||||
glBindBuffer(gl_target, gl_buffer.handle);
|
||||
|
||||
private:
|
||||
void Create(size_t size, size_t sync_subdivide) override;
|
||||
void Release() override;
|
||||
GLsizeiptr allocate_size = size;
|
||||
if (target == GL_ARRAY_BUFFER) {
|
||||
// On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer
|
||||
// read position is near the end and is an out-of-bound access to the vertex buffer. This is
|
||||
// probably a bug in the driver and is related to the usage of vec3<byte> attributes in the
|
||||
// vertex array. Doubling the allocation size for the vertex buffer seems to avoid the
|
||||
// crash.
|
||||
allocate_size *= 2;
|
||||
}
|
||||
|
||||
std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
|
||||
void Unmap() override;
|
||||
if (GLAD_GL_ARB_buffer_storage) {
|
||||
persistent = true;
|
||||
coherent = prefer_coherent;
|
||||
GLbitfield flags =
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
|
||||
glBufferStorage(gl_target, allocate_size, nullptr, flags);
|
||||
mapped_ptr = static_cast<u8*>(glMapBufferRange(
|
||||
gl_target, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)));
|
||||
} else {
|
||||
glBufferData(gl_target, allocate_size, nullptr, GL_STREAM_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
};
|
||||
|
||||
class StorageBuffer : public OGLStreamBuffer {
|
||||
public:
|
||||
explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {}
|
||||
~StorageBuffer() override;
|
||||
|
||||
private:
|
||||
void Create(size_t size, size_t sync_subdivide) override;
|
||||
void Release() override;
|
||||
|
||||
std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
|
||||
void Unmap() override;
|
||||
|
||||
struct Fence {
|
||||
OGLSync sync;
|
||||
size_t offset;
|
||||
};
|
||||
std::deque<Fence> head;
|
||||
std::deque<Fence> tail;
|
||||
|
||||
u8* mapped_ptr;
|
||||
};
|
||||
|
||||
OGLStreamBuffer::OGLStreamBuffer(GLenum target) {
|
||||
gl_target = target;
|
||||
OGLStreamBuffer::~OGLStreamBuffer() {
|
||||
if (persistent) {
|
||||
glBindBuffer(gl_target, gl_buffer.handle);
|
||||
glUnmapBuffer(gl_target);
|
||||
}
|
||||
gl_buffer.Release();
|
||||
}
|
||||
|
||||
GLuint OGLStreamBuffer::GetHandle() const {
|
||||
return gl_buffer.handle;
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) {
|
||||
if (storage_buffer) {
|
||||
return std::make_unique<StorageBuffer>(target);
|
||||
}
|
||||
return std::make_unique<OrphanBuffer>(target);
|
||||
GLsizeiptr OGLStreamBuffer::GetSize() const {
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
OrphanBuffer::~OrphanBuffer() {
|
||||
Release();
|
||||
}
|
||||
|
||||
void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) {
|
||||
buffer_pos = 0;
|
||||
buffer_size = size;
|
||||
data.resize(buffer_size);
|
||||
|
||||
if (gl_buffer.handle == 0) {
|
||||
gl_buffer.Create();
|
||||
glBindBuffer(gl_target, gl_buffer.handle);
|
||||
}
|
||||
|
||||
glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
void OrphanBuffer::Release() {
|
||||
gl_buffer.Release();
|
||||
}
|
||||
|
||||
std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) {
|
||||
buffer_pos = Common::AlignUp(buffer_pos, alignment);
|
||||
|
||||
if (buffer_pos + size > buffer_size) {
|
||||
Create(std::max(buffer_size, size), 0);
|
||||
}
|
||||
|
||||
mapped_size = size;
|
||||
return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos));
|
||||
}
|
||||
|
||||
void OrphanBuffer::Unmap() {
|
||||
glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos),
|
||||
static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]);
|
||||
buffer_pos += mapped_size;
|
||||
}
|
||||
|
||||
StorageBuffer::~StorageBuffer() {
|
||||
Release();
|
||||
}
|
||||
|
||||
void StorageBuffer::Create(size_t size, size_t sync_subdivide) {
|
||||
if (gl_buffer.handle != 0)
|
||||
return;
|
||||
|
||||
buffer_pos = 0;
|
||||
buffer_size = size;
|
||||
buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1);
|
||||
|
||||
gl_buffer.Create();
|
||||
glBindBuffer(gl_target, gl_buffer.handle);
|
||||
|
||||
glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr,
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
|
||||
mapped_ptr = reinterpret_cast<u8*>(
|
||||
glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size),
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
|
||||
}
|
||||
|
||||
void StorageBuffer::Release() {
|
||||
if (gl_buffer.handle == 0)
|
||||
return;
|
||||
|
||||
glUnmapBuffer(gl_target);
|
||||
|
||||
gl_buffer.Release();
|
||||
head.clear();
|
||||
tail.clear();
|
||||
}
|
||||
|
||||
std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) {
|
||||
std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) {
|
||||
ASSERT(size <= buffer_size);
|
||||
|
||||
OGLSync sync;
|
||||
|
||||
buffer_pos = Common::AlignUp(buffer_pos, alignment);
|
||||
size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide);
|
||||
|
||||
if (!head.empty() &&
|
||||
(effective_offset > head.back().offset || buffer_pos + size > buffer_size)) {
|
||||
ASSERT(head.back().sync.handle == 0);
|
||||
head.back().sync.Create();
|
||||
}
|
||||
|
||||
if (buffer_pos + size > buffer_size) {
|
||||
if (!tail.empty()) {
|
||||
std::swap(sync, tail.back().sync);
|
||||
tail.clear();
|
||||
}
|
||||
std::swap(tail, head);
|
||||
buffer_pos = 0;
|
||||
effective_offset = 0;
|
||||
}
|
||||
|
||||
while (!tail.empty() && buffer_pos + size > tail.front().offset) {
|
||||
std::swap(sync, tail.front().sync);
|
||||
tail.pop_front();
|
||||
}
|
||||
|
||||
if (sync.handle != 0) {
|
||||
glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
sync.Release();
|
||||
}
|
||||
|
||||
if (head.empty() || effective_offset > head.back().offset) {
|
||||
head.emplace_back();
|
||||
head.back().offset = effective_offset;
|
||||
}
|
||||
|
||||
ASSERT(alignment <= buffer_size);
|
||||
mapped_size = size;
|
||||
return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos));
|
||||
|
||||
if (alignment > 0) {
|
||||
buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment);
|
||||
}
|
||||
|
||||
bool invalidate = false;
|
||||
if (buffer_pos + size > buffer_size) {
|
||||
buffer_pos = 0;
|
||||
invalidate = true;
|
||||
|
||||
if (persistent) {
|
||||
glUnmapBuffer(gl_target);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidate | !persistent) {
|
||||
GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
|
||||
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
|
||||
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
mapped_ptr = static_cast<u8*>(
|
||||
glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags));
|
||||
mapped_offset = buffer_pos;
|
||||
}
|
||||
|
||||
return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate);
|
||||
}
|
||||
|
||||
void StorageBuffer::Unmap() {
|
||||
glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos),
|
||||
static_cast<GLsizeiptr>(mapped_size));
|
||||
buffer_pos += mapped_size;
|
||||
void OGLStreamBuffer::Unmap(GLsizeiptr size) {
|
||||
ASSERT(size <= mapped_size);
|
||||
|
||||
if (!coherent && size > 0) {
|
||||
glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size);
|
||||
}
|
||||
|
||||
if (!persistent) {
|
||||
glUnmapBuffer(gl_target);
|
||||
}
|
||||
|
||||
buffer_pos += size;
|
||||
}
|
||||
|
||||
@@ -2,35 +2,41 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
class OGLStreamBuffer : private NonCopyable {
|
||||
public:
|
||||
explicit OGLStreamBuffer(GLenum target);
|
||||
virtual ~OGLStreamBuffer() = default;
|
||||
|
||||
public:
|
||||
static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target);
|
||||
|
||||
virtual void Create(size_t size, size_t sync_subdivide) = 0;
|
||||
virtual void Release() {}
|
||||
explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false);
|
||||
~OGLStreamBuffer();
|
||||
|
||||
GLuint GetHandle() const;
|
||||
GLsizeiptr GetSize() const;
|
||||
|
||||
virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0;
|
||||
virtual void Unmap() = 0;
|
||||
/*
|
||||
* Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes
|
||||
* and the optional alignment requirement.
|
||||
* If the buffer is full, the whole buffer is reallocated which invalidates old chunks.
|
||||
* The return values are the pointer to the new chunk, the offset within the buffer,
|
||||
* and the invalidation flag for previous chunks.
|
||||
* The actual used size must be specified on unmapping the chunk.
|
||||
*/
|
||||
std::tuple<u8*, GLintptr, bool> Map(GLsizeiptr size, GLintptr alignment = 0);
|
||||
|
||||
protected:
|
||||
void Unmap(GLsizeiptr size);
|
||||
|
||||
private:
|
||||
OGLBuffer gl_buffer;
|
||||
GLenum gl_target;
|
||||
|
||||
size_t buffer_pos = 0;
|
||||
size_t buffer_size = 0;
|
||||
size_t buffer_sync_subdivide = 0;
|
||||
size_t mapped_size = 0;
|
||||
bool coherent = false;
|
||||
bool persistent = false;
|
||||
|
||||
GLintptr buffer_pos = 0;
|
||||
GLsizeiptr buffer_size = 0;
|
||||
GLintptr mapped_offset = 0;
|
||||
GLsizeiptr mapped_size = 0;
|
||||
u8* mapped_ptr = nullptr;
|
||||
};
|
||||
|
||||
@@ -156,42 +156,61 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
|
||||
inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
|
||||
switch (factor) {
|
||||
case Maxwell::Blend::Factor::Zero:
|
||||
case Maxwell::Blend::Factor::ZeroGL:
|
||||
return GL_ZERO;
|
||||
case Maxwell::Blend::Factor::One:
|
||||
case Maxwell::Blend::Factor::OneGL:
|
||||
return GL_ONE;
|
||||
case Maxwell::Blend::Factor::SourceColor:
|
||||
case Maxwell::Blend::Factor::SourceColorGL:
|
||||
return GL_SRC_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusSourceColor:
|
||||
case Maxwell::Blend::Factor::OneMinusSourceColorGL:
|
||||
return GL_ONE_MINUS_SRC_COLOR;
|
||||
case Maxwell::Blend::Factor::SourceAlpha:
|
||||
case Maxwell::Blend::Factor::SourceAlphaGL:
|
||||
return GL_SRC_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusSourceAlpha:
|
||||
case Maxwell::Blend::Factor::OneMinusSourceAlphaGL:
|
||||
return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case Maxwell::Blend::Factor::DestAlpha:
|
||||
case Maxwell::Blend::Factor::DestAlphaGL:
|
||||
return GL_DST_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusDestAlpha:
|
||||
case Maxwell::Blend::Factor::OneMinusDestAlphaGL:
|
||||
return GL_ONE_MINUS_DST_ALPHA;
|
||||
case Maxwell::Blend::Factor::DestColor:
|
||||
case Maxwell::Blend::Factor::DestColorGL:
|
||||
return GL_DST_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusDestColor:
|
||||
case Maxwell::Blend::Factor::OneMinusDestColorGL:
|
||||
return GL_ONE_MINUS_DST_COLOR;
|
||||
case Maxwell::Blend::Factor::SourceAlphaSaturate:
|
||||
case Maxwell::Blend::Factor::SourceAlphaSaturateGL:
|
||||
return GL_SRC_ALPHA_SATURATE;
|
||||
case Maxwell::Blend::Factor::Source1Color:
|
||||
case Maxwell::Blend::Factor::Source1ColorGL:
|
||||
return GL_SRC1_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusSource1Color:
|
||||
case Maxwell::Blend::Factor::OneMinusSource1ColorGL:
|
||||
return GL_ONE_MINUS_SRC1_COLOR;
|
||||
case Maxwell::Blend::Factor::Source1Alpha:
|
||||
case Maxwell::Blend::Factor::Source1AlphaGL:
|
||||
return GL_SRC1_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusSource1Alpha:
|
||||
case Maxwell::Blend::Factor::OneMinusSource1AlphaGL:
|
||||
return GL_ONE_MINUS_SRC1_ALPHA;
|
||||
case Maxwell::Blend::Factor::ConstantColor:
|
||||
case Maxwell::Blend::Factor::ConstantColorGL:
|
||||
return GL_CONSTANT_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusConstantColor:
|
||||
case Maxwell::Blend::Factor::OneMinusConstantColorGL:
|
||||
return GL_ONE_MINUS_CONSTANT_COLOR;
|
||||
case Maxwell::Blend::Factor::ConstantAlpha:
|
||||
case Maxwell::Blend::Factor::ConstantAlphaGL:
|
||||
return GL_CONSTANT_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusConstantAlpha:
|
||||
case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
|
||||
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "core/tracer/recorder.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
#include "video_core/utils.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
static const char vertex_shader[] = R"(
|
||||
#version 150 core
|
||||
@@ -92,7 +91,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
|
||||
return matrix;
|
||||
}
|
||||
|
||||
ScopeAcquireGLContext::ScopeAcquireGLContext(EmuWindow& emu_window_) : emu_window{emu_window_} {
|
||||
ScopeAcquireGLContext::ScopeAcquireGLContext(Core::Frontend::EmuWindow& emu_window_)
|
||||
: emu_window{emu_window_} {
|
||||
if (Settings::values.use_multi_core) {
|
||||
emu_window.MakeCurrent();
|
||||
}
|
||||
@@ -103,7 +103,9 @@ ScopeAcquireGLContext::~ScopeAcquireGLContext() {
|
||||
}
|
||||
}
|
||||
|
||||
RendererOpenGL::RendererOpenGL(EmuWindow& window) : VideoCore::RendererBase{window} {}
|
||||
RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window)
|
||||
: VideoCore::RendererBase{window} {}
|
||||
|
||||
RendererOpenGL::~RendererOpenGL() = default;
|
||||
|
||||
/// Swap buffers (render frame)
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
}
|
||||
|
||||
/// Structure used for storing information about the textures for the Switch screen
|
||||
struct TextureInfo {
|
||||
@@ -34,16 +36,16 @@ struct ScreenInfo {
|
||||
/// Helper class to acquire/release OpenGL context within a given scope
|
||||
class ScopeAcquireGLContext : NonCopyable {
|
||||
public:
|
||||
explicit ScopeAcquireGLContext(EmuWindow& window);
|
||||
explicit ScopeAcquireGLContext(Core::Frontend::EmuWindow& window);
|
||||
~ScopeAcquireGLContext();
|
||||
|
||||
private:
|
||||
EmuWindow& emu_window;
|
||||
Core::Frontend::EmuWindow& emu_window;
|
||||
};
|
||||
|
||||
class RendererOpenGL : public VideoCore::RendererBase {
|
||||
public:
|
||||
explicit RendererOpenGL(EmuWindow& window);
|
||||
explicit RendererOpenGL(Core::Frontend::EmuWindow& window);
|
||||
~RendererOpenGL() override;
|
||||
|
||||
/// Swap buffers (render frame)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window) {
|
||||
std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window) {
|
||||
return std::make_unique<RendererOpenGL>(emu_window);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Core::Frontend {
|
||||
class EmuWindow;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
@@ -18,6 +20,6 @@ class RendererBase;
|
||||
* @note The returned renderer instance is simply allocated. Its Init()
|
||||
* function still needs to be called to fully complete its setup.
|
||||
*/
|
||||
std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window);
|
||||
std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window);
|
||||
|
||||
} // namespace VideoCore
|
||||
|
||||
@@ -101,7 +101,7 @@ signals:
|
||||
void ErrorThrown(Core::System::ResultStatus, std::string);
|
||||
};
|
||||
|
||||
class GRenderWindow : public QWidget, public EmuWindow {
|
||||
class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
class EmuWindow_SDL2 : public EmuWindow {
|
||||
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
||||
public:
|
||||
explicit EmuWindow_SDL2(bool fullscreen);
|
||||
~EmuWindow_SDL2();
|
||||
|
||||
Reference in New Issue
Block a user