mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 23:45:30 +03:00
Use an empty host texture in place of invalid TIC entries on guest
Some games may pass empty TICs as inputs to shaders while not actually using them within the shader. Create an empty texture and pass this in instead when we hit this case, the nullDescriptor feature could be used but it's not supported by all devices so we chose to do it this way instead.
This commit is contained in:
parent
41b98c7daa
commit
8eaca87de8
@ -70,6 +70,35 @@ namespace skyline::gpu::interconnect {
|
|||||||
|
|
||||||
if (!gpu.traits.supportsLastProvokingVertex)
|
if (!gpu.traits.supportsLastProvokingVertex)
|
||||||
rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>();
|
rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>();
|
||||||
|
|
||||||
|
// Set of default parameters for null image which we use instead of a null descriptor since not all devices support that extension
|
||||||
|
constexpr texture::Format NullImageFormat{format::R8G8B8A8Unorm};
|
||||||
|
constexpr texture::Dimensions NullImageDimensions{1, 1, 1};
|
||||||
|
constexpr vk::ImageLayout NullImageInitialLayout{vk::ImageLayout::eUndefined};
|
||||||
|
constexpr vk::ImageTiling NullImageTiling{vk::ImageTiling::eOptimal};
|
||||||
|
|
||||||
|
auto vkImage{gpu.memory.AllocateImage({
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = NullImageFormat->vkFormat,
|
||||||
|
.extent = NullImageDimensions,
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
|
.tiling = NullImageTiling,
|
||||||
|
.usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive,
|
||||||
|
.queueFamilyIndexCount = 1,
|
||||||
|
.pQueueFamilyIndices = &gpu.vkQueueFamilyIndex,
|
||||||
|
.initialLayout = NullImageInitialLayout
|
||||||
|
})};
|
||||||
|
|
||||||
|
auto nullTexture{std::make_shared<Texture>(gpu, std::move(vkImage), NullImageDimensions, NullImageFormat, NullImageInitialLayout, NullImageTiling)};
|
||||||
|
nullTexture->TransitionLayout(vk::ImageLayout::eGeneral);
|
||||||
|
nullTextureView = nullTexture->GetView(vk::ImageViewType::e2D, vk::ImageSubresourceRange{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.levelCount = 1,
|
||||||
|
.layerCount = 1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render Targets + Render Target Control */
|
/* Render Targets + Render Target Control */
|
||||||
@ -1769,6 +1798,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
/* Textures */
|
/* Textures */
|
||||||
private:
|
private:
|
||||||
u32 bindlessTextureConstantBufferIndex{};
|
u32 bindlessTextureConstantBufferIndex{};
|
||||||
|
std::shared_ptr<TextureView> nullTextureView; //!< View used instead of a null descriptor when an empty TIC is encountered, this avoids the need for the nullDescriptor VK feature
|
||||||
|
|
||||||
struct PoolTexture : public FenceCycleDependency {
|
struct PoolTexture : public FenceCycleDependency {
|
||||||
GuestTexture guest;
|
GuestTexture guest;
|
||||||
@ -1961,6 +1991,11 @@ namespace skyline::gpu::interconnect {
|
|||||||
auto textureIt{texturePool.textures.insert({textureControl, {}})};
|
auto textureIt{texturePool.textures.insert({textureControl, {}})};
|
||||||
auto &poolTexture{textureIt.first->second};
|
auto &poolTexture{textureIt.first->second};
|
||||||
if (textureIt.second) {
|
if (textureIt.second) {
|
||||||
|
if (textureControl.formatWord.format == TextureImageControl::ImageFormat::Invalid) {
|
||||||
|
poolTexture.view = nullTextureView;
|
||||||
|
return nullTextureView;
|
||||||
|
}
|
||||||
|
|
||||||
// If the entry didn't exist prior then we need to convert the TIC to a GuestTexture
|
// If the entry didn't exist prior then we need to convert the TIC to a GuestTexture
|
||||||
auto &guest{poolTexture.guest};
|
auto &guest{poolTexture.guest};
|
||||||
guest.format = ConvertTicFormat(textureControl.formatWord, textureControl.isSrgb);
|
guest.format = ConvertTicFormat(textureControl.formatWord, textureControl.isSrgb);
|
||||||
|
@ -22,6 +22,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
* @note An underscore may be used to describe a different block in a format
|
* @note An underscore may be used to describe a different block in a format
|
||||||
*/
|
*/
|
||||||
enum class ImageFormat : u32 {
|
enum class ImageFormat : u32 {
|
||||||
|
Invalid = 0x0,
|
||||||
R32G32B32A32 = 0x01,
|
R32G32B32A32 = 0x01,
|
||||||
R32G32B32 = 0x02,
|
R32G32B32 = 0x02,
|
||||||
R16G16B16A16 = 0x03,
|
R16G16B16A16 = 0x03,
|
||||||
|
@ -415,8 +415,8 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SynchronizeHost(bool rwTrap) {
|
void Texture::SynchronizeHost(bool rwTrap) {
|
||||||
if (dirtyState != DirtyState::CpuDirty)
|
if (dirtyState != DirtyState::CpuDirty || !guest)
|
||||||
return; // If the texture has not been modified on the CPU, there is no need to synchronize it
|
return; // If the texture has not been modified on the CPU or has no mappings, there is no need to synchronize it
|
||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeHost");
|
TRACE_EVENT("gpu", "Texture::SynchronizeHost");
|
||||||
|
|
||||||
@ -439,7 +439,7 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SynchronizeHostWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle, bool rwTrap) {
|
void Texture::SynchronizeHostWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle, bool rwTrap) {
|
||||||
if (dirtyState != DirtyState::CpuDirty)
|
if (dirtyState != DirtyState::CpuDirty || !guest)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeHostWithBuffer");
|
TRACE_EVENT("gpu", "Texture::SynchronizeHostWithBuffer");
|
||||||
@ -461,13 +461,12 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SynchronizeGuest(bool skipTrap) {
|
void Texture::SynchronizeGuest(bool skipTrap) {
|
||||||
if (dirtyState != DirtyState::GpuDirty || layout == vk::ImageLayout::eUndefined) {
|
if (dirtyState != DirtyState::GpuDirty || layout == vk::ImageLayout::eUndefined || !guest) {
|
||||||
// We can skip syncing in two cases:
|
// We can skip syncing in three cases:
|
||||||
// * If the texture has not been used on the GPU, there is no need to synchronize it
|
// * If the texture has not been used on the GPU, there is no need to synchronize it
|
||||||
// * If the state of the host texture is undefined then so can the guest
|
// * If the state of the host texture is undefined then so can the guest
|
||||||
|
// * If there is no guest texture to synchronise
|
||||||
return;
|
return;
|
||||||
} else if (!guest) {
|
|
||||||
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeGuest");
|
TRACE_EVENT("gpu", "Texture::SynchronizeGuest");
|
||||||
@ -497,12 +496,10 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SynchronizeGuestWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle) {
|
void Texture::SynchronizeGuestWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle) {
|
||||||
if (dirtyState != DirtyState::GpuDirty)
|
if (dirtyState != DirtyState::GpuDirty || !guest)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!guest)
|
if (layout == vk::ImageLayout::eUndefined)
|
||||||
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
|
|
||||||
else if (layout == vk::ImageLayout::eUndefined)
|
|
||||||
return; // If the state of the host texture is undefined then so can the guest
|
return; // If the state of the host texture is undefined then so can the guest
|
||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer");
|
TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer");
|
||||||
@ -530,6 +527,9 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TextureView> Texture::GetView(vk::ImageViewType type, vk::ImageSubresourceRange range, texture::Format pFormat, vk::ComponentMapping mapping) {
|
std::shared_ptr<TextureView> Texture::GetView(vk::ImageViewType type, vk::ImageSubresourceRange range, texture::Format pFormat, vk::ComponentMapping mapping) {
|
||||||
|
if (!pFormat)
|
||||||
|
pFormat = format;
|
||||||
|
|
||||||
for (auto viewIt{views.begin()}; viewIt != views.end();) {
|
for (auto viewIt{views.begin()}; viewIt != views.end();) {
|
||||||
auto view{viewIt->lock()};
|
auto view{viewIt->lock()};
|
||||||
if (view && type == view->type && pFormat == view->format && range == view->range && mapping == view->mapping)
|
if (view && type == view->type && pFormat == view->format && range == view->range && mapping == view->mapping)
|
||||||
|
Loading…
Reference in New Issue
Block a user