Compare commits

..

36 Commits

Author SHA1 Message Date
ReinUsesLisp
6b997c8f7f renderer_opengl: Fix rebase mistake 2019-09-11 00:09:37 -03:00
Fernando Sahmkow
e60d281a01 gl_rasterizer: Correct sRGB Fix regression 2019-09-10 19:31:42 -03:00
ReinUsesLisp
78574746bd renderer_opengl: Fix sRGB blits
Removes the sRGB hack of tracking if a frame used an sRGB rendertarget
to apply at least once to blit the final texture as sRGB. Instead of
doing this apply sRGB if the presented image has sRGB.

Also enable sRGB by default on Maxwell3D registers as some games seem to
assume this.
2019-09-10 19:31:42 -03:00
bunnei
34b2c60f95 Merge pull request #2823 from ReinUsesLisp/shr-clamp
shader/shift: Implement SHR wrapped and clamped variants
2019-09-10 11:56:17 -04:00
bunnei
c7ec7bc1f5 Merge pull request #2810 from ReinUsesLisp/mme-opt
maxwell_3d: Avoid moving macro_params
2019-09-10 11:55:45 -04:00
Fernando Sahmkow
434d0922dc Merge pull request #2759 from ReinUsesLisp/compute-images
gl_rasterizer: Bind images and samplers to compute
2019-09-10 08:57:05 -04:00
David
07a0242535 Merge pull request #2847 from VelocityRa/nro-nacp-fix
nro/ui: Show "Developer" field in Properties
2019-09-09 16:45:28 +10:00
David
1487153e06 Merge pull request #2716 from lioncash/hle-global
service/am: Remove usages of global system accessors
2019-09-09 16:44:41 +10:00
David
6f7b349461 Merge pull request #2763 from lioncash/map-phys
kernel/vm_manager: Minor cleanup
2019-09-09 16:43:54 +10:00
Nick Renieris
bfc5bacecd nro: Implement ReadControlData
With this, the "Developer" field in the Properties for homebrew is now populated.

Signed-off-by: Nick Renieris <velocityra@gmail.com>
2019-09-08 00:40:21 +03:00
ReinUsesLisp
1f43e5296f gl_shader_decompiler: Keep track of written images and mark them as modified 2019-09-05 23:26:05 -03:00
ReinUsesLisp
7228e22098 texture_cache: Minor changes 2019-09-05 23:25:15 -03:00
ReinUsesLisp
322d0200c8 gl_rasterizer: Apply textures and images state 2019-09-05 20:35:51 -03:00
ReinUsesLisp
80ec2feee8 gl_rasterizer: Add samplers to compute dispatches 2019-09-05 20:35:51 -03:00
ReinUsesLisp
954fc02fdd gl_rasterizer: Minor code changes 2019-09-05 20:35:51 -03:00
ReinUsesLisp
04cdecb7a1 gl_state: Split textures and samplers into two arrays 2019-09-05 20:35:51 -03:00
ReinUsesLisp
6170337001 gl_rasterizer: Implement image bindings 2019-09-05 20:35:51 -03:00
ReinUsesLisp
5edf24b510 gl_state: Add support for glBindImageTextures 2019-09-05 20:35:51 -03:00
ReinUsesLisp
2424eefad2 texture_cache: Pass TIC to texture cache 2019-09-05 20:35:51 -03:00
ReinUsesLisp
3a450c1395 kepler_compute: Implement texture queries 2019-09-05 20:35:51 -03:00
ReinUsesLisp
2e5b5c2358 gl_rasterizer: Split SetupTextures 2019-09-05 20:35:51 -03:00
Fernando Sahmkow
4ee9949639 Merge pull request #2804 from ReinUsesLisp/remove-gs-special
gl_shader_cache: Remove special casing for geometry shaders
2019-09-05 16:03:46 -04:00
bunnei
03badbdd9b Merge pull request #2833 from ReinUsesLisp/fix-stencil
gl_rasterizer: Fix stencil testing
2019-09-05 15:27:31 -04:00
Lioncash
d1abe8e92a service/am: Remove usages of global system accessors
Avoids the use of global accessors, removing the reliance on global
state. This also makes dependencies explicit in the interface, as
opposed to being hidden
2019-09-04 20:38:43 -04:00
Lioncash
f763e23083 kernel/vm_manager: Correct doxygen comment parameter tags for MapPhysicalMemory/UnmapPhysicalMemory
Corrects the parameter names within the doxygen comments so that they
resolve properly.
2019-09-04 19:58:55 -04:00
Lioncash
b0da7e4262 kernel/vm_manager: Move variables closer to usage spots in MapPhysicalMemory/UnmapPhysicalMemory
Narrows the scope of variables down to where they're only necessary.
2019-09-04 19:58:52 -04:00
ReinUsesLisp
7bbc98cfc3 gl_rasterizer: Fix stencil testing
* Fix stencil dirty flags tracking when stencil is disabled
* Attach stencil on clears (previously it only attached depth)
* Attach stencil on drawing regardless of stencil testing being enabled
2019-09-04 01:59:09 -03:00
ReinUsesLisp
77ef4fa907 shader/shift: Implement SHR wrapped and clamped variants
Nvidia defaults to wrapped shifts, but this is undefined behaviour on
OpenGL's spec. Explicitly mask/clamp according to what the guest shader
requires.
2019-09-04 01:55:24 -03:00
ReinUsesLisp
701dedcfad maxwell_3d: Avoid moving macro_params 2019-09-04 01:55:01 -03:00
ReinUsesLisp
42e1bb6d46 gl_shader_cache: Remove special casing for geometry shaders
Now that ProgramVariants holds the primitive topology we no longer need
to keep track of individual geometry shaders topologies.
2019-09-04 01:54:43 -03:00
Lioncash
96cc9a9279 kernel/vm_manager: Correct behavior in failure case of UnmapPhysicalMemory()
If an unmapping operation fails, we shouldn't be decrementing the amount
of memory mapped and returning that the operation was successful. We
should actually be returning the error code in this case.
2019-08-29 19:29:43 -04:00
Lioncash
56c6f767ae kernel/vm_manager: Reserve memory ahead of time for slow path in MergeAdjacentVMA
Avoids potentially expensive (depending on the size of the memory block)
allocations by reserving the necessary memory before performing both
insertions. This avoids scenarios where the second insert may cause a
reallocation to occur.
2019-08-29 19:29:43 -04:00
Lioncash
a43ee8d752 kernel/vm_manager: std::move shared_ptr instance in MergeAdjacentVMA
Avoids an unnecessary atomic reference count increment and decrement.
2019-08-29 19:28:58 -04:00
Lioncash
785c4946dd kernel/vm_manager: Deduplicate iterator creation in MergeAdjacentVMA
Avoids needing to read the same long sequence of code in both code
paths. Also makes it slightly nicer to read and debug, as the locals
will be able to be shown in the debugger.
2019-08-29 19:28:57 -04:00
Lioncash
70485e690b kernel/vm_manager: Simplify some std::vector constructor calls
Same behavior, one less magic constant to read.
2019-08-29 19:28:04 -04:00
Lioncash
3f695333cd kernel/vm_manager: Simplify some assertion messages
Assertions already log out the function name, so there's no need to
manually include the function name in the assertion strings.
2019-08-29 19:26:42 -04:00
51 changed files with 751 additions and 594 deletions

View File

@@ -104,7 +104,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
return vfs->OpenFile(path, FileSys::Mode::Read);
}
struct System::Impl {
explicit Impl(System& system) : kernel{system}, cpu_core_manager{system}, reporter{system} {}
explicit Impl(System& system)
: kernel{system}, cpu_core_manager{system}, applet_manager{system}, reporter{system} {}
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();

View File

@@ -296,12 +296,6 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
}
ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
const auto end_addr = target + size;
const auto last_addr = end_addr - 1;
VAddr cur_addr = target;
ResultCode result = RESULT_SUCCESS;
// Check how much memory we've already mapped.
const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size);
if (mapped_size_result.Failed()) {
@@ -324,13 +318,16 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
// Keep track of the memory regions we unmap.
std::vector<std::pair<u64, u64>> mapped_regions;
ResultCode result = RESULT_SUCCESS;
// Iterate, trying to map memory.
{
cur_addr = target;
const auto end_addr = target + size;
const auto last_addr = end_addr - 1;
VAddr cur_addr = target;
auto iter = FindVMA(target);
ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end");
ASSERT(iter != vma_map.end());
while (true) {
const auto& vma = iter->second;
@@ -342,7 +339,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr);
if (vma.state == MemoryState::Unmapped) {
const auto map_res =
MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size, 0), 0,
MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size), 0,
map_size, MemoryState::Heap, VMAPermission::ReadWrite);
result = map_res.Code();
if (result.IsError()) {
@@ -360,7 +357,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
// Advance to the next block.
cur_addr = vma_end;
iter = FindVMA(cur_addr);
ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end");
ASSERT(iter != vma_map.end());
}
}
@@ -368,7 +365,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
if (result.IsError()) {
for (const auto [unmap_address, unmap_size] : mapped_regions) {
ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(),
"MapPhysicalMemory un-map on error");
"Failed to unmap memory range.");
}
return result;
@@ -381,12 +378,6 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
}
ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
const auto end_addr = target + size;
const auto last_addr = end_addr - 1;
VAddr cur_addr = target;
ResultCode result = RESULT_SUCCESS;
// Check how much memory is currently mapped.
const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size);
if (mapped_size_result.Failed()) {
@@ -401,13 +392,16 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
// Keep track of the memory regions we unmap.
std::vector<std::pair<u64, u64>> unmapped_regions;
ResultCode result = RESULT_SUCCESS;
// Try to unmap regions.
{
cur_addr = target;
const auto end_addr = target + size;
const auto last_addr = end_addr - 1;
VAddr cur_addr = target;
auto iter = FindVMA(target);
ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end");
ASSERT(iter != vma_map.end());
while (true) {
const auto& vma = iter->second;
@@ -434,7 +428,7 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
// Advance to the next block.
cur_addr = vma_end;
iter = FindVMA(cur_addr);
ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end");
ASSERT(iter != vma_map.end());
}
}
@@ -443,10 +437,12 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
if (result.IsError()) {
for (const auto [map_address, map_size] : unmapped_regions) {
const auto remap_res =
MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size, 0), 0,
map_size, MemoryState::Heap, VMAPermission::None);
ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error");
MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size), 0, map_size,
MemoryState::Heap, VMAPermission::None);
ASSERT_MSG(remap_res.Succeeded(), "Failed to remap a memory block.");
}
return result;
}
// Update mapped amount
@@ -757,20 +753,26 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
// Always merge allocated memory blocks, even when they don't share the same backing block.
if (left.type == VMAType::AllocatedMemoryBlock &&
(left.backing_block != right.backing_block || left.offset + left.size != right.offset)) {
const auto right_begin = right.backing_block->begin() + right.offset;
const auto right_end = right_begin + right.size;
// Check if we can save work.
if (left.offset == 0 && left.size == left.backing_block->size()) {
// Fast case: left is an entire backing block.
left.backing_block->insert(left.backing_block->end(),
right.backing_block->begin() + right.offset,
right.backing_block->begin() + right.offset + right.size);
left.backing_block->insert(left.backing_block->end(), right_begin, right_end);
} else {
// Slow case: make a new memory block for left and right.
const auto left_begin = left.backing_block->begin() + left.offset;
const auto left_end = left_begin + left.size;
const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end));
const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end));
auto new_memory = std::make_shared<PhysicalMemory>();
new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset,
left.backing_block->begin() + left.offset + left.size);
new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset,
right.backing_block->begin() + right.offset + right.size);
left.backing_block = new_memory;
new_memory->reserve(left_size + right_size);
new_memory->insert(new_memory->end(), left_begin, left_end);
new_memory->insert(new_memory->end(), right_begin, right_end);
left.backing_block = std::move(new_memory);
left.offset = 0;
}
@@ -965,7 +967,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address,
VAddr cur_addr = address;
auto iter = FindVMA(cur_addr);
ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end");
ASSERT(iter != vma_map.end());
while (true) {
const auto& vma = iter->second;
@@ -986,7 +988,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address,
// Advance to the next block.
cur_addr = vma_end;
iter = std::next(iter);
ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end");
ASSERT(iter != vma_map.end());
}
return MakeResult(mapped_size);
@@ -1000,7 +1002,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad
VAddr cur_addr = address;
auto iter = FindVMA(cur_addr);
ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end");
ASSERT(iter != vma_map.end());
while (true) {
const auto& vma = iter->second;
@@ -1029,7 +1031,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad
// Advance to the next block.
cur_addr = vma_end;
iter = std::next(iter);
ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end");
ASSERT(iter != vma_map.end());
}
return MakeResult(mapped_size);

