Refactor Comments + Other Minor Fixes

This commit is contained in:
◱ PixelyIon
2020-09-28 15:35:17 +05:30
committed by ◱ PixelyIon
parent 429af1990a
commit 4070686897
167 changed files with 1376 additions and 1433 deletions

View File

@ -8,9 +8,6 @@
#define U32_OFFSET(regs, field) (offsetof(regs, field) / sizeof(u32))
namespace skyline::gpu {
/**
* @brief This enumerates the identifiers used to label a specific engine
*/
enum class EngineID {
Fermi2D = 0x902D,
KeplerMemory = 0xA140,
@ -20,7 +17,7 @@ namespace skyline::gpu {
};
/**
* @brief This holds the parameters of a GPU engine method call
* @brief The parameters of a GPU engine method call
*/
struct MethodParams {
u16 method;
@ -31,8 +28,8 @@ namespace skyline::gpu {
namespace engine {
/**
* @brief The Engine class provides an interface that can be used to communicate with the GPU's internal engines
*/
* @brief The Engine class provides an interface that can be used to communicate with the GPU's internal engines
*/
class Engine {
protected:
const DeviceState &state;
@ -43,8 +40,8 @@ namespace skyline::gpu {
virtual ~Engine() = default;
/**
* @brief Calls an engine method with the given parameters
*/
* @brief Calls an engine method with the given parameters
*/
virtual void CallMethod(MethodParams params) {
state.logger->Warn("Called method in unimplemented engine: 0x{:X} args: 0x{:X}", params.method, params.argument);
};

View File

@ -18,9 +18,8 @@ namespace skyline {
class GPFIFO : public Engine {
private:
/**
* @brief This holds the GPFIFO engine's registers
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L65
*/
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L65
*/
#pragma pack(push, 1)
union Registers {
std::array<u32, constant::GpfifoRegisterCount> raw;
@ -30,22 +29,22 @@ namespace skyline {
Release = 2,
AcqGeq = 4,
AcqAnd = 8,
Reduction = 16
Reduction = 16,
};
enum class SemaphoreAcquireSwitch : u8 {
Disabled = 0,
Enabled = 1
Enabled = 1,
};
enum class SemaphoreReleaseWfi : u8 {
En = 0,
Dis = 1
Dis = 1,
};
enum class SemaphoreReleaseSize : u8 {
SixteenBytes = 0,
FourBytes = 1
FourBytes = 1,
};
enum class SemaphoreReduction : u8 {
@ -56,39 +55,39 @@ namespace skyline {
Or = 4,
Add = 5,
Inc = 6,
Dec = 7
Dec = 7,
};
enum class SemaphoreFormat : u8 {
Signed = 0,
Unsigned = 1
Unsigned = 1,
};
enum class MemOpTlbInvalidatePdb : u8 {
One = 0,
All = 1
All = 1,
};
enum class SyncpointOperation : u8 {
Wait = 0,
Incr = 1
Incr = 1,
};
enum class SyncpointWaitSwitch : u8 {
Dis = 0,
En = 1
En = 1,
};
enum class WfiScope : u8 {
CurrentScgType = 0,
All = 1
All = 1,
};
enum class YieldOp : u8 {
Nop = 0,
PbdmaTimeslice = 1,
RunlistTimeslice = 2,
Tsg = 3
Tsg = 3,
};
struct {

View File

@ -16,16 +16,16 @@ namespace skyline {
namespace gpu::engine {
/**
* @brief The Maxwell 3D engine handles processing 3D graphics
*/
* @brief The Maxwell 3D engine handles processing 3D graphics
*/
class Maxwell3D : public Engine {
private:
std::array<size_t, 0x80> macroPositions{}; //!< This holds the positions of each individual macro in macro memory, there can be a maximum of 0x80 macros at any one time
std::array<size_t, 0x80> macroPositions{}; //!< The positions of each individual macro in macro memory, there can be a maximum of 0x80 macros at any one time
struct {
u32 index;
std::vector<u32> arguments;
} macroInvocation{}; //!< This hold the index and arguments of the macro that is pending execution
} macroInvocation{}; //!< Data for a macro that is pending execution
MacroInterpreter macroInterpreter;
@ -35,9 +35,8 @@ namespace skyline {
public:
/**
* @brief This holds the Maxwell3D engine's register space
* @url https://github.com/devkitPro/deko3d/blob/master/source/maxwell/engine_3d.def#L478
*/
* @url https://github.com/devkitPro/deko3d/blob/master/source/maxwell/engine_3d.def#L478
*/
#pragma pack(push, 1)
union Registers {
std::array<u32, constant::Maxwell3DRegisterCounter> raw;
@ -56,7 +55,7 @@ namespace skyline {
MethodTrack = 0,
MethodTrackWithFilter = 1,
MethodPassthrough = 2,
MethodReplay = 3
MethodReplay = 3,
};
struct ViewportTransform {
@ -196,7 +195,7 @@ namespace skyline {
SubtractGL = 0x8007,
ReverseSubtractGL = 0x8008,
MinimumGL = 0x800A,
MaximumGL = 0x800B
MaximumGL = 0x800B,
};
enum class Factor : u32 {
@ -293,7 +292,7 @@ namespace skyline {
Release = 0,
Acquire = 1,
Counter = 2,
Trap = 3
Trap = 3,
};
enum class ReductionOp : u8 {
@ -348,7 +347,7 @@ namespace skyline {
TransformFeedbackOffset = 0x1A,
TessControlShaderInvocations = 0x1B,
TessEvaluationShaderInvocations = 0x1D,
TessEvaluationShaderPrimitives = 0x1F
TessEvaluationShaderPrimitives = 0x1F,
};
enum class StructureSize : u8 {
@ -375,7 +374,7 @@ namespace skyline {
enum class CoordOrigin : u8 {
LowerLeft = 0,
UpperLeft = 1
UpperLeft = 1,
};
struct {
@ -559,10 +558,10 @@ namespace skyline {
static_assert(sizeof(Registers) == (constant::Maxwell3DRegisterCounter * sizeof(u32)));
#pragma pack(pop)
Registers registers{}; //!< The Maxwell 3D register space
Registers registers{};
Registers shadowRegisters{}; //!< The shadow registers, their function is controlled by the 'shadowRamControl' register
std::array<u32, 0x10000> macroCode{}; //!< This is used to store GPU macros, the 256kb size is from Ryujinx
std::array<u32, 0x10000> macroCode{}; //!< This stores GPU macros, the 256kb size is from Ryujinx
Maxwell3D(const DeviceState &state);

View File

@ -4,14 +4,13 @@
#pragma once
#include <queue>
#include "engines/engine.h"
#include "engines/gpfifo.h"
#include "memory_manager.h"
namespace skyline::gpu {
namespace gpfifo {
/**
* @brief This contains a single GPFIFO entry that is submitted through 'SubmitGpfifo'
* @brief A GPFIFO entry as submitted through 'SubmitGpfifo'
* @url https://nvidia.github.io/open-gpu-doc/manuals/volta/gv100/dev_pbdma.ref.txt
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L155
*/
@ -72,7 +71,7 @@ namespace skyline::gpu {
static_assert(sizeof(GpEntry) == sizeof(u64));
/**
* @brief This holds a single pushbuffer method header that describes a compressed method sequence
* @brief A single pushbuffer method header that describes a compressed method sequence
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/manuals/volta/gv100/dev_ram.ref.txt#L850
* @url https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/clb06f.h#L179
*/
@ -84,7 +83,7 @@ namespace skyline::gpu {
Grp0SetSubDevMask = 1,
Grp0StoreSubDevMask = 2,
Grp0UseSubDevMask = 3,
Grp2NonIncMethod = 0
Grp2NonIncMethod = 0,
};
enum class SecOp : u8 {
@ -95,7 +94,7 @@ namespace skyline::gpu {
ImmdDataMethod = 4,
OneInc = 5,
Reserved6 = 6,
EndPbSegment = 7
EndPbSegment = 7,
};
u16 methodAddress : 12;
@ -128,7 +127,7 @@ namespace skyline::gpu {
class GPFIFO {
private:
/**
* @brief This is used to hold a pushbuffer's GPFIFO entry and contents, pushbuffers are made up of several 32-bit words
* @brief A pushbuffer is a descriptor of tasks that need to be executed for a specific client
*/
struct PushBuffer {
GpEntry gpEntry;
@ -149,7 +148,7 @@ namespace skyline::gpu {
engine::GPFIFO gpfifoEngine; //!< The engine for processing GPFIFO method calls
std::array<std::shared_ptr<engine::Engine>, 8> subchannels;
std::queue<PushBuffer> pushBufferQueue;
skyline::Mutex pushBufferQueueLock; //!< This is used to lock pushbuffer queue insertions as the GPU runs on a seperate thread
skyline::Mutex pushBufferQueueLock; //!< Synchronizes pushbuffer queue insertions as the GPU is multi-threaded
/**
* @brief Processes a pushbuffer segment, calling methods as needed
@ -157,7 +156,7 @@ namespace skyline::gpu {
void Process(const std::vector<u32> &segment);
/**
* @brief This sends a method call to the GPU hardware
* @brief Sends a method call to the GPU hardware
*/
void Send(MethodParams params);

View File

@ -15,9 +15,6 @@ namespace skyline::gpu {
*/
class MacroInterpreter {
private:
/**
* @brief This holds a single macro opcode
*/
#pragma pack(push, 1)
union Opcode {
u32 raw;
@ -98,11 +95,10 @@ namespace skyline::gpu {
static_assert(sizeof(Opcode) == sizeof(u32));
/**
* @brief This holds information about the Maxwell 3D method to be called in 'Send'
* @brief Metadata about the Maxwell 3D method to be called in 'Send'
*/
union MethodAddress {
u32 raw;
struct {
u16 address : 12;
u8 increment : 6;

View File

@ -11,23 +11,23 @@ namespace skyline::gpu::vmm {
// Create the initial chunk that will be split to create new chunks
ChunkDescriptor baseChunk(GpuAddressSpaceBase, GpuAddressSpaceSize, 0, ChunkState::Unmapped);
chunkList.push_back(baseChunk);
chunks.push_back(baseChunk);
}
std::optional<ChunkDescriptor> MemoryManager::FindChunk(u64 size, ChunkState state) {
auto chunk{std::find_if(chunkList.begin(), chunkList.end(), [size, state](const ChunkDescriptor &chunk) -> bool {
auto chunk{std::find_if(chunks.begin(), chunks.end(), [size, state](const ChunkDescriptor &chunk) -> bool {
return chunk.size > size && chunk.state == state;
})};
if (chunk != chunkList.end())
if (chunk != chunks.end())
return *chunk;
return std::nullopt;
}
u64 MemoryManager::InsertChunk(const ChunkDescriptor &newChunk) {
auto chunkEnd{chunkList.end()};
for (auto chunk{chunkList.begin()}; chunk != chunkEnd; chunk++) {
auto chunkEnd{chunks.end()};
for (auto chunk{chunks.begin()}; chunk != chunkEnd; chunk++) {
if (chunk->CanContain(newChunk)) {
auto oldChunk{*chunk};
u64 newSize{newChunk.address - chunk->address};
@ -38,11 +38,11 @@ namespace skyline::gpu::vmm {
} else {
chunk->size = newSize;
chunk = chunkList.insert(std::next(chunk), newChunk);
chunk = chunks.insert(std::next(chunk), newChunk);
}
if (extension)
chunkList.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, (oldChunk.state == ChunkState::Mapped) ? (oldChunk.cpuAddress + newSize + newChunk.size) : 0, oldChunk.state));
chunks.insert(std::next(chunk), ChunkDescriptor(newChunk.address + newChunk.size, extension, (oldChunk.state == ChunkState::Mapped) ? (oldChunk.cpuAddress + newSize + newChunk.size) : 0, oldChunk.state));
return newChunk.address;
} else if (chunk->address + chunk->size > newChunk.address) {
@ -54,8 +54,8 @@ namespace skyline::gpu::vmm {
if (tailChunk->address + tailChunk->size >= newChunk.address + newChunk.size)
break;
tailChunk = chunkList.erase(tailChunk);
chunkEnd = chunkList.end();
tailChunk = chunks.erase(tailChunk);
chunkEnd = chunks.end();
}
// The given chunk is too large to fit into existing chunks
@ -74,7 +74,7 @@ namespace skyline::gpu::vmm {
if (headChunk->size == 0)
*headChunk = newChunk;
else
chunkList.insert(std::next(headChunk), newChunk);
chunks.insert(std::next(headChunk), newChunk);
return newChunk.address;
}
@ -132,11 +132,11 @@ namespace skyline::gpu::vmm {
if (!util::IsAligned(address, constant::GpuPageSize))
return false;
auto chunk{std::find_if(chunkList.begin(), chunkList.end(), [address](const ChunkDescriptor &chunk) -> bool {
auto chunk{std::find_if(chunks.begin(), chunks.end(), [address](const ChunkDescriptor &chunk) -> bool {
return chunk.address == address;
})};
if (chunk == chunkList.end())
if (chunk == chunks.end())
return false;
chunk->state = ChunkState::Reserved;
@ -146,11 +146,11 @@ namespace skyline::gpu::vmm {
}
void MemoryManager::Read(u8 *destination, u64 address, u64 size) const {
auto chunk{std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
auto chunk{std::upper_bound(chunks.begin(), chunks.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
return address < chunk.address;
})};
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
if (chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
chunk--;
@ -166,7 +166,7 @@ namespace skyline::gpu::vmm {
size -= readSize;
if (size) {
if (++chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to read region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
readAddress = chunk->cpuAddress;
@ -176,11 +176,11 @@ namespace skyline::gpu::vmm {
}
void MemoryManager::Write(u8 *source, u64 address, u64 size) const {
auto chunk{std::upper_bound(chunkList.begin(), chunkList.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
auto chunk{std::upper_bound(chunks.begin(), chunks.end(), address, [](const u64 address, const ChunkDescriptor &chunk) -> bool {
return address < chunk.address;
})};
if (chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
if (chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
chunk--;
@ -196,7 +196,7 @@ namespace skyline::gpu::vmm {
size -= writeSize;
if (size) {
if (++chunk == chunkList.end() || chunk->state != ChunkState::Mapped)
if (++chunk == chunks.end() || chunk->state != ChunkState::Mapped)
throw exception("Failed to write region in GPU address space: Address: 0x{:X}, Size: 0x{:X}", address, size);
writeAddress = chunk->cpuAddress;

View File

@ -11,44 +11,38 @@ namespace skyline {
}
namespace gpu::vmm {
/**
* @brief This enumerates the possible states of a memory chunk
*/
enum ChunkState {
Unmapped, //!< The chunk is unmapped
Reserved, //!< The chunk is reserved
Mapped //!< The chunk is mapped and a CPU side address is present
};
/**
* @brief This describes a chunk of memory and all of it's individual attributes
*/
struct ChunkDescriptor {
u64 address; //!< The address of the chunk in the GPU address space
u64 size; //!< The size of the chunk in bytes
u64 cpuAddress; //!< The address of the chunk in the CPU address space (if mapped)
ChunkState state; //!< The state of the chunk
ChunkState state;
ChunkDescriptor(u64 address, u64 size, u64 cpuAddress, ChunkState state) : address(address), size(size), cpuAddress(cpuAddress), state(state) {}
/**
* @param chunk The chunk to check
* @return If the given chunk can be contained wholly within this chunk
*/
* @return If the given chunk can be contained wholly within this chunk
*/
inline bool CanContain(const ChunkDescriptor &chunk) {
return (chunk.address >= this->address) && ((this->size + this->address) >= (chunk.size + chunk.address));
}
};
/**
* @brief The MemoryManager class handles the mapping of the GPU address space
*/
* @brief The MemoryManager class handles the mapping of the GPU address space
*/
class MemoryManager {
private:
const DeviceState &state;
std::vector<ChunkDescriptor> chunks;
/**
* @brief This finds a chunk of the specified type in the GPU address space that is larger than the given size
* @brief Finds a chunk of the specified type in the GPU address space that is larger than the given size
* @param size The minimum size of the chunk to find
* @param state The state desired state of the chunk to find
* @return The first unmapped chunk in the GPU address space that fits the requested size
@ -56,7 +50,7 @@ namespace skyline {
std::optional<ChunkDescriptor> FindChunk(u64 size, ChunkState state);
/**
* @brief This inserts a chunk into the chunk list, resizing and splitting as necessary
* @brief Inserts a chunk into the chunk list, resizing and splitting as necessary
* @param newChunk The chunk to insert
* @return The base virtual GPU address of the inserted chunk
*/
@ -64,17 +58,16 @@ namespace skyline {
public:
MemoryManager(const DeviceState &state);
std::vector<ChunkDescriptor> chunkList; //!< This vector holds all the chunk descriptors
/**
* @brief This reserves a region of the GPU address space so it will not be chosen automatically when mapping
* @brief Reserves a region of the GPU address space so it will not be chosen automatically when mapping
* @param size The size of the region to reserve
* @return The virtual GPU base address of the region base
*/
u64 ReserveSpace(u64 size);
/**
* @brief This reserves a fixed region of the GPU address space so it will not be chosen automatically when mapping
* @brief Reserves a fixed region of the GPU address space so it will not be chosen automatically when mapping
* @param address The virtual base address of the region to allocate
* @param size The size of the region to allocate
* @return The virtual address of the region base
@ -82,7 +75,7 @@ namespace skyline {
u64 ReserveFixed(u64 address, u64 size);
/**
* @brief This maps a physical CPU memory region to an automatically chosen virtual memory region
* @brief Maps a physical CPU memory region to an automatically chosen virtual memory region
* @param address The physical CPU address of the region to be mapped into the GPU's address space
* @param size The size of the region to map
* @return The virtual address of the region base
@ -90,7 +83,7 @@ namespace skyline {
u64 MapAllocate(u64 address, u64 size);
/**
* @brief This maps a physical CPU memory region to a fixed virtual memory region
* @brief Maps a physical CPU memory region to a fixed virtual memory region
* @param address The target virtual address of the region
* @param cpuAddress The physical CPU address of the region to be mapped into the GPU's address space
* @param size The size of the region to map
@ -99,7 +92,7 @@ namespace skyline {
u64 MapFixed(u64 address, u64 cpuAddress, u64 size);
/**
* @brief This unmaps the chunk that starts at 'offset' from the GPU address space
* @brief Unmaps the chunk that starts at 'offset' from the GPU address space
* @return Whether the operation succeeded
*/
bool Unmap(u64 address);
@ -108,7 +101,6 @@ namespace skyline {
/**
* @brief Reads in a span from a region of the GPU virtual address space
* @tparam T The type of span to read into
*/
template<typename T>
void Read(span<T> destination, u64 address) const {
@ -138,7 +130,6 @@ namespace skyline {
/**
* @brief Reads in an object from a region of the GPU virtual address space
* @tparam T The type of object to return
*/
template<typename T>
void Write(T source, u64 address) const {

View File

@ -16,15 +16,12 @@ namespace skyline {
*/
class Syncpoint {
private:
/**
* @brief This holds information about a single waiter on a syncpoint
*/
struct Waiter {
u32 threshold;
std::function<void()> callback;
u32 threshold; //!< The syncpoint value to wait on to be reached
std::function<void()> callback; //!< The callback to do after the wait has ended
};
Mutex waiterLock; //!< Locks insertions and deletions of waiters
Mutex waiterLock; //!< Synchronizes insertions and deletions of waiters
std::map<u64, Waiter> waiterMap;
u64 nextWaiterId{1};

View File

@ -9,6 +9,22 @@
namespace skyline::gpu {
GuestTexture::GuestTexture(const DeviceState &state, u64 address, texture::Dimensions dimensions, texture::Format format, texture::TileMode tiling, texture::TileConfig layout) : state(state), address(address), dimensions(dimensions), format(format), tileMode(tiling), tileConfig(layout) {}
std::shared_ptr<Texture> GuestTexture::InitializeTexture(std::optional<texture::Format> format, std::optional<texture::Dimensions> dimensions, texture::Swizzle swizzle) {
if (!host.expired())
throw exception("Trying to create multiple Texture objects from a single GuestTexture");
auto sharedHost{std::make_shared<Texture>(state, shared_from_this(), dimensions ? *dimensions : this->dimensions, format ? *format : this->format, swizzle)};
host = sharedHost;
return sharedHost;
}
std::shared_ptr<PresentationTexture> GuestTexture::InitializePresentationTexture() {
if (!host.expired())
throw exception("Trying to create multiple PresentationTexture objects from a single GuestTexture");
auto presentation{std::make_shared<PresentationTexture>(state, shared_from_this(), dimensions, format)};
host = std::static_pointer_cast<Texture>(presentation);
return presentation;
}
Texture::Texture(const DeviceState &state, std::shared_ptr<GuestTexture> guest, texture::Dimensions dimensions, texture::Format format, texture::Swizzle swizzle) : state(state), guest(guest), dimensions(dimensions), format(format), swizzle(swizzle) {
SynchronizeHost();
}

View File

@ -12,13 +12,10 @@ namespace skyline {
}
namespace gpu {
namespace texture {
/*
* @brief This is used to hold the dimensions of a surface
*/
struct Dimensions {
u32 width; //!< The width of the surface
u32 height; //!< The height of the surface
u32 depth; //!< The depth of the surface
u32 width;
u32 height;
u32 depth;
constexpr Dimensions() : width(0), height(0), depth(0) {}
@ -26,34 +23,25 @@ namespace skyline {
constexpr Dimensions(u32 width, u32 height, u32 depth) : width(width), height(height), depth(depth) {}
/**
* @return If the specified dimension is equal to this one
*/
constexpr inline bool operator==(const Dimensions &dimensions) {
constexpr bool operator==(const Dimensions &dimensions) {
return (width == dimensions.width) && (height == dimensions.height) && (depth == dimensions.depth);
}
/**
* @return If the specified dimension is not equal to this one
*/
constexpr inline bool operator!=(const Dimensions &dimensions) {
constexpr bool operator!=(const Dimensions &dimensions) {
return (width != dimensions.width) || (height != dimensions.height) || (depth != dimensions.depth);
}
};
/**
* @brief This is used to hold the attributes of a texture format
* @note Blocks refers to the atomic unit of a compressed format (IE: The minimum amount of data that can be decompressed)
*/
struct Format {
u8 bpb; //!< Bytes Per Block, this is to accommodate compressed formats
u16 blockHeight; //!< The height of a single block
u16 blockWidth; //!< The width of a single block
vk::Format vkFormat; //!< The underlying Vulkan type of the format
u8 bpb; //!< Bytes Per Block, this is used instead of bytes per pixel as that might not be a whole number for compressed formats
u16 blockHeight; //!< The height of a block in pixels
u16 blockWidth; //!< The width of a block in pixels
vk::Format vkFormat;
/**
* @return If this is a compressed texture format or not
*/
inline constexpr bool IsCompressed() {
constexpr bool IsCompressed() {
return (blockHeight != 1) || (blockWidth != 1);
}
@ -63,42 +51,32 @@ namespace skyline {
* @param depth The depth of the texture in layers
* @return The size of the texture in bytes
*/
inline constexpr size_t GetSize(u32 width, u32 height, u32 depth = 1) {
constexpr size_t GetSize(u32 width, u32 height, u32 depth = 1) {
return (((width / blockWidth) * (height / blockHeight)) * bpb) * depth;
}
/**
* @param dimensions The dimensions of a texture
* @return The size of the texture in bytes
*/
inline constexpr size_t GetSize(Dimensions dimensions) {
constexpr size_t GetSize(Dimensions dimensions) {
return GetSize(dimensions.width, dimensions.height, dimensions.depth);
}
/**
* @return If the specified format is equal to this one
*/
inline constexpr bool operator==(const Format &format) {
constexpr bool operator==(const Format &format) {
return vkFormat == format.vkFormat;
}
/**
* @return If the specified format is not equal to this one
*/
inline constexpr bool operator!=(const Format &format) {
constexpr bool operator!=(const Format &format) {
return vkFormat != format.vkFormat;
}
/**
* @return If this format is actually valid or not
*/
inline constexpr operator bool() {
constexpr operator bool() {
return bpb;
}
};
/**
* @brief This describes the linearity of a texture. Refer to Chapter 20.1 of the Tegra X1 TRM for information.
* @brief The linearity of a texture, refer to Chapter 20.1 of the Tegra X1 TRM for information
*/
enum class TileMode {
Linear, //!< This is a purely linear texture
@ -107,7 +85,7 @@ namespace skyline {
};
/**
* @brief This holds the parameters of the tiling mode, covered in Table 76 in the Tegra X1 TRM
* @brief The parameters of the tiling mode, covered in Table 76 in the Tegra X1 TRM
*/
union TileConfig {
struct {
@ -118,9 +96,6 @@ namespace skyline {
u32 pitch; //!< The pitch of the texture if it's pitch linear
};
/**
* @brief This enumerates all of the channel swizzle options
*/
enum class SwizzleChannel {
Zero, //!< Write 0 to the channel
One, //!< Write 1 to the channel
@ -130,9 +105,6 @@ namespace skyline {
Alpha, //!< Alpha channel
};
/**
* @brief This holds all of the texture swizzles on each color channel
*/
struct Swizzle {
SwizzleChannel red{SwizzleChannel::Red}; //!< Swizzle for the red channel
SwizzleChannel green{SwizzleChannel::Green}; //!< Swizzle for the green channel
@ -145,109 +117,95 @@ namespace skyline {
class PresentationTexture;
/**
* @brief This class is used to hold metadata about a guest texture and can be used to create a host Texture object
* @brief A texture present in guest memory, it can be used to create a corresponding Texture object for usage on the host
*/
class GuestTexture : public std::enable_shared_from_this<GuestTexture> {
private:
const DeviceState &state; //!< The state of the device
const DeviceState &state;
public:
u64 address; //!< The address of the texture in guest memory
std::shared_ptr<Texture> host; //!< The corresponding host texture object
texture::Dimensions dimensions; //!< The dimensions of the texture
texture::Format format; //!< The format of the texture
texture::TileMode tileMode; //!< The tiling mode of the texture
texture::TileConfig tileConfig; //!< The tiling configuration of the texture
std::weak_ptr<Texture> host; //!< A host texture (if any) that was created from this guest texture
texture::Dimensions dimensions;
texture::Format format;
texture::TileMode tileMode;
texture::TileConfig tileConfig;
GuestTexture(const DeviceState &state, u64 address, texture::Dimensions dimensions, texture::Format format, texture::TileMode tileMode = texture::TileMode::Linear, texture::TileConfig tileConfig = {});
inline constexpr size_t Size() {
constexpr size_t Size() {
return format.GetSize(dimensions);
}
/**
* @brief This creates a corresponding host texture object for this guest texture
* @brief Creates a corresponding host texture object for this guest texture
* @param format The format of the host texture (Defaults to the format of the guest texture)
* @param dimensions The dimensions of the host texture (Defaults to the dimensions of the host texture)
* @param swizzle The channel swizzle of the host texture (Defaults to no channel swizzling)
* @return A shared pointer to the host texture object
* @note There can only be one host texture for a corresponding guest texture
*/
std::shared_ptr<Texture> InitializeTexture(std::optional<texture::Format> format = std::nullopt, std::optional<texture::Dimensions> dimensions = std::nullopt, texture::Swizzle swizzle = {}) {
if (host)
throw exception("Trying to create multiple Texture objects from a single GuestTexture");
host = std::make_shared<Texture>(state, shared_from_this(), dimensions ? *dimensions : this->dimensions, format ? *format : this->format, swizzle);
return host;
}
std::shared_ptr<Texture> InitializeTexture(std::optional<texture::Format> format = std::nullopt, std::optional<texture::Dimensions> dimensions = std::nullopt, texture::Swizzle swizzle = {});
protected:
std::shared_ptr<PresentationTexture> InitializePresentationTexture() {
if (host)
throw exception("Trying to create multiple PresentationTexture objects from a single GuestTexture");
auto presentation{std::make_shared<PresentationTexture>(state, shared_from_this(), dimensions, format)};
host = std::static_pointer_cast<Texture>(presentation);
return presentation;
}
std::shared_ptr<PresentationTexture> InitializePresentationTexture();
friend service::hosbinder::GraphicBufferProducer;
};
/**
* @brief This class is used to store a texture which is backed by host objects
* @brief A texture which is backed by host constructs while being synchronized with the underlying guest texture
*/
class Texture {
private:
const DeviceState &state; //!< The state of the device
const DeviceState &state;
public:
std::vector<u8> backing; //!< The object that holds a host copy of the guest texture (Will be replaced with a vk::Image)
std::shared_ptr<GuestTexture> guest; //!< The corresponding guest texture object
texture::Dimensions dimensions; //!< The dimensions of the texture
texture::Format format; //!< The format of the host texture
texture::Swizzle swizzle; //!< The swizzle of the host texture
std::shared_ptr<GuestTexture> guest; //!< The guest texture from which this was created, it is required for syncing
texture::Dimensions dimensions;
texture::Format format;
texture::Swizzle swizzle;
public:
Texture(const DeviceState &state, std::shared_ptr<GuestTexture> guest, texture::Dimensions dimensions, texture::Format format, texture::Swizzle swizzle);
public:
/**
* @brief This convert this texture to the specified tiling mode
* @brief Convert this texture to the specified tiling mode
* @param tileMode The tiling mode to convert it to
* @param tileConfig The configuration for the tiling mode (Can be default argument for Linear)
*/
void ConvertTileMode(texture::TileMode tileMode, texture::TileConfig tileConfig = {});
/**
* @brief This sets the texture dimensions to the specified ones (As long as they are within the GuestTexture's range)
* @param dimensions The dimensions to adjust the texture to
* @brief Converts the texture dimensions to the specified ones (As long as they are within the GuestTexture's range)
*/
void SetDimensions(texture::Dimensions dimensions);
/**
* @brief This sets the format to the specified one
* @param format The format to change the texture to
* @brief Converts the texture to have the specified format
*/
void SetFormat(texture::Format format);
/**
* @brief This sets the channel swizzle to the specified one
* @param swizzle The channel swizzle to the change the texture to
* @brief Change the texture channel swizzle to the specified one
*/
void SetSwizzle(texture::Swizzle swizzle);
/**
* @brief This synchronizes the host texture with the guest after it has been modified
* @brief Synchronizes the host texture with the guest after it has been modified
*/
void SynchronizeHost();
/**
* @brief This synchronizes the guest texture with the host texture after it has been modified
* @brief Synchronizes the guest texture with the host texture after it has been modified
*/
void SynchronizeGuest();
};
/**
* @brief This class is used to hold a texture object alongside a release callback used for display presentation
* @brief A texture object alongside a release callback used for display presentation
*/
class PresentationTexture : public Texture {
public: