skyline/app/src/main/cpp/skyline/gpu/texture.h

270 lines
12 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <common.h>
#include <vulkan/vulkan.hpp>
namespace skyline {
namespace service::hosbinder {
class IHOSBinderDriver;
}
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
constexpr Dimensions() : width(0), height(0), depth(0) {}
constexpr Dimensions(u32 width, u32 height) : width(width), height(height), depth(1) {}
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) {
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) {
return (width != dimensions.width) || (height != dimensions.height) || (depth != dimensions.depth);
}
};
/**
* @brief This is used to hold the attributes of a texture format
*/
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
/**
* @return If this is a compressed texture format or not
*/
inline constexpr bool IsCompressed() {
return (blockHeight != 1) || (blockWidth != 1);
}
/**
* @param width The width of the texture in pixels
* @param height The height of the texture in pixels
* @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) {
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) {
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) {
return vkFormat == format.vkFormat;
}
/**
* @return If the specified format is not equal to this one
*/
inline constexpr bool operator!=(const Format &format) {
return vkFormat != format.vkFormat;
}
/**
* @return If this format is actually valid or not
*/
inline constexpr operator bool() {
return bpb;
}
};
namespace format {
constexpr Format RGBA8888Unorm{sizeof(u8) * 4, 1, 1, vk::Format::eR8G8B8A8Unorm}; //!< 8-bits per channel 4-channel pixels
constexpr Format RGB565Unorm{sizeof(u8) * 2, 1, 1, vk::Format::eR5G6B5UnormPack16}; //!< Red channel: 5-bit, Green channel: 6-bit, Blue channel: 5-bit
}
/**
* @brief This describes 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
Pitch, //!< This is a pitch-linear texture
Block, //!< This is a 16Bx2 block-linear texture
};
/**
* @brief This holds the parameters of the tiling mode, covered in Table 76 in the Tegra X1 TRM
*/
union TileConfig {
struct {
u8 blockHeight; //!< The height of the blocks in GOBs
u8 blockDepth; //!< The depth of the blocks in GOBs
u16 surfaceWidth; //!< The width of a surface in samples
};
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
Red, //!< Red color channel
Green, //!< Green color channel
Blue, //!< Blue color channel
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
SwizzleChannel blue{SwizzleChannel::Blue}; //!< Swizzle for the blue channel
SwizzleChannel alpha{SwizzleChannel::Alpha}; //!< Swizzle for the alpha channel
};
}
class Texture;
class PresentationTexture;
/**
* @brief This class is used to hold metadata about a guest texture and can be used to create a host Texture object
*/
class GuestTexture : public std::enable_shared_from_this<GuestTexture> {
private:
const DeviceState &state; //!< The state of the device
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
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() {
return format.GetSize(dimensions);
}
/**
* @brief This 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;
}
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;
}
friend service::hosbinder::IHOSBinderDriver;
};
/**
* @brief This class is used to store a texture which is backed by host objects
*/
class Texture {
private:
const DeviceState &state; //!< The state of the device
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
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
* @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
*/
void SetDimensions(texture::Dimensions dimensions);
/**
* @brief This sets the format to the specified one
* @param format The format to change the texture to
*/
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
*/
void SetSwizzle(texture::Swizzle swizzle);
/**
* @brief This 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
*/
void SynchronizeGuest();
};
/**
* @brief This class is used to hold a texture object alongside a release callback used for display presentation
*/
class PresentationTexture : public Texture {
public:
std::function<void()> releaseCallback; //!< The release callback after this texture has been displayed
PresentationTexture(const DeviceState &state, const std::shared_ptr<GuestTexture> &guest, const texture::Dimensions &dimensions, const texture::Format &format, const std::function<void()> &releaseCallback = {});
/**
* @return The corresponding Android surface format for the current texture format
*/
i32 GetAndroidFormat();
};
}
}