View File

@@ -454,8 +454,8 @@ public:
/// Maps memory at a given address.
///
/// @param addr The virtual address to map memory at.
/// @param size The amount of memory to map.
/// @param target The virtual address to map memory at.
/// @param size The amount of memory to map.
///
/// @note The destination address must lie within the Map region.
///
@@ -468,8 +468,8 @@ public:
/// Unmaps memory at a given address.
///
/// @param addr The virtual address to unmap memory at.
/// @param size The amount of memory to unmap.
/// @param target The virtual address to unmap memory at.
/// @param size The amount of memory to unmap.
///
/// @note The destination address must lie within the Map region.
///

View File

@@ -56,7 +56,8 @@ struct LaunchParameters {
};
static_assert(sizeof(LaunchParameters) == 0x88);
IWindowController::IWindowController() : ServiceFramework("IWindowController") {
IWindowController::IWindowController(Core::System& system_)
: ServiceFramework("IWindowController"), system{system_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
@@ -75,7 +76,7 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
IWindowController::~IWindowController() = default;
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID();
const u64 process_id = system.CurrentProcess()->GetProcessID();
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
@@ -231,8 +232,9 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
IDebugFunctions::~IDebugFunctions() = default;
ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
ISelfController::ISelfController(Core::System& system_,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger_)
: ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Exit"},
@@ -280,7 +282,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
auto& kernel = system_.Kernel();
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"ISelfController:LaunchableEvent");
@@ -501,8 +503,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable);
}
AppletMessageQueue::AppletMessageQueue() {
auto& kernel = Core::System::GetInstance().Kernel();
AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"AMMessageQueue:OnMessageRecieved");
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
@@ -937,9 +938,8 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id)
: ServiceFramework("ILibraryAppletCreator"),
current_process_title_id(current_process_title_id) {
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
: ServiceFramework("ILibraryAppletCreator"), system{system_} {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
@@ -961,8 +961,8 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
static_cast<u32>(applet_id), applet_mode);
const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id);
const auto& applet_manager{system.GetAppletManager()};
const auto applet = applet_manager.GetApplet(applet_id);
if (applet == nullptr) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
@@ -999,8 +999,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
const auto handle{rp.Pop<Kernel::Handle>()};
const auto transfer_mem =
Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(
handle);
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
@@ -1018,7 +1017,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
}
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
: ServiceFramework("IApplicationFunctions"), system{system_} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1180,7 +1180,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()};
FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
const auto res = pm.GetControlMetadata();
if (res.first != nullptr) {
@@ -1188,8 +1188,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = Core::System::GetInstance().ServiceManager();
auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2");
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
@@ -1261,8 +1261,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
"new_journal={:016X}",
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id,
{new_normal_size, new_journal_size});
const auto title_id = system.CurrentProcess()->GetTitleID();
FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -1281,8 +1281,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
user_id[1], user_id[0]);
const auto size =
FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id);
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
@@ -1300,9 +1300,9 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
auto message_queue = std::make_shared<AppletMessageQueue>();
message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
// game boot
auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
// Needed on game boot
message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);

View File

