diff --git a/app/src/main/cpp/skyline/gpu/interconnect/blit_context.h b/app/src/main/cpp/skyline/gpu/interconnect/blit_context.h index 314a1def..f592e72a 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/blit_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/blit_context.h @@ -85,16 +85,15 @@ namespace skyline::gpu::interconnect { texture.aspect = texture.format->vkAspect; texture.baseArrayLayer = 0; texture.layerCount = 1; + texture.viewType = vk::ImageViewType::e2D; if (surface.memoryLayout == fermi2d::MemoryLayout::Pitch) { - texture.type = gpu::texture::TextureType::e2D; texture.dimensions = gpu::texture::Dimensions{surface.stride / texture.format->bpb, surface.height, 1}; texture.tileConfig = gpu::texture::TileConfig{ .mode = gpu::texture::TileMode::Pitch, .pitch = surface.stride }; } else { - texture.type = gpu::texture::TextureType::e2D; texture.dimensions = gpu::texture::Dimensions{surface.width, surface.height, surface.depth}; texture.tileConfig = gpu::texture::TileConfig{ .mode = gpu::texture::TileMode::Block, diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index d67c38d1..f33ed0cd 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -402,7 +402,15 @@ namespace skyline::gpu::interconnect { renderTarget.guest.mappings.assign(mappings.begin(), mappings.end()); } - renderTarget.guest.type = static_cast(renderTarget.guest.dimensions.GetType()); + renderTarget.guest.viewType = [&]() { + if (renderTarget.is3d) + return vk::ImageViewType::e2DArray; // We can't render to 3D textures, so render to a 2D array view of a 3D texture (since layerCount is 1 and depth is >1 the texture manager will create the underlying texture as such) + + if (renderTarget.guest.layerCount > 1) + return vk::ImageViewType::e2DArray; + + return vk::ImageViewType::e2D; + }(); renderTarget.view = gpu.texture.FindOrCreate(renderTarget.guest); return renderTarget.view.get(); @@ -2270,14 +2278,13 @@ namespace skyline::gpu::interconnect { guest.viewMipCount = textureControl.viewConfig.mipMaxLevel - textureControl.viewConfig.mipMinLevel + 1; using TicType = TextureImageControl::TextureType; - using TexType = texture::TextureType; switch (textureControl.textureType) { case TicType::e1D: - guest.type = TexType::e1D; + guest.viewType = vk::ImageViewType::e1D; guest.layerCount = 1; break; case TicType::e1DArray: - guest.type = TexType::e1DArray; + guest.viewType = vk::ImageViewType::e1DArray; guest.layerCount = depth; break; case TicType::e1DBuffer: @@ -2288,26 +2295,26 @@ namespace skyline::gpu::interconnect { guest.viewMipBase = 0; guest.viewMipCount = 1; case TicType::e2D: - guest.type = TexType::e2D; + guest.viewType = vk::ImageViewType::e2D; guest.layerCount = 1; break; case TicType::e2DArray: - guest.type = TexType::e2DArray; + guest.viewType = vk::ImageViewType::e2DArray; guest.layerCount = depth; break; case TicType::e3D: - guest.type = TexType::e3D; + guest.viewType = vk::ImageViewType::e3D; guest.layerCount = 1; guest.dimensions.depth = depth; break; case TicType::eCube: - guest.type = TexType::eCube; + guest.viewType = vk::ImageViewType::eCube; guest.layerCount = CubeFaceCount; break; case TicType::eCubeArray: - guest.type = TexType::eCubeArray; + guest.viewType = vk::ImageViewType::eCubeArray; guest.layerCount = depth * CubeFaceCount; break; } diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.cpp b/app/src/main/cpp/skyline/gpu/texture/texture.cpp index c97074a8..cf79623f 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.cpp +++ b/app/src/main/cpp/skyline/gpu/texture/texture.cpp @@ -28,6 +28,40 @@ namespace skyline::gpu { } } + vk::ImageType GuestTexture::GetImageType() const { + switch (viewType) { + case vk::ImageViewType::e1D: + case vk::ImageViewType::e1DArray: + return vk::ImageType::e1D; + case vk::ImageViewType::e2D: + case vk::ImageViewType::e2DArray: + // If depth is > 1 this is a 2D view into a 3D texture so the underlying image needs to be created as 3D yoo + if (dimensions.depth > 1) + return vk::ImageType::e3D; + else + return vk::ImageType::e2D; + case vk::ImageViewType::eCube: + case vk::ImageViewType::eCubeArray: + return vk::ImageType::e2D; + case vk::ImageViewType::e3D: + return vk::ImageType::e3D; + } + } + + u32 GuestTexture::GetViewLayerCount() const { + if (GetImageType() == vk::ImageType::e3D && viewType != vk::ImageViewType::e3D) + return dimensions.depth; + else + return layerCount; + } + + u32 GuestTexture::GetViewDepth() const { + if (GetImageType() == vk::ImageType::e3D && viewType != vk::ImageViewType::e3D) + return layerCount; + else + return dimensions.depth; + } + TextureView::TextureView(std::shared_ptr texture, vk::ImageViewType type, vk::ImageSubresourceRange range, texture::Format format, vk::ComponentMapping mapping) : texture(std::move(texture)), type(type), format(format), mapping(mapping), range(range) {} Texture::TextureViewStorage::TextureViewStorage(vk::ImageViewType type, texture::Format format, vk::ComponentMapping mapping, vk::ImageSubresourceRange range, vk::raii::ImageView &&vkView) : type(type), format(format), mapping(mapping), range(range), vkView(std::move(vkView)) {} @@ -519,21 +553,7 @@ namespace skyline::gpu { if (format->vkAspect & (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)) usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - // First attempt to derive type from dimensions - auto imageType{dimensions.GetType()}; - - // Try to ensure that the image type is compatible with the given image view type since we can't create a 2D image view from a 1D image - if (imageType == vk::ImageType::e1D && guest->type != texture::TextureType::e1D && guest->type != texture::TextureType::e1DArray) { - switch (guest->type) { - case texture::TextureType::e3D: - imageType = vk::ImageType::e3D; - break; - default: - imageType = vk::ImageType::e2D; - break; - } - } - + auto imageType{guest->GetImageType()}; if (imageType == vk::ImageType::e2D && dimensions.width == dimensions.height && layerCount >= 6) flags |= vk::ImageCreateFlagBits::eCubeCompatible; else if (imageType == vk::ImageType::e3D) diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.h b/app/src/main/cpp/skyline/gpu/texture/texture.h index ec650fe0..3c02a24b 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.h +++ b/app/src/main/cpp/skyline/gpu/texture/texture.h @@ -27,15 +27,6 @@ namespace skyline::gpu { auto operator<=>(const Dimensions &) const = default; - constexpr vk::ImageType GetType() const { - if (depth > 1) - return vk::ImageType::e3D; - else if (height > 1) - return vk::ImageType::e2D; - else - return vk::ImageType::e1D; - } - constexpr operator vk::Extent2D() const { return vk::Extent2D{ .width = width, @@ -208,21 +199,6 @@ namespace skyline::gpu { } }; - /** - * @brief The type of a texture to determine the access patterns for it - * @note This is effectively the Tegra X1 texture types with the 1DBuffer + 2DNoMipmap removed as those are handled elsewhere - * @note We explicitly utilize Vulkan types here as it provides the most efficient conversion while not exposing Vulkan to the outer API - */ - enum class TextureType { - e1D = VK_IMAGE_VIEW_TYPE_1D, - e2D = VK_IMAGE_VIEW_TYPE_2D, - e3D = VK_IMAGE_VIEW_TYPE_3D, - eCube = VK_IMAGE_VIEW_TYPE_CUBE, - e1DArray = VK_IMAGE_VIEW_TYPE_1D_ARRAY, - e2DArray = VK_IMAGE_VIEW_TYPE_2D_ARRAY, - eCubeArray = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, - }; - /** * @brief A description of a single mipmapped level of a block-linear surface */ @@ -250,7 +226,7 @@ namespace skyline::gpu { texture::Dimensions dimensions{}; texture::Format format{}; texture::TileConfig tileConfig{}; - texture::TextureType type{}; + vk::ImageViewType viewType{}; u32 baseArrayLayer{}; u32 layerCount{1}; u32 layerStride{}; //!< An optional hint regarding the size of a single layer, it **should** be set to 0 when not available and should never be a non-0 value that doesn't reflect the correct layer stride @@ -262,12 +238,12 @@ namespace skyline::gpu { GuestTexture() {} - GuestTexture(Mappings mappings, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u32 baseArrayLayer = 0, u32 layerCount = 1, u32 layerStride = 0, u32 mipLevelCount = 1, u32 viewMipBase = 0, u32 viewMipCount = 1) + GuestTexture(Mappings mappings, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, vk::ImageViewType viewType, u32 baseArrayLayer = 0, u32 layerCount = 1, u32 layerStride = 0, u32 mipLevelCount = 1, u32 viewMipBase = 0, u32 viewMipCount = 1) : mappings(mappings), dimensions(dimensions), format(format), tileConfig(tileConfig), - type(type), + viewType(viewType), baseArrayLayer(baseArrayLayer), layerCount(layerCount), layerStride(layerStride), @@ -276,12 +252,12 @@ namespace skyline::gpu { viewMipCount(viewMipCount), aspect(format->vkAspect) {} - GuestTexture(span mapping, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u32 baseArrayLayer = 0, u32 layerCount = 1, u32 layerStride = 0, u32 mipLevelCount = 1, u32 viewMipBase = 0, u32 viewMipCount = 1) + GuestTexture(span mapping, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, vk::ImageViewType viewType, u32 baseArrayLayer = 0, u32 layerCount = 1, u32 layerStride = 0, u32 mipLevelCount = 1, u32 viewMipBase = 0, u32 viewMipCount = 1) : mappings(1, mapping), dimensions(dimensions), format(format), tileConfig(tileConfig), - type(type), + viewType(viewType), baseArrayLayer(baseArrayLayer), layerCount(layerCount), layerStride(layerStride), @@ -296,6 +272,15 @@ namespace skyline::gpu { * @return The size of a single layer with layout alignment in bytes */ u32 GetLayerStride(); + + /** + * @return The most appropriate backing image type for this texture + */ + vk::ImageType GetImageType() const; + + u32 GetViewLayerCount() const; + + u32 GetViewDepth() const; }; class TextureManager; diff --git a/app/src/main/cpp/skyline/gpu/texture_manager.cpp b/app/src/main/cpp/skyline/gpu/texture_manager.cpp index 1addbb68..ca3cc2bd 100644 --- a/app/src/main/cpp/skyline/gpu/texture_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/texture_manager.cpp @@ -45,13 +45,18 @@ namespace skyline::gpu { if (firstHostMapping == hostMappings.begin() && firstHostMapping->begin() == guestMapping.begin() && mappingMatch && lastHostMapping == hostMappings.end() && lastGuestMapping.end() == std::prev(lastHostMapping)->end()) { // We've gotten a perfect 1:1 match for *all* mappings from the start to end, we just need to check for compatibility aside from this auto &matchGuestTexture{*hostMapping->texture->guest}; - if (matchGuestTexture.format->IsCompatible(*guestTexture.format) && (matchGuestTexture.dimensions == guestTexture.dimensions || matchGuestTexture.viewMipBase > 0) && matchGuestTexture.tileConfig == guestTexture.tileConfig) { + if (matchGuestTexture.format->IsCompatible(*guestTexture.format) && + ((matchGuestTexture.dimensions.width == guestTexture.dimensions.width && + matchGuestTexture.dimensions.height == guestTexture.dimensions.height && + matchGuestTexture.dimensions.depth == guestTexture.GetViewDepth()) + || matchGuestTexture.viewMipBase > 0) + && matchGuestTexture.tileConfig == guestTexture.tileConfig) { auto &texture{hostMapping->texture}; - return texture->GetView(static_cast(guestTexture.type), vk::ImageSubresourceRange{ + return texture->GetView(guestTexture.viewType, vk::ImageSubresourceRange{ .aspectMask = guestTexture.aspect, .baseMipLevel = guestTexture.viewMipBase, .levelCount = guestTexture.viewMipCount, - .layerCount = texture->layerCount, + .layerCount = guestTexture.GetViewLayerCount(), }, guestTexture.format, guestTexture.swizzle); } } /* else if (mappingMatch) { @@ -80,11 +85,11 @@ namespace skyline::gpu { textures.emplace(mapping, TextureMapping{texture, it, guestMapping}); } - return texture->GetView(static_cast(guestTexture.type), vk::ImageSubresourceRange{ + return texture->GetView(guestTexture.viewType, vk::ImageSubresourceRange{ .aspectMask = guestTexture.aspect, .baseMipLevel = guestTexture.viewMipBase, .levelCount = guestTexture.viewMipCount, - .layerCount = texture->layerCount, + .layerCount = guestTexture.GetViewLayerCount(), }, guestTexture.format, guestTexture.swizzle); } } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index 301ac24c..f3068718 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -344,7 +344,7 @@ namespace skyline::service::hosbinder { } gpu::texture::Dimensions dimensions(surface.width, surface.height); - gpu::GuestTexture guestTexture(span{}, dimensions, format, tileConfig, gpu::texture::TextureType::e2D); + gpu::GuestTexture guestTexture(span{}, dimensions, format, tileConfig, vk::ImageViewType::e2D); guestTexture.mappings[0] = span(nvMapHandleObj->GetPointer() + surface.offset, guestTexture.GetLayerStride()); buffer.texture = state.gpu->texture.FindOrCreate(guestTexture)->texture; }