mirror of
https://github.com/Takiiiiiiii/strato.git
synced 2025-07-17 08:46:39 +00:00
We earlier moved to LGPLv3.0 or Later. This was a mistake as what we wanted was being able to link to proprietary libraries but LGPL is the opposite and it allows linking proprietary libraries to libskyline instead. After further consideration, we've moved to MPL-2.0, it allows linking to proprietary libraries and is a standardized license as compared to adding an exception to GPL.
85 lines
5.5 KiB
C++
85 lines
5.5 KiB
C++
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
|
|
#include <android/native_window.h>
|
|
#include <kernel/types/KProcess.h>
|
|
#include "texture.h"
|
|
|
|
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) {}
|
|
|
|
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();
|
|
}
|
|
|
|
void Texture::SynchronizeHost() {
|
|
auto texture = state.process->GetPointer<u8>(guest->address);
|
|
auto size = format.GetSize(dimensions);
|
|
backing.resize(size);
|
|
auto output = reinterpret_cast<u8 *>(backing.data());
|
|
|
|
if (guest->tileMode == texture::TileMode::Block) {
|
|
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
|
|
constexpr auto sectorWidth = 16; // The width of a sector in bytes
|
|
constexpr auto sectorHeight = 2; // The height of a sector in lines
|
|
constexpr auto gobWidth = 64; // The width of a GOB in bytes
|
|
constexpr auto gobHeight = 8; // The height of a GOB in lines
|
|
|
|
auto robHeight = gobHeight * guest->tileConfig.blockHeight; // The height of a single ROB (Row of Blocks) in lines
|
|
auto surfaceHeightRobs = util::AlignUp(dimensions.height / format.blockHeight, robHeight) / robHeight; // The height of the surface in ROBs (Row Of Blocks)
|
|
auto robWidthBytes = util::AlignUp((guest->tileConfig.surfaceWidth / format.blockWidth) * format.bpb, gobWidth); // The width of a ROB in bytes
|
|
auto robWidthBlocks = robWidthBytes / gobWidth; // The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
|
|
auto robBytes = robWidthBytes * robHeight; // The size of a ROB in bytes
|
|
auto gobYOffset = robWidthBytes * gobHeight; // The offset of the next Y-axis GOB from the current one in linear space
|
|
|
|
auto inputSector = texture; // The address of the input sector
|
|
auto outputRob = output; // The address of the output block
|
|
|
|
for (u32 rob = 0; rob < surfaceHeightRobs; rob++) { // Every Surface contains `surfaceHeightRobs` ROBs
|
|
auto outputBlock = outputRob; // We iterate through a block independently of the ROB
|
|
for (u32 block = 0; block < robWidthBlocks; block++) { // Every ROB contains `surfaceWidthBlocks` Blocks
|
|
auto outputGob = outputBlock; // We iterate through a GOB independently of the block
|
|
for (u32 gobY = 0; gobY < guest->tileConfig.blockHeight; gobY++) { // Every Block contains `blockHeight` Y-axis GOBs
|
|
for (u32 index = 0; index < sectorWidth * sectorHeight; index++) { // Every Y-axis GOB contains `sectorWidth * sectorHeight` sectors
|
|
const u32 xT = ((index << 3) & 0b10000) | ((index << 1) & 0b100000); // Morton-Swizzle on the X-axis
|
|
const u32 yT = ((index >> 1) & 0b110) | (index & 0b1); // Morton-Swizzle on the Y-axis
|
|
std::memcpy(outputGob + (yT * robWidthBytes) + xT, inputSector, sectorWidth);
|
|
inputSector += sectorWidth; // `sectorWidth` bytes are of sequential image data
|
|
}
|
|
outputGob += gobYOffset; // Increment the output GOB to the next Y-axis GOB
|
|
}
|
|
outputBlock += gobWidth; // Increment the output block to the next block (As Block Width = 1 GOB Width)
|
|
}
|
|
outputRob += robBytes; // Increment the output block to the next ROB
|
|
}
|
|
} else if (guest->tileMode == texture::TileMode::Pitch) {
|
|
auto sizeLine = guest->format.GetSize(dimensions.width, 1); // The size of a single line of pixel data
|
|
auto sizeStride = guest->format.GetSize(guest->tileConfig.pitch, 1); // The size of a single stride of pixel data
|
|
|
|
auto inputLine = texture; // The address of the input line
|
|
auto outputLine = output; // The address of the output line
|
|
|
|
for (auto line = 0; line < dimensions.height; line++) {
|
|
std::memcpy(outputLine, inputLine, sizeLine);
|
|
inputLine += sizeStride;
|
|
outputLine += sizeLine;
|
|
}
|
|
} else if (guest->tileMode == texture::TileMode::Linear) {
|
|
std::memcpy(output, texture, size);
|
|
}
|
|
}
|
|
|
|
PresentationTexture::PresentationTexture(const DeviceState &state, const std::shared_ptr<GuestTexture> &guest, const texture::Dimensions &dimensions, const texture::Format &format, const std::function<void()> &releaseCallback) : releaseCallback(releaseCallback), Texture(state, guest, dimensions, format, {}) {}
|
|
|
|
i32 PresentationTexture::GetAndroidFormat() {
|
|
switch (format.vkFormat) {
|
|
case vk::Format::eR8G8B8A8Unorm:
|
|
return WINDOW_FORMAT_RGBA_8888;
|
|
case vk::Format::eR5G6B5UnormPack16:
|
|
return WINDOW_FORMAT_RGB_565;
|
|
default:
|
|
throw exception("GetAndroidFormat: Cannot find corresponding Android surface format");
|
|
}
|
|
}
|
|
}
|