@@ -10,12 +10,15 @@
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
namespace Service {
namespace NVFlinger {
namespace Kernel {
class KernelCore;
}
namespace Service::NVFlinger {
class NVFlinger;
}
namespace AM {
namespace Service::AM {
enum SystemLanguage {
Japanese = 0,
@@ -47,7 +50,7 @@ public:
PerformanceModeChanged = 31,
};
AppletMessageQueue();
explicit AppletMessageQueue(Kernel::KernelCore& kernel);
~AppletMessageQueue();
const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
@@ -65,12 +68,14 @@ private:
class IWindowController final : public ServiceFramework<IWindowController> {
public:
IWindowController();
explicit IWindowController(Core::System& system_);
~IWindowController() override;
private:
void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
Core::System& system;
};
class IAudioController final : public ServiceFramework<IAudioController> {
@@ -113,7 +118,8 @@ public:
class ISelfController final : public ServiceFramework<ISelfController> {
public:
explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
explicit ISelfController(Core::System& system_,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger_);
~ISelfController() override;
private:
@@ -208,7 +214,7 @@ private:
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
ILibraryAppletCreator(u64 current_process_title_id);
explicit ILibraryAppletCreator(Core::System& system_);
~ILibraryAppletCreator() override;
private:
@@ -216,12 +222,12 @@ private:
void CreateStorage(Kernel::HLERequestContext& ctx);
void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
u64 current_process_title_id;
Core::System& system;
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
IApplicationFunctions();
explicit IApplicationFunctions(Core::System& system_);
~IApplicationFunctions() override;
private:
@@ -245,6 +251,7 @@ private:
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
Kernel::EventPair gpu_error_detected_event;
Core::System& system;
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -278,5 +285,4 @@ public:
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
} // namespace AM
} // namespace Service
} // namespace Service::AM

View File

@@ -50,7 +50,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -58,7 +58,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -98,7 +98,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -106,7 +106,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
rb.PushIpcInterface<IApplicationFunctions>(system);
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -154,7 +154,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -162,7 +162,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -194,7 +194,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {

View File

@@ -4,7 +4,6 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -64,7 +63,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
rb.PushIpcInterface<IWindowController>(system);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -72,7 +71,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
@@ -88,7 +87,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -96,7 +95,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
rb.PushIpcInterface<IApplicationFunctions>(system);
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;

View File

@@ -23,8 +23,7 @@
namespace Service::AM::Applets {
AppletDataBroker::AppletDataBroker() {
auto& kernel = Core::System::GetInstance().Kernel();
AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
state_changed_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
@@ -121,7 +120,7 @@ Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent(
return state_changed_event.readable;
}
Applet::Applet() = default;
Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {}
Applet::~Applet() = default;
@@ -154,7 +153,7 @@ AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
AppletManager::AppletManager() = default;
AppletManager::AppletManager(Core::System& system_) : system{system_} {}
AppletManager::~AppletManager() = default;
@@ -216,28 +215,28 @@ void AppletManager::ClearAll() {
frontend = {};
}
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const {
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(*frontend.parental_controls);
return std::make_shared<Auth>(system, *frontend.parental_controls);
case AppletId::Error:
return std::make_shared<Error>(*frontend.error);
return std::make_shared<Error>(system, *frontend.error);
case AppletId::ProfileSelect:
return std::make_shared<ProfileSelect>(*frontend.profile_select);
return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
case AppletId::PhotoViewer:
return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
case AppletId::LibAppletShop:
return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id,
return std::make_shared<WebBrowser>(system, *frontend.web_browser,
frontend.e_commerce.get());
case AppletId::LibAppletOff:
return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id);
return std::make_shared<WebBrowser>(system, *frontend.web_browser);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id));
return std::make_shared<StubApplet>(id);
return std::make_shared<StubApplet>(system, id);
}
}

View File

@@ -12,6 +12,10 @@
union ResultCode;
namespace Core {
class System;
}
namespace Core::Frontend {
class ECommerceApplet;
class ErrorApplet;
@@ -22,6 +26,10 @@ class SoftwareKeyboardApplet;
class WebBrowserApplet;
} // namespace Core::Frontend
namespace Kernel {
class KernelCore;
}
namespace Service::AM {
class IStorage;
@@ -53,7 +61,7 @@ enum class AppletId : u32 {
class AppletDataBroker final {
public:
AppletDataBroker();
explicit AppletDataBroker(Kernel::KernelCore& kernel_);
~AppletDataBroker();
struct RawChannelData {
@@ -108,7 +116,7 @@ private:
class Applet {
public:
Applet();
explicit Applet(Kernel::KernelCore& kernel_);
virtual ~Applet();
virtual void Initialize();
@@ -179,7 +187,7 @@ struct AppletFrontendSet {
class AppletManager {
public:
AppletManager();
explicit AppletManager(Core::System& system_);
~AppletManager();
void SetAppletFrontendSet(AppletFrontendSet set);
@@ -187,10 +195,11 @@ public:
void SetDefaultAppletsIfMissing();
void ClearAll();
std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const;
std::shared_ptr<Applet> GetApplet(AppletId id) const;
private:
AppletFrontendSet frontend;
Core::System& system;
};
} // namespace Applets

View File

@@ -85,7 +85,8 @@ ResultCode Decode64BitError(u64 error) {
} // Anonymous namespace
Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {}
Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
Error::~Error() = default;
@@ -145,8 +146,8 @@ void Error::Execute() {
}
const auto callback = [this] { DisplayCompleted(); };
const auto title_id = Core::CurrentProcess()->GetTitleID();
const auto& reporter{Core::System::GetInstance().GetReporter()};
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto& reporter{system.GetReporter()};
switch (mode) {
case ErrorAppletMode::ShowError:

View File

@@ -7,6 +7,10 @@
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class ErrorAppletMode : u8 {
@@ -21,7 +25,7 @@ enum class ErrorAppletMode : u8 {
class Error final : public Applet {
public:
explicit Error(const Core::Frontend::ErrorApplet& frontend);
explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_);
~Error() override;
void Initialize() override;
@@ -42,6 +46,7 @@ private:
std::unique_ptr<ErrorArguments> args;
bool complete = false;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -37,7 +37,8 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
}
}
Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {}
Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_) {}
Auth::~Auth() = default;
@@ -151,7 +152,8 @@ void Auth::AuthFinished(bool successful) {
broker.SignalStateChanged();
}
PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}
PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
PhotoViewer::~PhotoViewer() = default;
@@ -185,7 +187,7 @@ void PhotoViewer::Execute() {
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback);
frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);
@@ -200,7 +202,8 @@ void PhotoViewer::ViewFinished() {
broker.SignalStateChanged();
}
StubApplet::StubApplet(AppletId id) : id(id) {}
StubApplet::StubApplet(Core::System& system_, AppletId id_)
: Applet{system_.Kernel()}, id(id_), system{system_} {}
StubApplet::~StubApplet() = default;
@@ -209,7 +212,7 @@ void StubApplet::Initialize() {
Applet::Initialize();
const auto data = broker.PeekDataToAppletForDebug();
Core::System::GetInstance().GetReporter().SaveUnimplementedAppletReport(
system.GetReporter().SaveUnimplementedAppletReport(
static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
data.normal, data.interactive);

View File

@@ -6,6 +6,10 @@
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class AuthAppletType : u32 {
@@ -16,7 +20,7 @@ enum class AuthAppletType : u32 {
class Auth final : public Applet {
public:
explicit Auth(Core::Frontend::ParentalControlsApplet& frontend);
explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_);
~Auth() override;
void Initialize() override;
@@ -45,7 +49,7 @@ enum class PhotoViewerAppletMode : u8 {
class PhotoViewer final : public Applet {
public:
explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend);
explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override;
void Initialize() override;
@@ -60,11 +64,12 @@ private:
const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
Core::System& system;
};
class StubApplet final : public Applet {
public:
explicit StubApplet(AppletId id);
explicit StubApplet(Core::System& system_, AppletId id_);
~StubApplet() override;
void Initialize() override;
@@ -76,6 +81,7 @@ public:
private:
AppletId id;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -15,8 +15,9 @@ namespace Service::AM::Applets {
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend)
: frontend(frontend) {}
ProfileSelect::ProfileSelect(Core::System& system_,
const Core::Frontend::ProfileSelectApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_) {}
ProfileSelect::~ProfileSelect() = default;

View File

@@ -11,6 +11,10 @@
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
struct UserSelectionConfig {
@@ -29,7 +33,8 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
class ProfileSelect final : public Applet {
public:
explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend);
explicit ProfileSelect(Core::System& system_,
const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override;
void Initialize() override;

View File

@@ -39,8 +39,9 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
return params;
}
SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend)
: frontend(frontend) {}
SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
const Core::Frontend::SoftwareKeyboardApplet& frontend_)
: Applet{system_.Kernel()}, frontend(frontend_) {}
SoftwareKeyboard::~SoftwareKeyboard() = default;

View File

@@ -16,6 +16,10 @@
union ResultCode;
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class KeysetDisable : u32 {
@@ -55,7 +59,8 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz
class SoftwareKeyboard final : public Applet {
public:
explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend);
explicit SoftwareKeyboard(Core::System& system_,
const Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override;
void Initialize() override;

View File

@@ -190,8 +190,9 @@ std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>&
return out;
}
FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) {
const auto& installed{Core::System::GetInstance().GetContentProvider()};
FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id,
FileSys::ContentRecordType type) {
const auto& installed{system.GetContentProvider()};
const auto res = installed.GetEntry(title_id, type);
if (res != nullptr) {
@@ -207,10 +208,10 @@ FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordTyp
} // Anonymous namespace
WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
Core::Frontend::ECommerceApplet* frontend_e_commerce)
: frontend(frontend), frontend_e_commerce(frontend_e_commerce),
current_process_title_id(current_process_title_id) {}
WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
Core::Frontend::ECommerceApplet* frontend_e_commerce_)
: Applet{system_.Kernel()}, frontend(frontend_),
frontend_e_commerce(frontend_e_commerce_), system{system_} {}
WebBrowser::~WebBrowser() = default;
@@ -266,7 +267,7 @@ void WebBrowser::UnpackRomFS() {
ASSERT(offline_romfs != nullptr);
const auto dir =
FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
const auto& vfs{Core::System::GetInstance().GetFilesystem()};
const auto& vfs{system.GetFilesystem()};
const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
FileSys::VfsRawCopyD(dir, temp_dir);
@@ -470,10 +471,10 @@ void WebBrowser::InitializeOffline() {
}
if (title_id == 0) {
title_id = current_process_title_id;
title_id = system.CurrentProcess()->GetTitleID();
}
offline_romfs = GetApplicationRomFS(title_id, type);
offline_romfs = GetApplicationRomFS(system, title_id, type);
if (offline_romfs == nullptr) {
status = ResultCode(-1);
LOG_ERROR(Service_AM, "Failed to find offline data for request!");

View File

@@ -9,6 +9,10 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class ShimKind : u32;
@@ -17,8 +21,8 @@ enum class WebArgTLVType : u16;
class WebBrowser final : public Applet {
public:
WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr);
WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr);
~WebBrowser() override;
@@ -59,8 +63,6 @@ private:
bool unpacked = false;
ResultCode status = RESULT_SUCCESS;
u64 current_process_title_id;
ShimKind kind;
std::map<WebArgTLVType, std::vector<u8>> args;
@@ -74,6 +76,8 @@ private:
std::optional<u128> user_id;
std::optional<bool> shop_full_display;
std::string shop_extra_parameter;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -258,6 +258,15 @@ ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
return ResultStatus::Success;
}
ResultStatus AppLoader_NRO::ReadControlData(FileSys::NACP& control) {
if (nacp == nullptr) {
return ResultStatus::ErrorNoControl;
}
control = *nacp;
return ResultStatus::Success;
}
bool AppLoader_NRO::IsRomFSUpdatable() const {
return false;
}

View File

@@ -43,6 +43,7 @@ public:
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadTitle(std::string& title) override;
ResultStatus ReadControlData(FileSys::NACP& control) override;
bool IsRomFSUpdatable() const override;
private:

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <bitset>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
@@ -49,6 +50,33 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
}
}
Tegra::Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
const std::bitset<8> cbuf_mask = launch_description.const_buffer_enable_mask.Value();
ASSERT(cbuf_mask[regs.tex_cb_index]);
const auto& texinfo = launch_description.const_buffer_config[regs.tex_cb_index];
ASSERT(texinfo.Address() != 0);
const GPUVAddr address = texinfo.Address() + offset * sizeof(Texture::TextureHandle);
ASSERT(address < texinfo.Address() + texinfo.size);
const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(address)};
return GetTextureInfo(tex_handle, offset);
}
Texture::FullTextureInfo KeplerCompute::GetTextureInfo(const Texture::TextureHandle tex_handle,
std::size_t offset) const {
return Texture::FullTextureInfo{static_cast<u32>(offset), GetTICEntry(tex_handle.tic_id),
GetTSCEntry(tex_handle.tsc_id)};
}
u32 KeplerCompute::AccessConstBuffer32(u64 const_buffer, u64 offset) const {
const auto& buffer = launch_description.const_buffer_config[const_buffer];
u32 result;
std::memcpy(&result, memory_manager.GetPointer(buffer.Address() + offset), sizeof(u32));
return result;
}
void KeplerCompute::ProcessLaunch() {
const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address();
memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description,
@@ -60,4 +88,29 @@ void KeplerCompute::ProcessLaunch() {
rasterizer.DispatchCompute(code_addr);
}
Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
const GPUVAddr tic_address_gpu{regs.tic.Address() + tic_index * sizeof(Texture::TICEntry)};
Texture::TICEntry tic_entry;
memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
const auto r_type{tic_entry.r_type.Value()};
const auto g_type{tic_entry.g_type.Value()};
const auto b_type{tic_entry.b_type.Value()};
const auto a_type{tic_entry.a_type.Value()};
// TODO(Subv): Different data types for separate components are not supported
DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
return tic_entry;
}
Texture::TSCEntry KeplerCompute::GetTSCEntry(u32 tsc_index) const {
const GPUVAddr tsc_address_gpu{regs.tsc.Address() + tsc_index * sizeof(Texture::TSCEntry)};
Texture::TSCEntry tsc_entry;
memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry));
return tsc_entry;
}
} // namespace Tegra::Engines

View File

@@ -12,6 +12,7 @@
#include "common/common_types.h"
#include "video_core/engines/engine_upload.h"
#include "video_core/gpu.h"
#include "video_core/textures/texture.h"
namespace Core {
class System;
@@ -111,7 +112,7 @@ public:
INSERT_PADDING_WORDS(0x3FE);
u32 texture_const_buffer_index;
u32 tex_cb_index;
INSERT_PADDING_WORDS(0x374);
};
@@ -149,7 +150,7 @@ public:
union {
BitField<0, 8, u32> const_buffer_enable_mask;
BitField<29, 2, u32> cache_layout;
} memory_config;
};
INSERT_PADDING_WORDS(0x8);
@@ -194,6 +195,14 @@ public:
/// Write the value to the register identified by method.
void CallMethod(const GPU::MethodCall& method_call);
Tegra::Texture::FullTextureInfo GetTexture(std::size_t offset) const;
/// Given a Texture Handle, returns the TSC and TIC entries.
Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
std::size_t offset) const;
u32 AccessConstBuffer32(u64 const_buffer, u64 offset) const;
private:
Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
@@ -201,6 +210,12 @@ private:
Upload::State upload_state;
void ProcessLaunch();
/// Retrieves information about a specific TIC entry from the TIC buffer.
Texture::TICEntry GetTICEntry(u32 tic_index) const;
/// Retrieves information about a specific TSC entry from the TSC buffer.
Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
};
#define ASSERT_REG_POSITION(field_name, position) \
@@ -218,12 +233,12 @@ ASSERT_REG_POSITION(launch, 0xAF);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(code_loc, 0x582);
ASSERT_REG_POSITION(texture_const_buffer_index, 0x982);
ASSERT_REG_POSITION(tex_cb_index, 0x982);
ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8);
ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC);
ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11);
ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12);
ASSERT_LAUNCH_PARAM_POSITION(memory_config, 0x14);
ASSERT_LAUNCH_PARAM_POSITION(const_buffer_enable_mask, 0x14);
ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D);
#undef ASSERT_REG_POSITION

View File

@@ -89,6 +89,9 @@ void Maxwell3D::InitializeRegisterDefaults() {
// Commercial games seem to assume this value is enabled and nouveau sets this value manually.
regs.rt_separate_frag_data = 1;
// Some games (like Super Mario Odyssey) assume that SRGB is enabled.
regs.framebuffer_srgb = 1;
}
#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
@@ -244,7 +247,7 @@ void Maxwell3D::InitDirtySettings() {
dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg;
}
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters) {
// Reset the current macro.
executing_macro = 0;
@@ -252,7 +255,7 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
const u32 entry = ((method - MacroRegistersStart) >> 1) % macro_positions.size();
// Execute the current macro.
macro_interpreter.Execute(macro_positions[entry], std::move(parameters));
macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
}
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
@@ -289,7 +292,8 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
// Call the macro when there are no more parameters in the command buffer
if (method_call.IsLastCall()) {
CallMacroMethod(executing_macro, std::move(macro_params));
CallMacroMethod(executing_macro, macro_params.size(), macro_params.data());
macro_params.clear();
}
return;
}

View File

@@ -62,6 +62,7 @@ public:
static constexpr std::size_t NumVertexAttributes = 32;
static constexpr std::size_t NumVaryings = 31;
static constexpr std::size_t NumTextureSamplers = 32;
static constexpr std::size_t NumImages = 8; // TODO(Rodrigo): Investigate this number
static constexpr std::size_t NumClipDistances = 8;
static constexpr std::size_t MaxShaderProgram = 6;
static constexpr std::size_t MaxShaderStage = 5;
@@ -1307,9 +1308,10 @@ private:
/**
* Call a macro on this engine.
* @param method Method to call
* @param num_parameters Number of arguments
* @param parameters Arguments to the method call
*/
void CallMacroMethod(u32 method, std::vector<u32> parameters);
void CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters);
/// Handles writes to the macro uploading register.
void ProcessMacroUpload(u32 data);

View File

@@ -674,6 +674,10 @@ union Instruction {
BitField<48, 1, u64> is_signed;
} shift;
union {
BitField<39, 1, u64> wrap;
} shr;
union {
BitField<39, 5, u64> shift_amount;
BitField<48, 1, u64> negate_b;

View File

@@ -14,11 +14,18 @@ namespace Tegra {
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
void MacroInterpreter::Execute(u32 offset, std::size_t num_parameters, const u32* parameters) {
MICROPROFILE_SCOPE(MacroInterp);
Reset();
registers[1] = parameters[0];
this->parameters = std::move(parameters);
if (num_parameters > parameters_capacity) {
parameters_capacity = num_parameters;
this->parameters = std::make_unique<u32[]>(num_parameters);
}
std::memcpy(this->parameters.get(), parameters, num_parameters * sizeof(u32));
this->num_parameters = num_parameters;
// Execute the code until we hit an exit condition.
bool keep_executing = true;
@@ -27,7 +34,7 @@ void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
}
// Assert the the macro used all the input parameters
ASSERT(next_parameter_index == this->parameters.size());
ASSERT(next_parameter_index == num_parameters);
}
void MacroInterpreter::Reset() {
@@ -35,7 +42,7 @@ void MacroInterpreter::Reset() {
pc = 0;
delayed_pc = {};
method_address.raw = 0;
parameters.clear();
num_parameters = 0;
// The next parameter index starts at 1, because $r1 already has the value of the first
// parameter.
next_parameter_index = 1;
@@ -229,7 +236,8 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
}
u32 MacroInterpreter::FetchParameter() {
return parameters.at(next_parameter_index++);
ASSERT(next_parameter_index < num_parameters);
return parameters[next_parameter_index++];
}
u32 MacroInterpreter::GetRegister(u32 register_id) const {

View File

@@ -25,7 +25,7 @@ public:
* @param offset Offset to start execution at.
* @param parameters The parameters of the macro.
*/
void Execute(u32 offset, std::vector<u32> parameters);
void Execute(u32 offset, std::size_t num_parameters, const u32* parameters);
private:
enum class Operation : u32 {
@@ -162,10 +162,12 @@ private:
MethodAddress method_address = {};
/// Input parameters of the current macro.
std::vector<u32> parameters;
std::unique_ptr<u32[]> parameters;
std::size_t num_parameters = 0;
std::size_t parameters_capacity = 0;
/// Index of the next parameter that will be fetched by the 'parm' instruction.
u32 next_parameter_index = 0;
bool carry_flag{};
bool carry_flag = false;
};
} // namespace Tegra

View File

@@ -331,7 +331,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
SetupDrawConstBuffers(stage_enum, shader);
SetupDrawGlobalMemory(stage_enum, shader);
const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)};
const auto texture_buffer_usage{SetupDrawTextures(stage_enum, shader, base_bindings)};
const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
@@ -489,9 +489,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
// Assume that a surface will be written to if it is used as a framebuffer, even if
// the shader doesn't actually write to it.
texture_cache.MarkColorBufferInUse(*single_color_target);
// Workaround for and issue in nvidia drivers
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion;
}
fbkey.is_single_buffer = true;
@@ -512,11 +509,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
// Assume that a surface will be written to if it is used as a framebuffer, even
// if the shader doesn't actually write to it.
texture_cache.MarkColorBufferInUse(index);
// Enable sRGB only for supported formats
// Workaround for and issue in nvidia drivers
// https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
state.framebuffer_srgb.enabled |=
color_surface->GetSurfaceParams().srgb_conversion;
}
fbkey.color_attachments[index] =
@@ -537,8 +529,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
texture_cache.MarkDepthBufferInUse();
fbkey.zeta = depth_surface;
fbkey.stencil_enable = regs.stencil_enable &&
depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
fbkey.stencil_enable = depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
}
texture_cache.GuardRenderTargets(false);
@@ -577,16 +568,15 @@ void RasterizerOpenGL::ConfigureClearFramebuffer(OpenGLState& current_state, boo
if (depth_surface) {
const auto& params = depth_surface->GetSurfaceParams();
switch (params.type) {
case VideoCore::Surface::SurfaceType::Depth: {
case VideoCore::Surface::SurfaceType::Depth:
depth_surface->Attach(GL_DEPTH_ATTACHMENT, GL_DRAW_FRAMEBUFFER);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
break;
}
case VideoCore::Surface::SurfaceType::DepthStencil: {
depth_surface->Attach(GL_DEPTH_ATTACHMENT, GL_DRAW_FRAMEBUFFER);
case VideoCore::Surface::SurfaceType::DepthStencil:
depth_surface->Attach(GL_DEPTH_STENCIL_ATTACHMENT, GL_DRAW_FRAMEBUFFER);
break;
}
default: { UNIMPLEMENTED(); }
default:
UNIMPLEMENTED();
}
} else {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
@@ -639,6 +629,7 @@ void RasterizerOpenGL::Clear() {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
use_stencil = true;
clear_state.stencil.test_enabled = true;
if (regs.clear_flags.stencil) {
// Stencil affects the clear so fill it with the used masks
clear_state.stencil.front.test_func = GL_ALWAYS;
@@ -802,7 +793,11 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
}
auto kernel = shader_cache.GetComputeKernel(code_addr);
const auto [program, next_bindings] = kernel->GetProgramHandle({});
ProgramVariant variant;
variant.texture_buffer_usage = SetupComputeTextures(kernel);
SetupComputeImages(kernel);
const auto [program, next_bindings] = kernel->GetProgramHandle(variant);
state.draw.shader_program = program;
state.draw.program_pipeline = 0;
@@ -817,13 +812,13 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
SetupComputeConstBuffers(kernel);
SetupComputeGlobalMemory(kernel);
// TODO(Rodrigo): Bind images and samplers
buffer_cache.Unmap();
bind_ubo_pushbuffer.Bind();
bind_ssbo_pushbuffer.Bind();
state.ApplyTextures();
state.ApplyImages();
state.ApplyShaderProgram();
state.ApplyProgramPipeline();
@@ -903,6 +898,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
}
screen_info.display_texture = surface->GetTexture();
screen_info.display_srgb = surface->GetSurfaceParams().srgb_conversion;
return true;
}
@@ -923,7 +919,7 @@ void RasterizerOpenGL::SetupComputeConstBuffers(const Shader& kernel) {
const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
for (const auto& entry : kernel->GetShaderEntries().const_buffers) {
const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
const std::bitset<8> mask = launch_desc.memory_config.const_buffer_enable_mask.Value();
const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
Tegra::Engines::ConstBufferInfo buffer;
buffer.address = config.Address();
buffer.size = config.size;
@@ -982,53 +978,125 @@ void RasterizerOpenGL::SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entr
bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size));
}
TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
BaseBindings base_bindings) {
TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage,
const Shader& shader,
BaseBindings base_bindings) {
MICROPROFILE_SCOPE(OpenGL_Texture);
const auto& gpu = system.GPU();
const auto& maxwell3d = gpu.Maxwell3D();
const auto& entries = shader->GetShaderEntries().samplers;
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
"Exceeded the number of active textures.");
TextureBufferUsage texture_buffer_usage{0};
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
const auto& entry = entries[bindpoint];
Tegra::Texture::FullTextureInfo texture;
if (entry.IsBindless()) {
const auto texture = [&]() {
if (!entry.IsBindless()) {
return maxwell3d.GetStageTexture(stage, entry.GetOffset());
}
const auto cbuf = entry.GetBindlessCBuf();
Tegra::Texture::TextureHandle tex_handle;
tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second);
texture = maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
} else {
texture = maxwell3d.GetStageTexture(stage, entry.GetOffset());
}
const u32 current_bindpoint = base_bindings.sampler + bindpoint;
return maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
}();
auto& unit{state.texture_units[current_bindpoint]};
unit.sampler = sampler_cache.GetSampler(texture.tsc);
if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) {
if (view->GetSurfaceParams().IsBuffer()) {
// Record that this texture is a texture buffer.
texture_buffer_usage.set(bindpoint);
} else {
// Apply swizzle to textures that are not buffers.
view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
texture.tic.w_source);
}
state.texture_units[current_bindpoint].texture = view->GetTexture();
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
unit.texture = 0;
if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) {
texture_buffer_usage.set(bindpoint);
}
}
return texture_buffer_usage;
}
TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
MICROPROFILE_SCOPE(OpenGL_Texture);
const auto& compute = system.GPU().KeplerCompute();
const auto& entries = kernel->GetShaderEntries().samplers;
ASSERT_MSG(entries.size() <= std::size(state.textures),
"Exceeded the number of active textures.");
TextureBufferUsage texture_buffer_usage{0};
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
const auto& entry = entries[bindpoint];
const auto texture = [&]() {
if (!entry.IsBindless()) {
return compute.GetTexture(entry.GetOffset());
}
const auto cbuf = entry.GetBindlessCBuf();
Tegra::Texture::TextureHandle tex_handle;
tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
return compute.GetTextureInfo(tex_handle, entry.GetOffset());
}();
if (SetupTexture(bindpoint, texture, entry)) {
texture_buffer_usage.set(bindpoint);
}
}
return texture_buffer_usage;
}
bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
const GLShader::SamplerEntry& entry) {
state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
if (!view) {
// Can occur when texture addr is null or its memory is unmapped/invalid
state.textures[binding] = 0;
return false;
}
state.textures[binding] = view->GetTexture();
if (view->GetSurfaceParams().IsBuffer()) {
return true;
}
// Apply swizzle to textures that are not buffers.
view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
texture.tic.w_source);
return false;
}
void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
const auto& compute = system.GPU().KeplerCompute();
const auto& entries = shader->GetShaderEntries().images;
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
const auto& entry = entries[bindpoint];
const auto tic = [&]() {
if (!entry.IsBindless()) {
return compute.GetTexture(entry.GetOffset()).tic;
}
const auto cbuf = entry.GetBindlessCBuf();
Tegra::Texture::TextureHandle tex_handle;
tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
return compute.GetTextureInfo(tex_handle, entry.GetOffset()).tic;
}();
SetupImage(bindpoint, tic, entry);
}
}
void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
const GLShader::ImageEntry& entry) {
const auto view = texture_cache.GetImageSurface(tic, entry);
if (!view) {
state.images[binding] = 0;
return;
}
if (!tic.IsBuffer()) {
view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
}
if (entry.IsWritten()) {
view->MarkAsModified(texture_cache.Tick());
}
state.images[binding] = view->GetTexture();
}
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
const auto& regs = system.GPU().Maxwell3D().regs;
const bool geometry_shaders_enabled =
@@ -1119,9 +1187,12 @@ void RasterizerOpenGL::SyncStencilTestState() {
if (!maxwell3d.dirty.stencil_test) {
return;
}
const auto& regs = maxwell3d.regs;
maxwell3d.dirty.stencil_test = false;
const auto& regs = maxwell3d.regs;
state.stencil.test_enabled = regs.stencil_enable != 0;
state.MarkDirtyStencilState();
if (!regs.stencil_enable) {
return;
}
@@ -1150,8 +1221,6 @@ void RasterizerOpenGL::SyncStencilTestState() {
state.stencil.back.action_depth_fail = GL_KEEP;
state.stencil.back.action_depth_pass = GL_KEEP;
}
state.MarkDirtyStencilState();
maxwell3d.dirty.stencil_test = false;
}
void RasterizerOpenGL::SyncColorMask() {

View File

@@ -32,6 +32,7 @@
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/utils.h"
#include "video_core/textures/texture.h"
namespace Core {
class System;
@@ -137,8 +138,22 @@ private:
/// Configures the current textures to use for the draw command. Returns shaders texture buffer
/// usage.
TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
const Shader& shader, BaseBindings base_bindings);
TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
const Shader& shader, BaseBindings base_bindings);
/// Configures the textures used in a compute shader. Returns texture buffer usage.
TextureBufferUsage SetupComputeTextures(const Shader& kernel);
/// Configures a texture. Returns true when the texture is a texture buffer.
bool SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
const GLShader::SamplerEntry& entry);
/// Configures images in a compute shader.
void SetupComputeImages(const Shader& shader);
/// Configures an image.
void SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
const GLShader::ImageEntry& entry);
/// Syncs the viewport and depth range to match the guest state
void SyncViewport(OpenGLState& current_state);

View File

@@ -348,23 +348,16 @@ Shader CachedShader::CreateKernelFromCache(const ShaderParameters& params,
}
std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) {
GLuint handle{};
if (program_type == ProgramType::Geometry) {
handle = GetGeometryShader(variant);
} else {
const auto [entry, is_cache_miss] = programs.try_emplace(variant);
auto& program = entry->second;
if (is_cache_miss) {
program = TryLoadProgram(variant);
if (!program) {
program = SpecializeShader(code, entries, program_type, variant);
disk_cache.SaveUsage(GetUsage(variant));
}
LabelGLObject(GL_PROGRAM, program->handle, cpu_addr);
const auto [entry, is_cache_miss] = programs.try_emplace(variant);
auto& program = entry->second;
if (is_cache_miss) {
program = TryLoadProgram(variant);
if (!program) {
program = SpecializeShader(code, entries, program_type, variant);
disk_cache.SaveUsage(GetUsage(variant));
}
handle = program->handle;
LabelGLObject(GL_PROGRAM, program->handle, cpu_addr);
}
auto base_bindings = variant.base_bindings;
@@ -375,52 +368,9 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar
base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
base_bindings.sampler += static_cast<u32>(entries.samplers.size());
return {handle, base_bindings};
return {program->handle, base_bindings};
}
GLuint CachedShader::GetGeometryShader(const ProgramVariant& variant) {
const auto [entry, is_cache_miss] = geometry_programs.try_emplace(variant);
auto& programs = entry->second;
switch (variant.primitive_mode) {
case GL_POINTS:
return LazyGeometryProgram(programs.points, variant);
case GL_LINES:
case GL_LINE_STRIP:
return LazyGeometryProgram(programs.lines, variant);
case GL_LINES_ADJACENCY:
case GL_LINE_STRIP_ADJACENCY:
return LazyGeometryProgram(programs.lines_adjacency, variant);
case GL_TRIANGLES:
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
return LazyGeometryProgram(programs.triangles, variant);
case GL_TRIANGLES_ADJACENCY:
case GL_TRIANGLE_STRIP_ADJACENCY:
return LazyGeometryProgram(programs.triangles_adjacency, variant);
default:
UNREACHABLE_MSG("Unknown primitive mode.");
return LazyGeometryProgram(programs.points, variant);
}
}
GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program,
const ProgramVariant& variant) {
if (target_program) {
return target_program->handle;
}
const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(variant.primitive_mode);
target_program = TryLoadProgram(variant);
if (!target_program) {
target_program = SpecializeShader(code, entries, program_type, variant);
disk_cache.SaveUsage(GetUsage(variant));
}
LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name);
return target_program->handle;
};
CachedProgram CachedShader::TryLoadProgram(const ProgramVariant& variant) const {
const auto found = precompiled_programs.find(GetUsage(variant));
if (found == precompiled_programs.end()) {

View File

@@ -86,22 +86,6 @@ private:
explicit CachedShader(const ShaderParameters& params, ProgramType program_type,
GLShader::ProgramResult result);
// Geometry programs. These are needed because GLSL needs an input topology but it's not
// declared by the hardware. Workaround this issue by generating a different shader per input
// topology class.
struct GeometryPrograms {
CachedProgram points;
CachedProgram lines;
CachedProgram lines_adjacency;
CachedProgram triangles;
CachedProgram triangles_adjacency;
};
GLuint GetGeometryShader(const ProgramVariant& variant);
/// Generates a geometry shader or returns one that already exists.
GLuint LazyGeometryProgram(CachedProgram& target_program, const ProgramVariant& variant);
CachedProgram TryLoadProgram(const ProgramVariant& variant) const;
ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant) const;
@@ -117,11 +101,6 @@ private:
std::size_t shader_length{};
std::unordered_map<ProgramVariant, CachedProgram> programs;
std::unordered_map<ProgramVariant, GeometryPrograms> geometry_programs;
std::unordered_map<u32, GLuint> cbuf_resource_cache;
std::unordered_map<u32, GLuint> gmem_resource_cache;
std::unordered_map<u32, GLint> uniform_cache;
};
class ShaderCacheOpenGL final : public RasterizerCache<Shader> {

View File

@@ -325,7 +325,6 @@ public:
DeclareRegisters();
DeclarePredicates();
DeclareLocalMemory();
DeclareSharedMemory();
DeclareInternalFlags();
DeclareInputAttributes();
DeclareOutputAttributes();
@@ -390,11 +389,10 @@ public:
for (const auto& sampler : ir.GetSamplers()) {
entries.samplers.emplace_back(sampler);
}
for (const auto& image : ir.GetImages()) {
for (const auto& [offset, image] : ir.GetImages()) {
entries.images.emplace_back(image);
}
for (const auto& gmem_pair : ir.GetGlobalMemory()) {
const auto& [base, usage] = gmem_pair;
for (const auto& [base, usage] : ir.GetGlobalMemory()) {
entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
usage.is_read, usage.is_written);
}
@@ -501,13 +499,6 @@ private:
code.AddNewLine();
}
void DeclareSharedMemory() {
if (stage != ProgramType::Compute) {
return;
}
code.AddLine("shared uint {}[];", GetSharedMemory());
}
void DeclareInternalFlags() {
for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
const auto flag_code = static_cast<InternalFlag>(flag);
@@ -714,7 +705,7 @@ private:
void DeclareImages() {
const auto& images{ir.GetImages()};
for (const auto& image : images) {
for (const auto& [offset, image] : images) {
const std::string image_type = [&]() {
switch (image.GetType()) {
case Tegra::Shader::ImageType::Texture1D:
@@ -734,9 +725,16 @@ private:
return "image1D";
}
}();
code.AddLine("layout (binding = IMAGE_BINDING_{}) coherent volatile writeonly uniform "
std::string qualifier = "coherent volatile";
if (image.IsRead() && !image.IsWritten()) {
qualifier += " readonly";
} else if (image.IsWritten() && !image.IsRead()) {
qualifier += " writeonly";
}
code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform "
"{} {};",
image.GetIndex(), image_type, GetImage(image));
image.GetIndex(), qualifier, image_type, GetImage(image));
}
if (!images.empty()) {
code.AddNewLine();
@@ -866,12 +864,6 @@ private:
Type::Uint};
}
if (const auto smem = std::get_if<SmemNode>(&*node)) {
return {
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
Type::Uint};
}
if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
return {GetInternalFlag(internal_flag->GetFlag()), Type::Bool};
}
@@ -1209,11 +1201,6 @@ private:
target = {
fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
Type::Uint};
} else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
ASSERT(stage == ProgramType::Compute);
target = {
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
Type::Uint};
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
const std::string real = Visit(gmem->GetRealAddress()).AsUint();
const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
@@ -2095,10 +2082,6 @@ private:
return "lmem_" + suffix;
}
std::string GetSharedMemory() const {
return fmt::format("smem_{}", suffix);
}
std::string GetInternalFlag(InternalFlag flag) const {
constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
"overflow_flag"};

View File

@@ -341,13 +341,16 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
u64 index{};
u32 type{};
u8 is_bindless{};
u8 is_read{};
u8 is_written{};
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless)) {
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
!LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) {
return {};
}
entry.entries.images.emplace_back(
static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0);
entry.entries.images.emplace_back(static_cast<u64>(offset), static_cast<std::size_t>(index),
static_cast<Tegra::Shader::ImageType>(type),
is_bindless != 0, is_written != 0, is_read != 0);
}
u32 global_memory_count{};
@@ -429,7 +432,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
!SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0))) {
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0))) {
return false;
}
}

View File

@@ -16,7 +16,6 @@ namespace OpenGL {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
OpenGLState OpenGLState::cur_state;
bool OpenGLState::s_rgb_used;
namespace {
@@ -34,6 +33,25 @@ bool UpdateTie(T1 current_value, const T2 new_value) {
return changed;
}
template <typename T>
std::optional<std::pair<GLuint, GLsizei>> UpdateArray(T& current_values, const T& new_values) {
std::optional<std::size_t> first;
std::size_t last;
for (std::size_t i = 0; i < std::size(current_values); ++i) {
if (!UpdateValue(current_values[i], new_values[i])) {
continue;
}
if (!first) {
first = i;
}
last = i;
}
if (!first) {
return std::nullopt;
}
return std::make_pair(static_cast<GLuint>(*first), static_cast<GLsizei>(last - *first + 1));
}
void Enable(GLenum cap, bool enable) {
if (enable) {
glEnable(cap);
@@ -134,10 +152,6 @@ OpenGLState::OpenGLState() {
logic_op.enabled = false;
logic_op.operation = GL_COPY;
for (auto& texture_unit : texture_units) {
texture_unit.Reset();
}
draw.read_framebuffer = 0;
draw.draw_framebuffer = 0;
draw.vertex_array = 0;
@@ -267,8 +281,6 @@ void OpenGLState::ApplySRgb() const {
return;
cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled;
if (framebuffer_srgb.enabled) {
// Track if sRGB is used
s_rgb_used = true;
glEnable(GL_FRAMEBUFFER_SRGB);
} else {
glDisable(GL_FRAMEBUFFER_SRGB);
@@ -496,52 +508,20 @@ void OpenGLState::ApplyAlphaTest() const {
}
void OpenGLState::ApplyTextures() const {
bool has_delta{};
std::size_t first{};
std::size_t last{};
std::array<GLuint, Maxwell::NumTextureSamplers> textures;
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
const auto& texture_unit = texture_units[i];
auto& cur_state_texture_unit = cur_state.texture_units[i];
textures[i] = texture_unit.texture;
if (cur_state_texture_unit.texture == textures[i]) {
continue;
}
cur_state_texture_unit.texture = textures[i];
if (!has_delta) {
first = i;
has_delta = true;
}
last = i;
}
if (has_delta) {
glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
textures.data() + first);
if (const auto update = UpdateArray(cur_state.textures, textures)) {
glBindTextures(update->first, update->second, textures.data() + update->first);
}
}
void OpenGLState::ApplySamplers() const {
bool has_delta{};
std::size_t first{};
std::size_t last{};
std::array<GLuint, Maxwell::NumTextureSamplers> samplers;
for (std::size_t i = 0; i < std::size(samplers); ++i) {
samplers[i] = texture_units[i].sampler;
if (cur_state.texture_units[i].sampler == texture_units[i].sampler) {
continue;
}
cur_state.texture_units[i].sampler = texture_units[i].sampler;
if (!has_delta) {
first = i;
has_delta = true;
}
last = i;
if (const auto update = UpdateArray(cur_state.samplers, samplers)) {
glBindSamplers(update->first, update->second, samplers.data() + update->first);
}
if (has_delta) {
glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
samplers.data() + first);
}
void OpenGLState::ApplyImages() const {
if (const auto update = UpdateArray(cur_state.images, images)) {
glBindImageTextures(update->first, update->second, images.data() + update->first);
}
}
@@ -576,6 +556,7 @@ void OpenGLState::Apply() {
ApplyLogicOp();
ApplyTextures();
ApplySamplers();
ApplyImages();
if (dirty.polygon_offset) {
ApplyPolygonOffset();
dirty.polygon_offset = false;
@@ -606,18 +587,18 @@ void OpenGLState::EmulateViewportWithScissor() {
}
OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
for (auto& unit : texture_units) {
if (unit.texture == handle) {
unit.Unbind();
for (auto& texture : textures) {
if (texture == handle) {
texture = 0;
}
}
return *this;
}
OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
for (auto& unit : texture_units) {
if (unit.sampler == handle) {
unit.sampler = 0;
for (auto& sampler : samplers) {
if (sampler == handle) {
sampler = 0;
}
}
return *this;

View File

@@ -118,21 +118,9 @@ public:
GLenum operation;
} logic_op;
// 3 texture units - one for each that is used in PICA fragment shader emulation
struct TextureUnit {
GLuint texture; // GL_TEXTURE_BINDING_2D
GLuint sampler; // GL_SAMPLER_BINDING
void Unbind() {
texture = 0;
}
void Reset() {
Unbind();
sampler = 0;
}
};
std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures{};
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers{};
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images{};
struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -187,14 +175,6 @@ public:
return cur_state;
}
static bool GetsRGBUsed() {
return s_rgb_used;
}
static void ClearsRGBUsed() {
s_rgb_used = false;
}
void SetDefaultViewports();
/// Apply this state as the current OpenGL state
void Apply();
@@ -220,6 +200,7 @@ public:
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
void ApplyImages() const;
void ApplyDepthClamp() const;
void ApplyPolygonOffset() const;
void ApplyAlphaTest() const;
@@ -264,8 +245,6 @@ public:
private:
static OpenGLState cur_state;
// Workaround for sRGB problems caused by QT not supporting srgb output
static bool s_rgb_used;
struct {
bool blend_state;
bool stencil_state;

View File

@@ -78,6 +78,17 @@ public:
/// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
void Attach(GLenum attachment, GLenum target) const;
void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
Tegra::Texture::SwizzleSource z_source,
Tegra::Texture::SwizzleSource w_source);
void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
void MarkAsModified(u64 tick) {
surface.MarkAsModified(true, tick);
}
GLuint GetTexture() const {
if (is_proxy) {
return surface.GetTexture();
@@ -89,13 +100,6 @@ public:
return surface.GetSurfaceParams();
}
void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
Tegra::Texture::SwizzleSource z_source,
Tegra::Texture::SwizzleSource w_source);
void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
private:
u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
@@ -111,8 +115,8 @@ private:
GLenum target{};
OGLTextureView texture_view;
u32 swizzle;
bool is_proxy;
u32 swizzle{};
bool is_proxy{};
};
class TextureCacheOpenGL final : public TextureCacheBase {

View File

@@ -264,7 +264,6 @@ void RendererOpenGL::CreateRasterizer() {
if (rasterizer) {
return;
}
OpenGLState::ClearsRGBUsed();
rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info);
}
@@ -342,21 +341,17 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
}};
state.texture_units[0].texture = screen_info.display_texture;
// Workaround brigthness problems in SMO by enabling sRGB in the final output
// if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
state.textures[0] = screen_info.display_texture;
state.framebuffer_srgb.enabled = screen_info.display_srgb;
state.AllDirty();
state.Apply();
glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Restore default state
state.framebuffer_srgb.enabled = false;
state.texture_units[0].texture = 0;
state.textures[0] = 0;
state.AllDirty();
state.Apply();
// Clear sRGB state for the next frame
OpenGLState::ClearsRGBUsed();
}
/**
@@ -406,8 +401,8 @@ void RendererOpenGL::CaptureScreenshot() {
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, state.GetsRGBUsed() ? GL_SRGB8 : GL_RGB8, layout.width,
layout.height);
glRenderbufferStorage(GL_RENDERBUFFER, screen_info.display_srgb ? GL_SRGB8 : GL_RGB8,
layout.width, layout.height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
DrawScreen(layout);

View File

@@ -38,7 +38,8 @@ struct TextureInfo {
/// Structure used for storing information about the display target for the Switch screen
struct ScreenInfo {
GLuint display_texture;
GLuint display_texture{};
bool display_srgb{};
const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f};
TextureInfo texture;
};

View File

@@ -61,56 +61,54 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
}
const auto type{instr.sust.image_type};
const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
: GetBindlessImage(instr.gpr39, type)};
auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
: GetBindlessImage(instr.gpr39, type)};
image.MarkWrite();
MetaImage meta{image, values};
const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
bb.push_back(store);
break;
}
default:
UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
UNIMPLEMENTED_MSG("Unhandled image instruction: {}", opcode->get().GetName());
}
return pc;
}
const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
const auto offset{static_cast<std::size_t>(image.index.Value())};
Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
const auto offset{static_cast<u64>(image.index.Value())};
// If this image has already been used, return the existing mapping.
const auto itr{std::find_if(used_images.begin(), used_images.end(),
[=](const Image& entry) { return entry.GetOffset() == offset; })};
if (itr != used_images.end()) {
ASSERT(itr->GetType() == type);
return *itr;
const auto it = used_images.find(offset);
if (it != used_images.end()) {
ASSERT(it->second.GetType() == type);
return it->second;
}
// Otherwise create a new mapping for this image.
const std::size_t next_index{used_images.size()};
const Image entry{offset, next_index, type};
return *used_images.emplace(entry).first;
return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
}
const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
Tegra::Shader::ImageType type) {
Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
const Node image_register{GetRegister(reg)};
const auto [base_image, cbuf_index, cbuf_offset]{
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
// If this image has already been used, return the existing mapping.
const auto itr{std::find_if(used_images.begin(), used_images.end(),
[=](const Image& entry) { return entry.GetOffset() == cbuf_key; })};
if (itr != used_images.end()) {
ASSERT(itr->GetType() == type);
return *itr;
const auto it = used_images.find(cbuf_key);
if (it != used_images.end()) {
ASSERT(it->second.GetType() == type);
return it->second;
}
// Otherwise create a new mapping for this image.
const std::size_t next_index{used_images.size()};
const Image entry{cbuf_index, cbuf_offset, next_index, type};
return *used_images.emplace(entry).first;
return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
.first->second;
}
} // namespace VideoCommon::Shader

View File

@@ -35,7 +35,7 @@ u32 GetUniformTypeElementsCount(Tegra::Shader::UniformType uniform_type) {
return 1;
}
}
} // Anonymous namespace
} // namespace
u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
@@ -106,17 +106,16 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
}
break;
}
case OpCode::Id::LD_L:
LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown));
[[fallthrough]];
case OpCode::Id::LD_S: {
const auto GetMemory = [&](s32 offset) {
case OpCode::Id::LD_L: {
LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}",
static_cast<u64>(instr.ld_l.unknown.Value()));
const auto GetLmem = [&](s32 offset) {
ASSERT(offset % 4 == 0);
const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset);
const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
immediate_offset);
return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(address)
: GetLocalMemory(address);
return GetLocalMemory(address);
};
switch (instr.ldst_sl.type.Value()) {
@@ -136,16 +135,14 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
return 0;
}
}();
for (u32 i = 0; i < count; ++i) {
SetTemporary(bb, i, GetMemory(i * 4));
}
for (u32 i = 0; i < count; ++i) {
for (u32 i = 0; i < count; ++i)
SetTemporary(bb, i, GetLmem(i * 4));
for (u32 i = 0; i < count; ++i)
SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
}
break;
}
default:
UNIMPLEMENTED_MSG("{} Unhandled type: {}", opcode->get().GetName(),
UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
static_cast<u32>(instr.ldst_sl.type.Value()));
}
break;
@@ -212,34 +209,27 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::ST_L:
case OpCode::Id::ST_L: {
LOG_DEBUG(HW_GPU, "ST_L cache management mode: {}",
static_cast<u64>(instr.st_l.cache_management.Value()));
[[fallthrough]];
case OpCode::Id::ST_S: {
const auto GetAddress = [&](s32 offset) {
const auto GetLmemAddr = [&](s32 offset) {
ASSERT(offset % 4 == 0);
const Node immediate = Immediate(static_cast<s32>(instr.smem_imm) + offset);
return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate);
};
const auto set_memory = opcode->get().GetId() == OpCode::Id::ST_L
? &ShaderIR::SetLocalMemory
: &ShaderIR::SetSharedMemory;
switch (instr.ldst_sl.type.Value()) {
case Tegra::Shader::StoreType::Bits128:
(this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3));
(this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2));
[[fallthrough]];
SetLocalMemory(bb, GetLmemAddr(12), GetRegister(instr.gpr0.Value() + 3));
SetLocalMemory(bb, GetLmemAddr(8), GetRegister(instr.gpr0.Value() + 2));
case Tegra::Shader::StoreType::Bits64:
(this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1));
[[fallthrough]];
SetLocalMemory(bb, GetLmemAddr(4), GetRegister(instr.gpr0.Value() + 1));
case Tegra::Shader::StoreType::Bits32:
(this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0));
SetLocalMemory(bb, GetLmemAddr(0), GetRegister(instr.gpr0));
break;
default:
UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(),
UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
static_cast<u32>(instr.ldst_sl.type.Value()));
}
break;

View File

@@ -17,8 +17,8 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
const Instruction instr = {program_code[pc]};
const auto opcode = OpCode::Decode(instr);
const Node op_a = GetRegister(instr.gpr8);
const Node op_b = [&]() {
Node op_a = GetRegister(instr.gpr8);
Node op_b = [&]() {
if (instr.is_b_imm) {
return Immediate(instr.alu.GetSignedImm20_20());
} else if (instr.is_b_gpr) {
@@ -32,16 +32,23 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
case OpCode::Id::SHR_C:
case OpCode::Id::SHR_R:
case OpCode::Id::SHR_IMM: {
const Node value = SignedOperation(OperationCode::IArithmeticShiftRight,
instr.shift.is_signed, PRECISE, op_a, op_b);
if (instr.shr.wrap) {
op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
} else {
op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
}
Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
std::move(op_a), std::move(op_b));
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
SetRegister(bb, instr.gpr0, value);
SetRegister(bb, instr.gpr0, std::move(value));
break;
}
case OpCode::Id::SHL_C:
case OpCode::Id::SHL_R:
case OpCode::Id::SHL_IMM: {
const Node value = Operation(OperationCode::ILogicalShiftLeft, PRECISE, op_a, op_b);
const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
SetRegister(bb, instr.gpr0, value);
break;

View File

@@ -198,13 +198,12 @@ class PredicateNode;
class AbufNode;
class CbufNode;
class LmemNode;
class SmemNode;
class GmemNode;
class CommentNode;
using NodeData =
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
PredicateNode, AbufNode, CbufNode, LmemNode, SmemNode, GmemNode, CommentNode>;
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
@@ -274,46 +273,64 @@ private:
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
};
class Image {
class Image final {
public:
explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
constexpr explicit Image(u64 offset, std::size_t index, Tegra::Shader::ImageType type)
: offset{offset}, index{index}, type{type}, is_bindless{false} {}
explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::ImageType type)
constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::ImageType type)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
is_bindless{true} {}
explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
bool is_bindless)
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {}
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
bool is_bindless, bool is_written, bool is_read)
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
is_written{is_written}, is_read{is_read} {}
std::size_t GetOffset() const {
void MarkRead() {
is_read = true;
}
void MarkWrite() {
is_written = true;
}
constexpr std::size_t GetOffset() const {
return offset;
}
std::size_t GetIndex() const {
constexpr std::size_t GetIndex() const {
return index;
}
Tegra::Shader::ImageType GetType() const {
constexpr Tegra::Shader::ImageType GetType() const {
return type;
}
bool IsBindless() const {
constexpr bool IsBindless() const {
return is_bindless;
}
bool operator<(const Image& rhs) const {
return std::tie(offset, index, type, is_bindless) <
std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
constexpr bool IsRead() const {
return is_read;
}
constexpr bool IsWritten() const {
return is_written;
}
constexpr std::pair<u32, u32> GetBindlessCBuf() const {
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
}
private:
std::size_t offset{};
u64 offset{};
std::size_t index{};
Tegra::Shader::ImageType type{};
bool is_bindless{};
bool is_read{};
bool is_written{};
};
struct GlobalMemoryBase {
@@ -537,19 +554,6 @@ private:
Node address;
};
/// Shared memory node
class SmemNode final {
public:
explicit SmemNode(Node address) : address{std::move(address)} {}
const Node& GetAddress() const {
return address;
}
private:
Node address;
};
/// Global memory node
class GmemNode final {
public:

View File

@@ -137,10 +137,6 @@ Node ShaderIR::GetLocalMemory(Node address) {
return MakeNode<LmemNode>(std::move(address));
}
Node ShaderIR::GetSharedMemory(Node address) {
return MakeNode<SmemNode>(std::move(address));
}
Node ShaderIR::GetTemporary(u32 id) {
return GetRegister(Register::ZeroIndex + 1 + id);
}
@@ -382,11 +378,6 @@ void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
}
void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
bb.push_back(
Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
}
void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
}

View File

@@ -95,7 +95,7 @@ public:
return used_samplers;
}
const std::set<Image>& GetImages() const {
const std::map<u64, Image>& GetImages() const {
return used_images;
}
@@ -208,8 +208,6 @@ private:
Node GetInternalFlag(InternalFlag flag, bool negated = false);
/// Generates a node representing a local memory address
Node GetLocalMemory(Node address);
/// Generates a node representing a shared memory address
Node GetSharedMemory(Node address);
/// Generates a temporary, internally it uses a post-RZ register
Node GetTemporary(u32 id);
@@ -219,10 +217,8 @@ private:
void SetPredicate(NodeBlock& bb, u64 dest, Node src);
/// Sets an internal flag. src value must be a bool-evaluated node
void SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value);
/// Sets a local memory address with a value.
/// Sets a local memory address. address and value must be a number-evaluated node
void SetLocalMemory(NodeBlock& bb, Node address, Node value);
/// Sets a shared memory address with a value.
void SetSharedMemory(NodeBlock& bb, Node address, Node value);
/// Sets a temporary. Internally it uses a post-RZ register
void SetTemporary(NodeBlock& bb, u32 id, Node value);
@@ -276,10 +272,10 @@ private:
bool is_shadow);
/// Accesses an image.
const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
/// Access a bindless image sampler.
const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
/// Extracts a sequence of bits from a node
Node BitfieldExtract(Node value, u32 offset, u32 bits);
@@ -360,7 +356,7 @@ private:
std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
std::map<u32, ConstBuffer> used_cbufs;
std::set<Sampler> used_samplers;
std::set<Image> used_images;
std::map<u64, Image> used_images;
std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
bool uses_layer{};

View File

@@ -195,18 +195,18 @@ public:
virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
void MarkAsModified(const bool is_modified_, const u64 tick) {
void MarkAsModified(bool is_modified_, u64 tick) {
is_modified = is_modified_ || is_target;
modification_tick = tick;
}
void MarkAsRenderTarget(const bool is_target, const u32 index) {
this->is_target = is_target;
this->index = index;
void MarkAsRenderTarget(bool is_target_, u32 index_) {
is_target = is_target_;
index = index_;
}
void MarkAsPicked(const bool is_picked) {
this->is_picked = is_picked;
void MarkAsPicked(bool is_picked_) {
is_picked = is_picked_;
}
bool IsModified() const {

View File

@@ -24,55 +24,62 @@ using VideoCore::Surface::SurfaceTarget;
using VideoCore::Surface::SurfaceTargetFromTextureType;
using VideoCore::Surface::SurfaceType;
SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
namespace {
SurfaceTarget TextureTypeToSurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
switch (type) {
case Tegra::Shader::TextureType::Texture1D: {
if (is_array)
return SurfaceTarget::Texture1DArray;
else
return SurfaceTarget::Texture1D;
}
case Tegra::Shader::TextureType::Texture2D: {
if (is_array)
return SurfaceTarget::Texture2DArray;
else
return SurfaceTarget::Texture2D;
}
case Tegra::Shader::TextureType::Texture3D: {
case Tegra::Shader::TextureType::Texture1D:
return is_array ? SurfaceTarget::Texture1DArray : SurfaceTarget::Texture1D;
case Tegra::Shader::TextureType::Texture2D:
return is_array ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D;
case Tegra::Shader::TextureType::Texture3D:
ASSERT(!is_array);
return SurfaceTarget::Texture3D;
}
case Tegra::Shader::TextureType::TextureCube: {
if (is_array)
return SurfaceTarget::TextureCubeArray;
else
return SurfaceTarget::TextureCubemap;
}
default: {
case Tegra::Shader::TextureType::TextureCube:
return is_array ? SurfaceTarget::TextureCubeArray : SurfaceTarget::TextureCubemap;
default:
UNREACHABLE();
return SurfaceTarget::Texture2D;
}
}
SurfaceTarget ImageTypeToSurfaceTarget(Tegra::Shader::ImageType type) {
switch (type) {
case Tegra::Shader::ImageType::Texture1D:
return SurfaceTarget::Texture1D;
case Tegra::Shader::ImageType::TextureBuffer:
return SurfaceTarget::TextureBuffer;
case Tegra::Shader::ImageType::Texture1DArray:
return SurfaceTarget::Texture1DArray;
case Tegra::Shader::ImageType::Texture2D:
return SurfaceTarget::Texture2D;
case Tegra::Shader::ImageType::Texture2DArray:
return SurfaceTarget::Texture2DArray;
case Tegra::Shader::ImageType::Texture3D:
return SurfaceTarget::Texture3D;
default:
UNREACHABLE();
return SurfaceTarget::Texture2D;
}
}
namespace {
constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
}
} // Anonymous namespace
SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
const Tegra::Texture::FullTextureInfo& config,
SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Sampler& entry) {
SurfaceParams params;
params.is_tiled = config.tic.IsTiled();
params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(),
params.srgb_conversion);
params.is_tiled = tic.IsTiled();
params.srgb_conversion = tic.IsSrgbConversionEnabled();
params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
params.pixel_format =
PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
params.type = GetFormatType(params.pixel_format);
if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) {
switch (params.pixel_format) {
@@ -92,31 +99,72 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
}
params.type = GetFormatType(params.pixel_format);
}
params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
params.type = GetFormatType(params.pixel_format);
// TODO: on 1DBuffer we should use the tic info.
if (!config.tic.IsBuffer()) {
params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray());
params.width = config.tic.Width();
params.height = config.tic.Height();
params.depth = config.tic.Depth();
params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
if (params.target == SurfaceTarget::TextureCubemap ||
params.target == SurfaceTarget::TextureCubeArray) {
params.depth *= 6;
}
params.num_levels = config.tic.max_mip_level + 1;
params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
params.is_layered = params.IsLayered();
} else {
if (tic.IsBuffer()) {
params.target = SurfaceTarget::TextureBuffer;
params.width = config.tic.Width();
params.width = tic.Width();
params.pitch = params.width * params.GetBytesPerPixel();
params.height = 1;
params.depth = 1;
params.num_levels = 1;
params.emulated_levels = 1;
params.is_layered = false;
} else {
params.target = TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray());
params.width = tic.Width();
params.height = tic.Height();
params.depth = tic.Depth();
params.pitch = params.is_tiled ? 0 : tic.Pitch();
if (params.target == SurfaceTarget::TextureCubemap ||
params.target == SurfaceTarget::TextureCubeArray) {
params.depth *= 6;
}
params.num_levels = tic.max_mip_level + 1;
params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
params.is_layered = params.IsLayered();
}
return params;
}
SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Image& entry) {
SurfaceParams params;
params.is_tiled = tic.IsTiled();
params.srgb_conversion = tic.IsSrgbConversionEnabled();
params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
params.pixel_format =
PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
params.type = GetFormatType(params.pixel_format);
params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
params.type = GetFormatType(params.pixel_format);
params.target = ImageTypeToSurfaceTarget(entry.GetType());
// TODO: on 1DBuffer we should use the tic info.
if (tic.IsBuffer()) {
params.target = SurfaceTarget::TextureBuffer;
params.width = tic.Width();
params.pitch = params.width * params.GetBytesPerPixel();
params.height = 1;
params.depth = 1;
params.num_levels = 1;
params.emulated_levels = 1;
params.is_layered = false;
} else {
params.width = tic.Width();
params.height = tic.Height();
params.depth = tic.Depth();
params.pitch = params.is_tiled ? 0 : tic.Pitch();
if (params.target == SurfaceTarget::TextureCubemap ||
params.target == SurfaceTarget::TextureCubeArray) {
params.depth *= 6;
}
params.num_levels = tic.max_mip_level + 1;
params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
params.is_layered = params.IsLayered();
}
return params;
}

View File

@@ -4,8 +4,6 @@
#pragma once
#include <map>
#include "common/alignment.h"
#include "common/bit_util.h"
#include "common/cityhash.h"
@@ -23,10 +21,13 @@ using VideoCore::Surface::SurfaceCompression;
class SurfaceParams {
public:
/// Creates SurfaceCachedParams from a texture configuration.
static SurfaceParams CreateForTexture(Core::System& system,
const Tegra::Texture::FullTextureInfo& config,
static SurfaceParams CreateForTexture(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Sampler& entry);
/// Creates SurfaceCachedParams from an image configuration.
static SurfaceParams CreateForImage(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Image& entry);
/// Creates SurfaceCachedParams for a depth buffer configuration.
static SurfaceParams CreateForDepthBuffer(
Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,

View File

@@ -10,7 +10,7 @@
namespace VideoCommon {
std::size_t ViewParams::Hash() const {
return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^
return static_cast<std::size_t>(base_layer) ^ (static_cast<std::size_t>(num_layers) << 16) ^
(static_cast<std::size_t>(base_level) << 24) ^
(static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36);
}

View File

@@ -13,8 +13,8 @@
namespace VideoCommon {
struct ViewParams {
ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer, u32 num_layers,
u32 base_level, u32 num_levels)
constexpr explicit ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer,
u32 num_layers, u32 base_level, u32 num_levels)
: target{target}, base_layer{base_layer}, num_layers{num_layers}, base_level{base_level},
num_levels{num_levels} {}
@@ -22,12 +22,6 @@ struct ViewParams {
bool operator==(const ViewParams& rhs) const;
VideoCore::Surface::SurfaceTarget target{};
u32 base_layer{};
u32 num_layers{};
u32 base_level{};
u32 num_levels{};
bool IsLayered() const {
switch (target) {
case VideoCore::Surface::SurfaceTarget::Texture1DArray:
@@ -39,13 +33,19 @@ struct ViewParams {
return false;
}
}
VideoCore::Surface::SurfaceTarget target{};
u32 base_layer{};
u32 num_layers{};
u32 base_level{};
u32 num_levels{};
};
class ViewBase {
public:
ViewBase(const ViewParams& params) : params{params} {}
constexpr explicit ViewBase(const ViewParams& params) : params{params} {}
const ViewParams& GetViewParams() const {
constexpr const ViewParams& GetViewParams() const {
return params;
}

View File

@@ -89,14 +89,29 @@ public:
}
}
TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Sampler& entry) {
std::lock_guard lock{mutex};
const auto gpu_addr{config.tic.Address()};
const auto gpu_addr{tic.Address()};
if (!gpu_addr) {
return {};
}
const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
const auto params{SurfaceParams::CreateForTexture(tic, entry)};
const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
if (guard_samplers) {
sampled_textures.push_back(surface);
}
return view;
}
TView GetImageSurface(const Tegra::Texture::TICEntry& tic,
const VideoCommon::Shader::Image& entry) {
std::lock_guard lock{mutex};
const auto gpu_addr{tic.Address()};
if (!gpu_addr) {
return {};
}
const auto params{SurfaceParams::CreateForImage(tic, entry)};
const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
if (guard_samplers) {
sampled_textures.push_back(surface);