diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index 4ec54f3e0..f134b0332 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -66,32 +66,42 @@ enum class VulkanImageType { RenderTexture }; +struct ImageViewInfo { + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; + VkImageAspectFlags aspect = 0; + uint32_t base_level = 0; + uint32_t level_count = 0; + uint32_t base_layer = 0; + uint32_t layer_count = 1; + uint32_t swizzle = 0; + bool is_storage = false; + + bool operator==(const ImageViewInfo&) const = default; +}; + +struct CachedImageView { + ImageViewInfo info; + VkImageView view = nullptr; +}; + +struct ImageViewCache { + std::mutex mutex; + std::vector views; + + ImageViewCache() = default; + KYTY_CLASS_NO_COPY(ImageViewCache); +}; + struct VulkanImage { - static constexpr int VIEW_MAX = 22; - static constexpr int VIEW_DEFAULT = 0; - static constexpr int VIEW_BGRA = 1; - static constexpr int VIEW_DEPTH_TEXTURE = 2; - static constexpr int VIEW_R001 = 3; - static constexpr int VIEW_RGB1 = 4; - static constexpr int VIEW_R000 = 5; - static constexpr int VIEW_RG01 = 6; - static constexpr int VIEW_000R = 7; - static constexpr int VIEW_DEFAULT_ARRAY = 8; - static constexpr int VIEW_BGRA_ARRAY = 9; - static constexpr int VIEW_DEPTH_TEXTURE_ARRAY = 10; - static constexpr int VIEW_R001_ARRAY = 11; - static constexpr int VIEW_RGB1_ARRAY = 12; - static constexpr int VIEW_R000_ARRAY = 13; - static constexpr int VIEW_RG01_ARRAY = 14; - static constexpr int VIEW_000R_ARRAY = 15; - static constexpr int VIEW_STENCIL_TEXTURE = 16; - static constexpr int VIEW_STENCIL_TEXTURE_ARRAY = 17; - static constexpr int VIEW_STORAGE = 18; - static constexpr int VIEW_STORAGE_ARRAY = 19; - static constexpr int VIEW_BGRA_TO_RGBA = 20; - static constexpr int VIEW_ABGR = 21; + static constexpr int VIEW_MAX = 4; + static constexpr int VIEW_DEFAULT = 0; + static constexpr int VIEW_DEFAULT_ARRAY = 1; + static constexpr int VIEW_STORAGE = 2; + static constexpr int VIEW_STORAGE_ARRAY = 3; explicit VulkanImage(VulkanImageType type): type(type) {} + KYTY_CLASS_NO_COPY(VulkanImage); VulkanImageType type = VulkanImageType::Unknown; VkFormat format = VK_FORMAT_UNDEFINED; @@ -103,6 +113,7 @@ struct VulkanImage { VkImageView image_view[VIEW_MAX] = {}; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; Graphics::VulkanMemory memory; + ImageViewCache view_cache; }; struct VideoOutVulkanImage: public VulkanImage { @@ -130,23 +141,7 @@ struct TextureVulkanImage: public GpuTextureVulkanImage { }; struct StorageTextureVulkanImage: public GpuTextureVulkanImage { - struct StorageView { - uint32_t base_level = 0; - VkImageView view = nullptr; - }; - struct SampledView { - VkFormat format = VK_FORMAT_UNDEFINED; - uint32_t swizzle = 0; - uint32_t type = 0; - uint32_t base_level = 0; - uint32_t level_count = 0; - VkImageView view = nullptr; - }; StorageTextureVulkanImage(): GpuTextureVulkanImage(VulkanImageType::StorageTexture) {} - std::mutex sampled_view_mutex; - std::vector sampled_views; - std::mutex storage_view_mutex; - std::vector storage_views; }; struct RenderTextureVulkanImage: public VulkanImage { @@ -157,33 +152,10 @@ struct RenderTextureVulkanImage: public VulkanImage { uint32_t layer_count = 1; VkImageView view = nullptr; }; - struct SampledView { - VkFormat format = VK_FORMAT_UNDEFINED; - VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; - uint32_t base_level = 0; - uint32_t level_count = 0; - uint32_t base_layer = 0; - uint32_t layer_count = 1; - int variant = VIEW_DEFAULT; - VkImageView view = nullptr; - }; - struct StorageView { - VkFormat format = VK_FORMAT_UNDEFINED; - VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; - uint32_t base_level = 0; - uint32_t level_count = 0; - uint32_t base_layer = 0; - uint32_t layer_count = 1; - VkImageView view = nullptr; - }; RenderTextureVulkanImage(): VulkanImage(VulkanImageType::RenderTexture) {} VkImageView render_view[16] = {}; std::mutex attachment_view_mutex; std::vector attachment_views; - std::mutex sampled_view_mutex; - std::vector sampled_views; - std::mutex storage_view_mutex; - std::vector storage_views; }; struct VulkanBuffer { diff --git a/src/graphics/host_gpu/renderer/descriptors.cpp b/src/graphics/host_gpu/renderer/descriptors.cpp index 221cc5de8..d6f004f98 100644 --- a/src/graphics/host_gpu/renderer/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/descriptors.cpp @@ -84,14 +84,6 @@ static int SampledArrayViewIndex(const VulkanImage* image, int view_index) { switch (view_index) { case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY; - case VulkanImage::VIEW_BGRA: return VulkanImage::VIEW_BGRA_ARRAY; - case VulkanImage::VIEW_DEPTH_TEXTURE: return VulkanImage::VIEW_DEPTH_TEXTURE_ARRAY; - case VulkanImage::VIEW_STENCIL_TEXTURE: return VulkanImage::VIEW_STENCIL_TEXTURE_ARRAY; - case VulkanImage::VIEW_R001: return VulkanImage::VIEW_R001_ARRAY; - case VulkanImage::VIEW_RGB1: return VulkanImage::VIEW_RGB1_ARRAY; - case VulkanImage::VIEW_R000: return VulkanImage::VIEW_R000_ARRAY; - case VulkanImage::VIEW_RG01: return VulkanImage::VIEW_RG01_ARRAY; - case VulkanImage::VIEW_000R: return VulkanImage::VIEW_000R_ARRAY; default: return view_index; } } @@ -334,6 +326,16 @@ ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource, } } +bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource, + const ShaderTextureResource& descriptor, + const VulkanImage& image) { + return image.type == VulkanImageType::VideoOut && image.layers == 1 && + IsSupportedSampledColorResource(resource) && + resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && + descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && + descriptor.Depth() == 0 && descriptor.BaseArray5() == 0; +} + bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const VulkanImage& image) { const auto width = static_cast(descriptor.Width5()) + 1u; @@ -588,7 +590,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, image = nullptr; } else { ValidateDepthTargetBinding(resource, descriptor, image, view_format, size.size); - view = SelectSampledDepthView(image->format, view_format, swizzle); + image_view = g_render_ctx->GetTextureCache()->GetDepthTargetSampledView( + g_render_ctx->GetGraphicCtx(), static_cast(image), + view_format, swizzle, 0, 1, VK_IMAGE_VIEW_TYPE_2D, 0, 1); } } else { if (!(storage ? IsSupportedStorageImageResource(resource) @@ -611,19 +615,17 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, image->mip_levels, base_level, descriptor.BaseArray5(), static_cast(type)); } - view = storage ? SelectStorageColorView(image->format, view_format, swizzle) - : SelectSampledColorView(image->format, view_format, swizzle); if (storage) { + view = SelectStorageColorView(image->format, view_format, swizzle); image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView( g_render_ctx->GetGraphicCtx(), static_cast(image), view_format, base_level, view_levels, target_view.type, target_view.base_layer, target_view.layer_count); } else { - image_view = g_render_ctx->GetTextureCache()->GetRenderTargetSampledView( - g_render_ctx->GetGraphicCtx(), - static_cast(image), view_format, view, - base_level, view_levels, target_view.type, target_view.base_layer, + image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( + g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level, + view_levels, target_view.type, target_view.base_layer, target_view.layer_count); } } @@ -661,10 +663,27 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, view = VulkanImage::VIEW_STORAGE; g_render_ctx->GetTextureCache()->MarkGpuWritten(image); } else { - image = video.image; - if (swizzle == DstSel(6, 5, 4, 7)) { - view = VulkanImage::VIEW_BGRA; + const bool exact = + IsSupportedSampledVideoOutView(resource, descriptor, *video.image) && + width == video.image->extent.width && height == video.image->extent.height && + levels == 1 && base_level == 0 && view_levels == 1 && video.size == size.size && + video.pitch == pitch; + if (!exact) { + EXIT("unsupported sampled access to video-out surface: resource=%u dimension=%u" + " image_format=%d view_format=%d swizzle=0x%03x extent=%ux%u/%ux%u" + " depth=%u levels=%u base=%u count=%u type=%u size=0x%016" PRIx64 + "/0x%016" PRIx64 " pitch=%u/%u\n", + static_cast(resource.kind), + static_cast(resource.dimension), + static_cast(video.image->format), static_cast(view_format), + swizzle, width, height, video.image->extent.width, + video.image->extent.height, depth, levels, base_level, view_levels, + static_cast(type), size.size, video.size, pitch, video.pitch); } + image = video.image; + image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( + g_render_ctx->GetGraphicCtx(), video.image, view_format, swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); } } } diff --git a/src/graphics/host_gpu/renderer/descriptors.h b/src/graphics/host_gpu/renderer/descriptors.h index b2b87eb96..d7a0ab458 100644 --- a/src/graphics/host_gpu/renderer/descriptors.h +++ b/src/graphics/host_gpu/renderer/descriptors.h @@ -12,6 +12,9 @@ struct VulkanImage; [[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const VulkanImage& image); +[[nodiscard]] bool +IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource, + const ShaderTextureResource& descriptor, const VulkanImage& image); void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& resource, const ShaderTextureResource& descriptor, uint64_t size); void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, diff --git a/src/graphics/host_gpu/renderer/imageView.h b/src/graphics/host_gpu/renderer/imageView.h index b0141a660..42605e8b9 100644 --- a/src/graphics/host_gpu/renderer/imageView.h +++ b/src/graphics/host_gpu/renderer/imageView.h @@ -86,41 +86,67 @@ namespace Libs::Graphics { return view_format == BgraSrgbStorageViewFormat(image_format) && swizzle == DstSel(6, 5, 4, 7); } -[[nodiscard]] inline int SelectSampledColorView(VkFormat image_format, VkFormat view_format, - uint32_t swizzle) noexcept { +[[nodiscard]] inline bool IsValidSampledColorSwizzle(uint32_t swizzle) noexcept { + if ((swizzle & ~0xfffu) != 0) { + return false; + } + for (uint32_t channel = 0; channel < 4; channel++) { + switch (GetDstSel(swizzle, channel)) { + case 0: + case 1: + case 4: + case 5: + case 6: + case 7: break; + default: return false; + } + } + return true; +} + +[[nodiscard]] inline bool IsSupportedSampledColorView(VkFormat image_format, + VkFormat view_format, + uint32_t swizzle) noexcept { + if (!IsValidSampledColorSwizzle(swizzle)) { + return false; + } + if (image_format == view_format || IsRgba8SrgbReinterpretation(image_format, view_format)) { + return true; + } if ((IsRgba16UintFloatReinterpretation(image_format, view_format) || IsRgba8UnormUintReinterpretation(image_format, view_format)) && swizzle == DstSel(4, 5, 6, 7)) { - return VulkanImage::VIEW_DEFAULT; + return true; } - if (image_format == view_format) { - switch (swizzle) { - case DstSel(4, 5, 6, 7): return VulkanImage::VIEW_DEFAULT; - case DstSel(4, 0, 0, 1): return VulkanImage::VIEW_R001; - case DstSel(4, 5, 0, 1): return VulkanImage::VIEW_RG01; - case DstSel(4, 5, 6, 1): return VulkanImage::VIEW_RGB1; - default: break; - } - } - if (image_format == VK_FORMAT_R16G16B16A16_SFLOAT && view_format == image_format && - swizzle == DstSel(7, 6, 5, 4)) { - return VulkanImage::VIEW_ABGR; - } - if (IsBgraToRgbaSampledView(image_format, view_format) && swizzle == DstSel(6, 5, 4, 7)) { - return VulkanImage::VIEW_BGRA_TO_RGBA; + return IsBgraToRgbaSampledView(image_format, view_format) && + swizzle == DstSel(6, 5, 4, 7); +} + +[[nodiscard]] inline uint32_t SelectSampledColorView(VkFormat image_format, VkFormat view_format, + uint32_t swizzle) noexcept { + if (IsSupportedSampledColorView(image_format, view_format, swizzle)) { + return swizzle; } UnsupportedColorView("sampled", image_format, view_format, swizzle); } -[[nodiscard]] inline int SelectSampledDepthView(VkFormat image_format, VkFormat view_format, - uint32_t swizzle) noexcept { - if (IsSupportedSampledDepthFormat(image_format, view_format)) { - switch (swizzle) { - case DstSel(4, 4, 4, 4): return VulkanImage::VIEW_DEPTH_TEXTURE; - case DstSel(4, 0, 0, 0): return VulkanImage::VIEW_R000; - case DstSel(4, 0, 0, 1): return VulkanImage::VIEW_R001; - default: break; - } +[[nodiscard]] inline bool IsSupportedSampledDepthView(VkFormat image_format, VkFormat view_format, + uint32_t swizzle) noexcept { + if (!IsSupportedSampledDepthFormat(image_format, view_format)) { + return false; + } + switch (swizzle) { + case DstSel(4, 4, 4, 4): + case DstSel(4, 0, 0, 0): + case DstSel(4, 0, 0, 1): return true; + default: return false; + } +} + +[[nodiscard]] inline uint32_t SelectSampledDepthView(VkFormat image_format, VkFormat view_format, + uint32_t swizzle) noexcept { + if (IsSupportedSampledDepthView(image_format, view_format, swizzle)) { + return swizzle; } EXIT("unsupported sampled depth image view: image_format=%d view_format=%d swizzle=0x%03x\n", static_cast(image_format), static_cast(view_format), swizzle); @@ -134,8 +160,8 @@ IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resou !resource.written && !resource.atomic; } -[[nodiscard]] inline bool IsSupportedSampledDepthUintResource( - const ShaderRecompiler::IR::ImageResource& resource) noexcept { +[[nodiscard]] inline bool +IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept { return resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint && resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.read && diff --git a/src/graphics/host_gpu/renderer/textureCache.cpp b/src/graphics/host_gpu/renderer/textureCache.cpp index 765598591..375b8b2e4 100644 --- a/src/graphics/host_gpu/renderer/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/textureCache.cpp @@ -887,32 +887,11 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_BGRA, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_IDENTITY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_R001, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ONE); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_RGB1, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_ONE); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_R000, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_RG01, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ONE); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_000R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_R); if (image->layers > 1) { CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_IMAGE_VIEW_TYPE_2D_ARRAY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_BGRA_ARRAY, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_IMAGE_VIEW_TYPE_2D_ARRAY); } if (FormatSupportsStorage(ctx, image->format)) { CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, VK_COMPONENT_SWIZZLE_IDENTITY, @@ -926,13 +905,6 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_FORMAT_UNDEFINED, 0, 1); } } - const auto rgba_view_format = BgraToRgbaSampledViewFormat(image->format); - if (rgba_view_format != VK_FORMAT_UNDEFINED) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_BGRA_TO_RGBA, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_A, VK_IMAGE_VIEW_TYPE_2D, rgba_view_format, - VK_IMAGE_USAGE_SAMPLED_BIT); - } CreateRenderAttachmentViews(ctx, image); } @@ -940,24 +912,12 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_BGRA, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_IDENTITY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_IMAGE_VIEW_TYPE_2D_ARRAY); - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_BGRA_ARRAY, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_IMAGE_VIEW_TYPE_2D_ARRAY); - if ((image->format == VK_FORMAT_R8G8B8A8_SRGB || - image->format == VK_FORMAT_B8G8R8A8_SRGB) && + if ((image->format == VK_FORMAT_R8G8B8A8_SRGB || image->format == VK_FORMAT_B8G8R8A8_SRGB) && FormatSupportsStorage(ctx, VK_FORMAT_R8G8B8A8_UINT)) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, + CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UINT, - VK_IMAGE_USAGE_STORAGE_BIT, 1); + VK_COMPONENT_SWIZZLE_IDENTITY, VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UINT, VK_IMAGE_USAGE_STORAGE_BIT, 1); } } @@ -1074,43 +1034,6 @@ void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) { {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, 0, 0, 1, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_DEPTH_TEXTURE, VK_IMAGE_VIEW_TYPE_2D, - VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_R}, - 0, 0, 1, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_R000, VK_IMAGE_VIEW_TYPE_2D, - VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO}, - 0, 0, 1, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_R001, VK_IMAGE_VIEW_TYPE_2D, - VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE}, - 0, 0, 1, 1); - if (image->layers > 1) { - UtilCreateImageView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, DepthAspectMask(image->format), - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, - 0, 0, image->layers, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_DEPTH_TEXTURE_ARRAY, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_R}, - 0, 0, image->layers, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_R000_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY, - VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO}, - 0, 0, image->layers, 1); - UtilCreateImageView(ctx, image, VulkanImage::VIEW_R001_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY, - VK_IMAGE_ASPECT_DEPTH_BIT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE}, - 0, 0, image->layers, 1); - } } DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, @@ -1366,147 +1289,128 @@ VkImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* return view; } -VkImageView TextureCache::GetRenderTargetSampledView(GraphicContext* ctx, - RenderTextureVulkanImage* image, - VkFormat view_format, int variant, - uint32_t base_level, uint32_t level_count, - VkImageViewType type, uint32_t base_layer, - uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || base_level >= 16 || - view_format == VK_FORMAT_UNDEFINED || level_count == 0 || - base_level + level_count > image->mip_levels || layer_count == 0 || - base_layer >= image->layers || layer_count > image->layers - base_layer || - (type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) || - (type == VK_IMAGE_VIEW_TYPE_2D && layer_count != 1)) { - EXIT("TextureCache: invalid render-target sampled view, image=%p variant=%d" - " view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", - static_cast(image), variant, static_cast(view_format), base_level, - level_count, base_layer, layer_count, static_cast(type), - image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); - } - const bool compatible_variant_format = - view_format == image->format || (variant == VulkanImage::VIEW_BGRA_TO_RGBA && - IsBgraToRgbaSampledView(image->format, view_format)) || - (variant == VulkanImage::VIEW_DEFAULT && - (IsRgba16UintFloatReinterpretation(image->format, view_format) || - IsRgba8UnormUintReinterpretation(image->format, view_format))); - if (!compatible_variant_format) { - EXIT("TextureCache: incompatible render-target sampled view format, image_format=%d" - " view_format=%d variant=%d\n", - static_cast(image->format), static_cast(view_format), variant); - } - const auto default_view_format = variant == VulkanImage::VIEW_BGRA_TO_RGBA - ? BgraToRgbaSampledViewFormat(image->format) - : image->format; - int default_variant = variant; - if (type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) { - switch (variant) { - case VulkanImage::VIEW_DEFAULT: - default_variant = VulkanImage::VIEW_DEFAULT_ARRAY; - break; - case VulkanImage::VIEW_BGRA: default_variant = VulkanImage::VIEW_BGRA_ARRAY; break; - default: default_variant = VulkanImage::VIEW_MAX; break; - } - } - const bool full_view = - base_level == 0 && level_count == image->mip_levels && base_layer == 0 && - layer_count == (type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ? image->layers : 1u); - if (view_format == default_view_format && full_view && default_variant >= 0 && - default_variant < VulkanImage::VIEW_MAX && image->image_view[default_variant] != nullptr) { - return image->image_view[default_variant]; +VkImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image, + const ImageViewInfo& info) { + const bool supported_type = info.type == VK_IMAGE_VIEW_TYPE_2D || + info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY || + info.type == VK_IMAGE_VIEW_TYPE_3D; + const bool valid_shape = + (info.type == VK_IMAGE_VIEW_TYPE_2D && info.layer_count == 1) || + info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY || + (info.type == VK_IMAGE_VIEW_TYPE_3D && info.base_layer == 0 && info.layer_count == 1); + if (ctx == nullptr || image == nullptr || image->image == nullptr || + info.format == VK_FORMAT_UNDEFINED || info.aspect == 0 || info.level_count == 0 || + info.base_level >= (image != nullptr ? image->mip_levels : 0) || + info.level_count > image->mip_levels - info.base_level || info.layer_count == 0 || + info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer || + !supported_type || !valid_shape) { + EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x" + " swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d storage=%d" + " image_levels=%u image_layers=%u\n", + static_cast(image), static_cast(info.format), info.aspect, + info.swizzle, info.base_level, info.level_count, info.base_layer, info.layer_count, + static_cast(info.type), info.is_storage, image != nullptr ? image->mip_levels : 0, + image != nullptr ? image->layers : 0); } - std::lock_guard lock(image->sampled_view_mutex); - for (const auto& cached: image->sampled_views) { - if (cached.format == view_format && cached.type == type && cached.variant == variant && - cached.base_level == base_level && cached.level_count == level_count && - cached.base_layer == base_layer && cached.layer_count == layer_count) { + auto& cache = image->view_cache; + std::lock_guard lock(cache.mutex); + for (const auto& cached: cache.views) { + if (cached.info == info) { return cached.view; } } - VkComponentMapping components {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - switch (variant) { - case VulkanImage::VIEW_DEFAULT: break; - case VulkanImage::VIEW_BGRA: - components = {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_IDENTITY}; - break; - case VulkanImage::VIEW_R001: - components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE}; - break; - case VulkanImage::VIEW_RGB1: - components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_ONE}; - break; - case VulkanImage::VIEW_R000: - components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO}; - break; - case VulkanImage::VIEW_RG01: - components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ONE}; - break; - case VulkanImage::VIEW_000R: - components = {VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R}; - break; - case VulkanImage::VIEW_BGRA_TO_RGBA: - if (!IsBgraToRgbaSampledView(image->format, view_format)) { - EXIT("TextureCache: incompatible mutable render-target sampled view\n"); - } - components = {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_A}; - break; - case VulkanImage::VIEW_ABGR: - components = {VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_R}; - break; - default: - EXIT("TextureCache: unsupported render-target sampled view variant: %d\n", variant); - } - - VkImageViewCreateInfo create {}; VkImageViewUsageCreateInfo usage {}; - usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; - usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create.pNext = &usage; - create.image = image->image; - create.viewType = type; - create.format = view_format; - create.components = components; - create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - create.subresourceRange.baseMipLevel = base_level; - create.subresourceRange.levelCount = level_count; - create.subresourceRange.baseArrayLayer = base_layer; - create.subresourceRange.layerCount = layer_count; + usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; + usage.usage = info.is_storage ? VK_IMAGE_USAGE_STORAGE_BIT : VK_IMAGE_USAGE_SAMPLED_BIT; + VkImageViewCreateInfo create {}; + create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create.pNext = &usage; + create.image = image->image; + create.viewType = info.type; + create.format = info.format; + create.components = + info.is_storage ? VkComponentMapping {} : TextureGetComponentMapping(info.swizzle); + create.subresourceRange.aspectMask = info.aspect; + create.subresourceRange.baseMipLevel = info.base_level; + create.subresourceRange.levelCount = info.level_count; + create.subresourceRange.baseArrayLayer = info.base_layer; + create.subresourceRange.layerCount = info.layer_count; VkImageView view = nullptr; const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view); if (result != VK_SUCCESS || view == nullptr) { - EXIT("TextureCache: failed to create render-target sampled subresource view," - " result=%d view_format=%d variant=%d mip=%u+%u layer=%u+%u type=%d\n", - static_cast(result), static_cast(view_format), variant, base_level, - level_count, base_layer, layer_count, static_cast(type)); + EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d" + " aspect=0x%x swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d storage=%d\n", + static_cast(result), static_cast(info.format), info.aspect, info.swizzle, + info.base_level, info.level_count, info.base_layer, info.layer_count, + static_cast(info.type), info.is_storage); } - image->sampled_views.push_back( - {view_format, type, base_level, level_count, base_layer, layer_count, variant, view}); + cache.views.push_back({info, view}); return view; } +VkImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx, + DepthStencilVulkanImage* image, + VkFormat view_format, uint32_t swizzle, + uint32_t base_level, uint32_t level_count, + VkImageViewType type, uint32_t base_layer, + uint32_t layer_count) { + if (ctx == nullptr || image == nullptr || image->image == nullptr || + view_format == VK_FORMAT_UNDEFINED || + !IsSupportedSampledDepthView(image->format, view_format, swizzle)) { + EXIT("TextureCache: invalid sampled depth-target view, image=%p image_format=%d" + " view_format=%d swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d" + " image_levels=%u image_layers=%u\n", + static_cast(image), + image != nullptr ? static_cast(image->format) : VK_FORMAT_UNDEFINED, + static_cast(view_format), swizzle, base_level, level_count, base_layer, + layer_count, static_cast(type), image != nullptr ? image->mip_levels : 0, + image != nullptr ? image->layers : 0); + } + return GetImageView(ctx, image, + {image->format, type, VK_IMAGE_ASPECT_DEPTH_BIT, base_level, level_count, + base_layer, layer_count, swizzle}); +} + +VkImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image, + VkFormat view_format, uint32_t swizzle, + uint32_t base_level, uint32_t level_count, + VkImageViewType type, uint32_t base_layer, + uint32_t layer_count) { + if (ctx == nullptr || image == nullptr || image->image == nullptr || + view_format == VK_FORMAT_UNDEFINED || base_level >= 16 || + (type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) || + !IsSupportedSampledColorView(image->format, view_format, swizzle)) { + EXIT("TextureCache: invalid sampled color view, image=%p swizzle=0x%03x" + " view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", + static_cast(image), swizzle, static_cast(view_format), base_level, + level_count, base_layer, layer_count, static_cast(type), + image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); + } + const auto precreated_view = type == VK_IMAGE_VIEW_TYPE_2D_ARRAY + ? VulkanImage::VIEW_DEFAULT_ARRAY + : VulkanImage::VIEW_DEFAULT; + const bool full_view = + base_level == 0 && level_count == image->mip_levels && base_layer == 0 && + layer_count == (type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ? image->layers : 1u); + if (view_format == image->format && swizzle == DstSel(4, 5, 6, 7) && full_view && + image->image_view[precreated_view] != nullptr) { + return image->image_view[precreated_view]; + } + return GetImageView(ctx, image, + {view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, base_level, level_count, + base_layer, layer_count, swizzle}); +} + VkImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx, RenderTextureVulkanImage* image, VkFormat view_format, uint32_t base_level, uint32_t level_count, VkImageViewType type, uint32_t base_layer, uint32_t layer_count) { if (ctx == nullptr || image == nullptr || image->image == nullptr || - view_format == VK_FORMAT_UNDEFINED || level_count == 0 || - base_level + level_count > image->mip_levels || layer_count == 0 || - base_layer >= image->layers || layer_count > image->layers - base_layer || - (type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) || - (type == VK_IMAGE_VIEW_TYPE_2D && layer_count != 1)) { + view_format == VK_FORMAT_UNDEFINED || + (type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY)) { EXIT("TextureCache: invalid render-target storage view, image=%p view_format=%d" " mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", static_cast(image), static_cast(view_format), base_level, @@ -1532,52 +1436,15 @@ VkImageView TextureCache::GetRenderTargetStorageView(GraphicContext* c } } - std::lock_guard lock(image->storage_view_mutex); - for (const auto& cached: image->storage_views) { - if (cached.format == view_format && cached.type == type && - cached.base_level == base_level && cached.level_count == level_count && - cached.base_layer == base_layer && cached.layer_count == layer_count) { - return cached.view; - } - } if (compatible && !FormatSupportsStorage(ctx, view_format)) { EXIT("TextureCache: compatible render-target storage format lacks storage support," " image_format=%d view_format=%d base=%u count=%u\n", static_cast(image->format), static_cast(view_format), base_level, level_count); } - - VkImageViewUsageCreateInfo usage {}; - usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; - usage.usage = VK_IMAGE_USAGE_STORAGE_BIT; - VkImageViewCreateInfo create {}; - create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create.pNext = &usage; - create.image = image->image; - create.viewType = type; - create.format = view_format; - create.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - create.subresourceRange.baseMipLevel = base_level; - create.subresourceRange.levelCount = level_count; - create.subresourceRange.baseArrayLayer = base_layer; - create.subresourceRange.layerCount = layer_count; - VkImageView view = nullptr; - const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view); - if (result != VK_SUCCESS || view == nullptr) { - EXIT("TextureCache: failed to create compatible render-target storage view," - " result=%d image_format=%d view_format=%d base=%u count=%u\n", - static_cast(result), static_cast(image->format), - static_cast(view_format), base_level, level_count); - } - image->storage_views.push_back( - {view_format, type, base_level, level_count, base_layer, layer_count, view}); - LOGF("TextureCache: created compatible render-target storage view: image_format=%d" - " view_format=%d base=%u count=%u extent=%ux%u\n", - static_cast(image->format), static_cast(view_format), base_level, level_count, - image->extent.width, image->extent.height); - return view; + return GetImageView(ctx, image, + {view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, base_level, level_count, + base_layer, layer_count, DstSel(4, 5, 6, 7), true}); } VkImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx, @@ -1595,101 +1462,41 @@ VkImageView TextureCache::GetStorageTextureSampledView(GraphicContext* info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array); } const auto view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled); - if (view_format != image->format && - !IsRgba8SrgbReinterpretation(image->format, view_format) && + if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) && !IsR32UintFloatReinterpretation(image->format, view_format)) { EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" " view_format=%d swizzle=0x%03x\n", static_cast(image->format), static_cast(view_format), info.swizzle); } - std::lock_guard lock(image->sampled_view_mutex); - for (const auto& cached: image->sampled_views) { - if (cached.format == view_format && cached.swizzle == info.swizzle && - cached.type == info.type && cached.base_level == info.base_level && - cached.level_count == info.view_levels) { - return cached.view; - } - } - - VkImageViewUsageCreateInfo usage {}; - usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; - usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - VkImageViewCreateInfo create {}; - create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create.pNext = &usage; - create.image = image->image; + VkImageViewType type = VK_IMAGE_VIEW_TYPE_MAX_ENUM; switch (shape) { - case StorageSampledViewShape::Image2D: create.viewType = VK_IMAGE_VIEW_TYPE_2D; break; - case StorageSampledViewShape::Image2DArray: - create.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - break; - case StorageSampledViewShape::Image3D: create.viewType = VK_IMAGE_VIEW_TYPE_3D; break; + case StorageSampledViewShape::Image2D: type = VK_IMAGE_VIEW_TYPE_2D; break; + case StorageSampledViewShape::Image2DArray: type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; break; + case StorageSampledViewShape::Image3D: type = VK_IMAGE_VIEW_TYPE_3D; break; case StorageSampledViewShape::Unsupported: EXIT("TextureCache: unsupported sampled storage-image view shape\n"); } - create.format = view_format; - create.components = TextureGetComponentMapping(info.swizzle); - create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - create.subresourceRange.baseMipLevel = info.base_level; - create.subresourceRange.levelCount = info.view_levels; - create.subresourceRange.baseArrayLayer = 0; - create.subresourceRange.layerCount = - shape == StorageSampledViewShape::Image2DArray ? info.depth : 1; - VkImageView view = nullptr; - const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view); - if (result != VK_SUCCESS || view == nullptr) { - EXIT("TextureCache: failed to create sampled view of storage texture, result=%d" - " image_format=%d view_format=%d swizzle=0x%03x type=%u base=%u count=%u\n", - static_cast(result), static_cast(image->format), - static_cast(view_format), info.swizzle, info.type, info.base_level, - info.view_levels); - } - image->sampled_views.push_back( - {view_format, info.swizzle, info.type, info.base_level, info.view_levels, view}); - LOGF("TextureCache: created sampled view of storage texture: image_format=%d" - " view_format=%d swizzle=0x%03x type=%u base=%u count=%u\n", - static_cast(image->format), static_cast(view_format), info.swizzle, info.type, - info.base_level, info.view_levels); - return view; + const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u; + return GetImageView(ctx, image, + {view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, info.base_level, + info.view_levels, 0, layer_count, info.swizzle}); } -VkImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx, - StorageTextureVulkanImage* image, - uint32_t base_level) { - if (base_level >= image->mip_levels) { +VkImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx, + StorageTextureVulkanImage* image, + uint32_t base_level) { + if (ctx == nullptr || image == nullptr || image->image == nullptr || + base_level >= (image != nullptr ? image->mip_levels : 0)) { EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n", static_cast(image), base_level, image != nullptr ? image->mip_levels : 0); } if (base_level == 0) { return image->image_view[VulkanImage::VIEW_DEFAULT]; } - std::lock_guard lock(image->storage_view_mutex); - for (const auto& cached: image->storage_views) { - if (cached.base_level == base_level) { - return cached.view; - } - } - VkImageViewCreateInfo create {}; - create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - create.image = image->image; - create.viewType = VK_IMAGE_VIEW_TYPE_2D; - create.format = image->format; - create.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - create.subresourceRange.baseMipLevel = base_level; - create.subresourceRange.levelCount = 1; - create.subresourceRange.baseArrayLayer = 0; - create.subresourceRange.layerCount = 1; - VkImageView view = nullptr; - const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view); - if (result != VK_SUCCESS || view == nullptr) { - EXIT("TextureCache: failed to create storage-texture mip view, result=%d level=%u\n", - static_cast(result), base_level); - } - image->storage_views.push_back({base_level, view}); - return view; + return GetImageView(ctx, image, + {image->format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, + base_level, 1, 0, 1, DstSel(4, 5, 6, 7), true}); } TextureCache::CachedImage* TextureCache::FindGpuReadbackPageCandidateLocked(uint64_t vaddr, @@ -4295,6 +4102,13 @@ void TextureCache::DeleteImageViews(GraphicContext* ctx, VulkanImage* image) { EXIT_IF(ctx == nullptr); EXIT_IF(image == nullptr); + for (auto& cached: image->view_cache.views) { + if (cached.view != nullptr) { + vkDestroyImageView(ctx->device, cached.view, nullptr); + cached.view = nullptr; + } + } + image->view_cache.views.clear(); for (auto& view: image->image_view) { if (view != nullptr) { vkDestroyImageView(ctx->device, view, nullptr); @@ -4310,23 +4124,6 @@ void TextureCache::DeleteGpuTexture(GraphicContext* ctx, GpuTextureVulkanImage* EXIT_IF(ctx == nullptr); EXIT_IF(image == nullptr); - if (image->type == VulkanImageType::StorageTexture) { - auto* storage = static_cast(image); - for (auto& cached: storage->sampled_views) { - if (cached.view != nullptr) { - vkDestroyImageView(ctx->device, cached.view, nullptr); - cached.view = nullptr; - } - } - storage->sampled_views.clear(); - for (auto& cached: storage->storage_views) { - if (cached.view != nullptr) { - vkDestroyImageView(ctx->device, cached.view, nullptr); - cached.view = nullptr; - } - } - storage->storage_views.clear(); - } DeleteImageViews(ctx, image); VulkanDeleteImage(ctx, image, mem); @@ -4360,20 +4157,6 @@ void TextureCache::DeleteRenderTexture(GraphicContext* ctx, RenderTextureVulkanI } } image->attachment_views.clear(); - for (auto& cached: image->sampled_views) { - if (cached.view != nullptr) { - vkDestroyImageView(ctx->device, cached.view, nullptr); - cached.view = nullptr; - } - } - image->sampled_views.clear(); - for (auto& cached: image->storage_views) { - if (cached.view != nullptr) { - vkDestroyImageView(ctx->device, cached.view, nullptr); - cached.view = nullptr; - } - } - image->storage_views.clear(); DeleteImageViews(ctx, image); VulkanDeleteImage(ctx, image, mem); delete image; diff --git a/src/graphics/host_gpu/renderer/textureCache.h b/src/graphics/host_gpu/renderer/textureCache.h index 83ee1c749..85af4fcb3 100644 --- a/src/graphics/host_gpu/renderer/textureCache.h +++ b/src/graphics/host_gpu/renderer/textureCache.h @@ -20,6 +20,7 @@ namespace Libs::Graphics { struct DepthStencilVulkanImage; struct GpuTextureVulkanImage; struct GraphicContext; +struct ImageViewInfo; struct RenderTextureVulkanImage; struct StorageTextureVulkanImage; struct VideoOutVulkanImage; @@ -69,12 +70,17 @@ public: DepthStencilVulkanImage* image, uint32_t base_layer, uint32_t layer_count); - [[nodiscard]] VkImageView GetRenderTargetSampledView(GraphicContext* ctx, - RenderTextureVulkanImage* image, - VkFormat view_format, int variant, - uint32_t base_level, uint32_t level_count, - VkImageViewType type, uint32_t base_layer, - uint32_t layer_count); + [[nodiscard]] VkImageView GetDepthTargetSampledView(GraphicContext* ctx, + DepthStencilVulkanImage* image, + VkFormat view_format, uint32_t swizzle, + uint32_t base_level, uint32_t level_count, + VkImageViewType type, uint32_t base_layer, + uint32_t layer_count); + [[nodiscard]] VkImageView GetSampledColorView(GraphicContext* ctx, VulkanImage* image, + VkFormat view_format, uint32_t swizzle, + uint32_t base_level, uint32_t level_count, + VkImageViewType type, uint32_t base_layer, + uint32_t layer_count); [[nodiscard]] VkImageView GetRenderTargetStorageView(GraphicContext* ctx, RenderTextureVulkanImage* image, VkFormat view_format, uint32_t base_level, @@ -83,13 +89,13 @@ public: [[nodiscard]] VkImageView GetStorageTextureSampledView(GraphicContext* ctx, StorageTextureVulkanImage* image, const ImageInfo& info); - [[nodiscard]] VkImageView GetStorageTextureStorageView(GraphicContext* ctx, + [[nodiscard]] VkImageView GetStorageTextureStorageView(GraphicContext* ctx, StorageTextureVulkanImage* image, - uint32_t base_level); - [[nodiscard]] DepthStencilVulkanImage* FindDepthTargetByRange(uint64_t vaddr, uint64_t size, - bool allow_containing_sampled = false); - [[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size); - [[nodiscard]] bool HasRangeOverlap(uint64_t vaddr, uint64_t size); + uint32_t base_level); + [[nodiscard]] DepthStencilVulkanImage* + FindDepthTargetByRange(uint64_t vaddr, uint64_t size, bool allow_containing_sampled = false); + [[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size); + [[nodiscard]] bool HasRangeOverlap(uint64_t vaddr, uint64_t size); [[nodiscard]] bool HasGpuModifiedRangeOverlap(uint64_t vaddr, uint64_t size); [[nodiscard]] bool HasGpuTargetPageOverlap(uint64_t vaddr, uint64_t size); void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1); @@ -126,6 +132,8 @@ private: bool gpu_modified = false; }; static void DeleteImageViews(GraphicContext* ctx, VulkanImage* image); + [[nodiscard]] VkImageView GetImageView(GraphicContext* ctx, VulkanImage* image, + const ImageViewInfo& info); [[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const; [[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size) const; diff --git a/src/graphics/presentation/window/swapchain.cpp b/src/graphics/presentation/window/swapchain.cpp index 86c58f9b9..f67f4328d 100644 --- a/src/graphics/presentation/window/swapchain.cpp +++ b/src/graphics/presentation/window/swapchain.cpp @@ -154,8 +154,9 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, VkExtent2D extent, VkFo return; } if (dst.image != nullptr) { + EXIT_IF(!dst.view_cache.views.empty()); VulkanDeleteImage(ctx, &dst, &dst.memory); - dst = VulkanImage(VulkanImageType::Unknown); + dst.memory = {}; } dst.extent = extent; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 87d287901..64af67109 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -491,6 +491,11 @@ void Require(const char *shader_name, const char *stage, bool value, } } +bool RejectUnexpectedPageFault(void *, PageFaultAccess, uint64_t, uint64_t, + PageFaultPhase) noexcept { + return false; +} + struct TestCase { const char *name = ""; std::vector code; @@ -1047,6 +1052,258 @@ public: static_cast(view_info.format)); } + void CheckRenderTargetViewCache() { + constexpr const char *name = "RenderTargetViewCache"; + VkImageCreateInfo image_info{}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + image_info.imageType = VK_IMAGE_TYPE_2D; + image_info.format = VK_FORMAT_R8G8B8A8_UNORM; + image_info.extent = {8, 8, 1}; + image_info.mipLevels = 2; + image_info.arrayLayers = 2; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkImage image_handle = VK_NULL_HANDLE; + RequireVk(name, "image", + vkCreateImage(m_device, &image_info, nullptr, &image_handle), + "vkCreateImage"); + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(m_device, image_handle, &requirements); + u32 memory_type = 0; + Require(name, "memory", + FindMemoryType(requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_type) || + FindMemoryType(requirements.memoryTypeBits, 0, &memory_type), + "no memory type for sampled render target"); + VkMemoryAllocateInfo allocation{}; + allocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocation.allocationSize = requirements.size; + allocation.memoryTypeIndex = memory_type; + VkDeviceMemory memory = VK_NULL_HANDLE; + RequireVk(name, "memory", + vkAllocateMemory(m_device, &allocation, nullptr, &memory), + "vkAllocateMemory"); + RequireVk(name, "memory", + vkBindImageMemory(m_device, image_handle, memory, 0), + "vkBindImageMemory"); + + GraphicContext context{}; + context.physical_device = m_physical_device; + context.device = m_device; + ResourceMutex resource_mutex; + PageManager page_manager(RejectUnexpectedPageFault, nullptr); + BufferCache buffer_cache(page_manager, resource_mutex); + TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + buffer_cache.SetTextureCache(texture_cache); + RenderTextureVulkanImage image; + image.image = image_handle; + image.format = image_info.format; + image.extent = {image_info.extent.width, image_info.extent.height}; + image.layers = 2; + image.mip_levels = 2; + + constexpr auto first_swizzle = DstSel(5, 1, 7, 0); + constexpr auto second_swizzle = DstSel(7, 4, 0, 1); + const auto first = texture_cache.GetSampledColorView( + &context, &image, image.format, first_swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto first_again = texture_cache.GetSampledColorView( + &context, &image, image.format, first_swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto second = texture_cache.GetSampledColorView( + &context, &image, image.format, second_swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto different_mip = texture_cache.GetSampledColorView( + &context, &image, image.format, first_swizzle, 1, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto different_layer = texture_cache.GetSampledColorView( + &context, &image, image.format, first_swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 1, 1); + const auto array_view = texture_cache.GetSampledColorView( + &context, &image, image.format, first_swizzle, 0, 1, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, 0, 2); + constexpr auto identity = DstSel(4, 5, 6, 7); + const auto native_format = texture_cache.GetSampledColorView( + &context, &image, image.format, identity, 0, 1, VK_IMAGE_VIEW_TYPE_2D, + 0, 1); + const auto reinterpreted_format = texture_cache.GetSampledColorView( + &context, &image, VK_FORMAT_R8G8B8A8_UINT, identity, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto storage = texture_cache.GetRenderTargetStorageView( + &context, &image, image.format, 0, 1, VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto storage_again = texture_cache.GetRenderTargetStorageView( + &context, &image, image.format, 0, 1, VK_IMAGE_VIEW_TYPE_2D, 0, 1); + Require(name, "cache identity", + first != VK_NULL_HANDLE && first_again == first && + second != VK_NULL_HANDLE && second != first && + different_mip != VK_NULL_HANDLE && different_mip != first && + different_layer != VK_NULL_HANDLE && different_layer != first && + array_view != VK_NULL_HANDLE && array_view != first && + native_format != VK_NULL_HANDLE && + reinterpreted_format != VK_NULL_HANDLE && + reinterpreted_format != native_format && + storage != VK_NULL_HANDLE && storage != native_format && + storage_again == storage && image.view_cache.views.size() == 8, + "view cache omitted usage, swizzle, format, type, mip, or layer " + "identity"); + + for (const auto &view : image.view_cache.views) { + vkDestroyImageView(m_device, view.view, nullptr); + } + image.view_cache.views.clear(); + vkDestroyImage(m_device, image_handle, nullptr); + vkFreeMemory(m_device, memory, nullptr); + std::printf("[host] %-32s ok\n", name); + } + + void CheckDepthTargetSampledViewCache() { + constexpr const char *name = "DepthTargetSampledViewCache"; + VkImageCreateInfo image_info{}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.imageType = VK_IMAGE_TYPE_2D; + image_info.format = VK_FORMAT_D32_SFLOAT; + image_info.extent = {8, 8, 1}; + image_info.mipLevels = 1; + image_info.arrayLayers = 2; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; + image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkImage image_handle = VK_NULL_HANDLE; + RequireVk(name, "image", + vkCreateImage(m_device, &image_info, nullptr, &image_handle), + "vkCreateImage"); + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(m_device, image_handle, &requirements); + u32 memory_type = 0; + Require(name, "memory", + FindMemoryType(requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_type) || + FindMemoryType(requirements.memoryTypeBits, 0, &memory_type), + "no memory type for sampled depth target"); + VkMemoryAllocateInfo allocation{}; + allocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocation.allocationSize = requirements.size; + allocation.memoryTypeIndex = memory_type; + VkDeviceMemory memory = VK_NULL_HANDLE; + RequireVk(name, "memory", + vkAllocateMemory(m_device, &allocation, nullptr, &memory), + "vkAllocateMemory"); + RequireVk(name, "memory", + vkBindImageMemory(m_device, image_handle, memory, 0), + "vkBindImageMemory"); + + GraphicContext context{}; + context.physical_device = m_physical_device; + context.device = m_device; + ResourceMutex resource_mutex; + PageManager page_manager(RejectUnexpectedPageFault, nullptr); + BufferCache buffer_cache(page_manager, resource_mutex); + TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + buffer_cache.SetTextureCache(texture_cache); + DepthStencilVulkanImage image; + image.image = image_handle; + image.format = image_info.format; + image.extent = {image_info.extent.width, image_info.extent.height}; + image.layers = image_info.arrayLayers; + image.mip_levels = image_info.mipLevels; + + constexpr auto replicated = DstSel(4, 4, 4, 4); + constexpr auto r001 = DstSel(4, 0, 0, 1); + const auto first = texture_cache.GetDepthTargetSampledView( + &context, &image, VK_FORMAT_R32_SFLOAT, replicated, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto first_again = texture_cache.GetDepthTargetSampledView( + &context, &image, VK_FORMAT_R32_SFLOAT, replicated, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto different_swizzle = texture_cache.GetDepthTargetSampledView( + &context, &image, VK_FORMAT_R32_SFLOAT, r001, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 0, 1); + const auto different_layer = texture_cache.GetDepthTargetSampledView( + &context, &image, VK_FORMAT_R32_SFLOAT, replicated, 0, 1, + VK_IMAGE_VIEW_TYPE_2D, 1, 1); + const auto array_view = texture_cache.GetDepthTargetSampledView( + &context, &image, VK_FORMAT_R32_SFLOAT, replicated, 0, 1, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, 0, 2); + Require(name, "cache identity", + first != VK_NULL_HANDLE && first_again == first && + different_swizzle != VK_NULL_HANDLE && + different_swizzle != first && + different_layer != VK_NULL_HANDLE && different_layer != first && + array_view != VK_NULL_HANDLE && array_view != first && + image.view_cache.views.size() == 4, + "sampled depth cache omitted swizzle, type, or layer identity"); + + for (const auto &view : image.view_cache.views) { + vkDestroyImageView(m_device, view.view, nullptr); + } + image.view_cache.views.clear(); + vkDestroyImage(m_device, image_handle, nullptr); + vkFreeMemory(m_device, memory, nullptr); + std::printf("[host] %-32s ok\n", name); + } + + void CheckVideoOutSampledViewCache() { + constexpr const char *name = "VideoOutSampledViewCache"; + auto backing = CreateImage2D(name, 8, 8, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT, + {}, 1, VK_IMAGE_LAYOUT_UNDEFINED); + + GraphicContext context{}; + context.physical_device = m_physical_device; + context.device = m_device; + ResourceMutex resource_mutex; + PageManager page_manager(RejectUnexpectedPageFault, nullptr); + BufferCache buffer_cache(page_manager, resource_mutex); + TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + buffer_cache.SetTextureCache(texture_cache); + VideoOutVulkanImage image; + image.image = backing.image; + image.format = backing.format; + image.extent = {backing.width, backing.height}; + image.layers = 1; + image.mip_levels = 1; + image.image_view[VulkanImage::VIEW_DEFAULT] = backing.view; + + constexpr auto identity = DstSel(4, 5, 6, 7); + constexpr auto bgra = DstSel(6, 5, 4, 7); + constexpr auto uncommon = DstSel(5, 1, 7, 0); + const auto default_view = texture_cache.GetSampledColorView( + &context, &image, image.format, identity, 0, 1, VK_IMAGE_VIEW_TYPE_2D, + 0, 1); + const auto bgra_view = texture_cache.GetSampledColorView( + &context, &image, image.format, bgra, 0, 1, VK_IMAGE_VIEW_TYPE_2D, 0, + 1); + const auto uncommon_view = texture_cache.GetSampledColorView( + &context, &image, image.format, uncommon, 0, 1, VK_IMAGE_VIEW_TYPE_2D, + 0, 1); + const auto uncommon_again = texture_cache.GetSampledColorView( + &context, &image, image.format, uncommon, 0, 1, VK_IMAGE_VIEW_TYPE_2D, + 0, 1); + Require(name, "cache identity", + default_view == backing.view && bgra_view != VK_NULL_HANDLE && + bgra_view != default_view && uncommon_view != VK_NULL_HANDLE && + uncommon_view != bgra_view && uncommon_again == uncommon_view && + image.view_cache.views.size() == 2, + "video-out sampled views did not use identity fast path and lazy " + "mappings"); + + for (const auto &view : image.view_cache.views) { + vkDestroyImageView(m_device, view.view, nullptr); + } + image.view_cache.views.clear(); + DestroyImage(&backing); + std::printf("[host] %-32s ok\n", name); + } + Buffer CreateStorageBuffer(const char *shader_name, const std::vector &initial, size_t dword_count) { @@ -8730,7 +8987,7 @@ void CheckReverseRenderTargetFormatContract() { if (std::strcmp(kind, "sampled") == 0) { (void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(4, 5, 6, 0)); + DstSel(4, 5, 6, 2)); } else if (std::strcmp(kind, "sampled-compatible-swizzle") == 0) { (void)SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, @@ -8759,10 +9016,10 @@ void CheckReverseRenderTargetFormatContract() { (void)SelectSampledColorView(VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_UNORM_PACK32, DstSel(6, 5, 4, 7)); - } else if (std::strcmp(kind, "sampled-abgr-format") == 0) { + } else if (std::strcmp(kind, "sampled-invalid-high") == 0) { (void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(7, 6, 5, 4)); + DstSel(7, 6, 5, 3)); } else if (std::strcmp(kind, "sampled-depth-format") == 0) { (void)SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R32_SFLOAT, DstSel(4, 4, 4, 4)); @@ -8811,95 +9068,135 @@ void CheckSampledColorViews() { Require("SampledColorViews", "identity", SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(4, 5, 6, 7)) == VulkanImage::VIEW_DEFAULT, + DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7), "RGBA did not select the identity view"); + uint32_t valid_swizzles = 0; + for (uint32_t swizzle = 0; swizzle <= 0xfffu; swizzle++) { + bool expected = true; + for (uint32_t channel = 0; channel < 4; channel++) { + const auto selector = GetDstSel(swizzle, channel); + if (selector == 2 || selector == 3) { + expected = false; + } + } + const bool valid = IsValidSampledColorSwizzle(swizzle); + const bool supported = IsSupportedSampledColorView( + VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, swizzle); + Require("SampledColorViews", "exhaustive read swizzle domain", + valid == expected && supported == expected, + "sampled swizzle validator disagreed with the PS5 selector domain"); + valid_swizzles += valid; + } + Require("SampledColorViews", "all PS5 read swizzles", + valid_swizzles == 1296 && + !IsValidSampledColorSwizzle(DstSel(4, 5, 6, 2)) && + !IsValidSampledColorSwizzle(DstSel(4, 5, 6, 3)) && + !IsValidSampledColorSwizzle(0x1000), + "valid PS5 sampled mappings were rejected or reserved selectors were " + "admitted"); + const auto arbitrary = DstSel(5, 1, 7, 0); + const auto components = TextureGetComponentMapping(arbitrary); + Require("SampledColorViews", "generic Vulkan component mapping", + SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_UNORM, + arbitrary) == arbitrary && + components.r == VK_COMPONENT_SWIZZLE_G && + components.g == VK_COMPONENT_SWIZZLE_ONE && + components.b == VK_COMPONENT_SWIZZLE_A && + components.a == VK_COMPONENT_SWIZZLE_ZERO, + "arbitrary valid sampled mapping did not use the generic view path"); Require("SampledColorViews", "R8 R001", SelectSampledColorView(VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, - DstSel(4, 0, 0, 1)) == VulkanImage::VIEW_R001, + DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "R8 did not select its R001 view"); + Require("SampledColorViews", "R8 000R", + SelectSampledColorView(VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, + DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4), + "R8 did not select its 000R component-mapped view"); Require("SampledColorViews", "R16G16 RG01", SelectSampledColorView(VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16_SFLOAT, - DstSel(4, 5, 0, 1)) == VulkanImage::VIEW_RG01, + DstSel(4, 5, 0, 1)) == DstSel(4, 5, 0, 1), "R16G16 did not select its RG01 view"); Require("SampledColorViews", "alpha one", SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(4, 5, 6, 1)) == VulkanImage::VIEW_RGB1, + DstSel(4, 5, 6, 1)) == DstSel(4, 5, 6, 1), "RGB1 did not select the alpha-one view"); Require("SampledColorViews", "mutable BGRA target", SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(6, 5, 4, 7)) == VulkanImage::VIEW_BGRA_TO_RGBA, + DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7), "BGRA target did not select the exact RGBA/BGRA mutable view"); - Require("SampledColorViews", "mutable sRGB view of UNORM BGRA target", - SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, - VK_FORMAT_R8G8B8A8_SRGB, - DstSel(6, 5, 4, 7)) == VulkanImage::VIEW_BGRA_TO_RGBA, - "UNORM BGRA target did not select its compatible sRGB RGBA sampled view"); + Require( + "SampledColorViews", "mutable sRGB view of UNORM BGRA target", + SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, + DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7), + "UNORM BGRA target did not select its compatible sRGB RGBA sampled view"); Require("SampledColorViews", "mutable sRGB BGRA target", BgraToRgbaSampledViewFormat(VK_FORMAT_B8G8R8A8_SRGB) == VK_FORMAT_R8G8B8A8_SRGB && SelectSampledColorView(VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_R8G8B8A8_SRGB, - DstSel(6, 5, 4, 7)) == - VulkanImage::VIEW_BGRA_TO_RGBA, + DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7), "sRGB BGRA target did not select its matching mutable RGBA view"); + constexpr auto colorspace_swizzle = DstSel(5, 1, 7, 0); + Require("SampledColorViews", "mutable sRGB/UNORM views", + SelectSampledColorView(VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_R8G8B8A8_UNORM, + DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7) && + SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_B8G8R8A8_SRGB, + colorspace_swizzle) == colorspace_swizzle, + "same-order mutable sRGB/UNORM sampled views were rejected"); Require("SampledColorViews", "mutable packed RGB10 view", BgraToRgbaSampledViewFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32) == VK_FORMAT_A2B10G10R10_UNORM_PACK32 && SelectSampledColorView(VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32, - DstSel(6, 5, 4, 7)) == - VulkanImage::VIEW_BGRA_TO_RGBA, + DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7), "packed RGB10 target did not select its matching mutable channel-order view"); Require("SampledColorViews", "reverse RGBA16F sampled view", SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT, - DstSel(7, 6, 5, 4)) == VulkanImage::VIEW_ABGR, + DstSel(7, 6, 5, 4)) == DstSel(7, 6, 5, 4), "reverse RGBA16F target did not select its reciprocal ABGR sampled view"); Require("SampledColorViews", "mutable integer-class views", SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16B16A16_UINT, - DstSel(4, 5, 6, 7)) == VulkanImage::VIEW_DEFAULT && + DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7) && SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UINT, - DstSel(4, 5, 6, 7)) == VulkanImage::VIEW_DEFAULT && + DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7) && SelectSampledColorView(VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_UNORM, - DstSel(4, 5, 6, 7)) == VulkanImage::VIEW_DEFAULT, + DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7), "compatible integer render-target sampled view was rejected"); Require("SampledColorViews", "D32 depth target", SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R32_SFLOAT, - DstSel(4, 4, 4, 4)) == - VulkanImage::VIEW_DEPTH_TEXTURE, + DstSel(4, 4, 4, 4)) == DstSel(4, 4, 4, 4), "D32 depth target did not select its depth-aspect view"); Require("SampledColorViews", "D16 R000 depth target", SelectSampledDepthView(VK_FORMAT_D16_UNORM, VK_FORMAT_R16_UNORM, - DstSel(4, 0, 0, 0)) == - VulkanImage::VIEW_R000, + DstSel(4, 0, 0, 0)) == DstSel(4, 0, 0, 0), "D16 depth target did not select its R000 depth-aspect view"); Require("SampledColorViews", "D16S8 R001 depth target", SelectSampledDepthView(VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_R16_UNORM, - DstSel(4, 0, 0, 1)) == - VulkanImage::VIEW_R001, + DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "D16S8 depth target did not select its R001 depth-aspect view"); Require("SampledColorViews", "promoted D24S8 R001 depth target", SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R16_UNORM, - DstSel(4, 0, 0, 1)) == - VulkanImage::VIEW_R001, + DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "D24S8 host fallback did not preserve the guest R16 depth view"); Require("SampledColorViews", "promoted D32S8 R001 depth target", SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R16_UNORM, - DstSel(4, 0, 0, 1)) == - VulkanImage::VIEW_R001, + DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "D32S8 host fallback did not preserve the guest R16 depth view"); Require("SampledColorViews", "D32S8 R001 depth target", SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R32_SFLOAT, - DstSel(4, 0, 0, 1)) == - VulkanImage::VIEW_R001, + DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "D32S8 depth target did not select its R001 depth-aspect view"); Require("SampledColorViews", "storage identity", SelectStorageColorView(VK_FORMAT_R8G8B8A8_UNORM, @@ -8981,7 +9278,7 @@ void CheckSampledColorViews() { {"sampled", "sampled-compatible-swizzle", "sampled-compatible-reverse", "sampled-compatible-colorspace", "sampled-compatible-snorm", "sampled-rgb10-swizzle", - "sampled-rgb10-reverse", "sampled-abgr-format", "sampled-depth-format", + "sampled-rgb10-reverse", "sampled-invalid-high", "sampled-depth-format", "sampled-depth-swizzle", "storage", "storage-format", "storage-compatible-swizzle", "storage-abgr", "storage-kind", "storage-no-write", "storage-atomic", "storage-compare", "storage-mip", @@ -9069,6 +9366,50 @@ void CheckSampledDepthResource() { std::printf("[host] %-32s ok\n", "SampledDepthResource"); } +void CheckSampledVideoOutView() { + ShaderRecompiler::IR::ImageResource resource{}; + resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; + resource.read = true; + + ShaderTextureResource descriptor{}; + descriptor.fields[3] = Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) + << 28u; + VulkanImage image{VulkanImageType::VideoOut}; + image.layers = 1; + Require("SampledVideoOutView", "basic 2D", + IsSupportedSampledVideoOutView(resource, descriptor, image), + "basic 2D video-out view was rejected"); + + const auto basic_resource = resource; + resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; + const bool rejects_array_resource = + !IsSupportedSampledVideoOutView(resource, descriptor, image); + resource = basic_resource; + descriptor.fields[3] = + Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) << 28u; + const bool rejects_array_descriptor = + !IsSupportedSampledVideoOutView(resource, descriptor, image); + descriptor.fields[3] = Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) + << 28u; + descriptor.fields[4] = 1u << 16u; + const bool rejects_base_layer = + !IsSupportedSampledVideoOutView(resource, descriptor, image); + descriptor.fields[4] = 1u; + const bool rejects_layer_count = + !IsSupportedSampledVideoOutView(resource, descriptor, image); + descriptor.fields[4] = 0; + image.layers = 2; + const bool rejects_layered_image = + !IsSupportedSampledVideoOutView(resource, descriptor, image); + Require("SampledVideoOutView", "array hard failures", + rejects_array_resource && rejects_array_descriptor && + rejects_base_layer && rejects_layer_count && + rejects_layered_image, + "unsupported layered video-out view was accepted"); + std::printf("[host] %-32s ok\n", "SampledVideoOutView"); +} + void CheckSampledDepthDescriptor() { ShaderTextureResource descriptor{{0x00eb0900u, 0xc1600000u, 0x00bcc14fu, 0x91800924u, 0x00000000u, 0x00700000u, @@ -12358,6 +12699,14 @@ int main(int argc, char **argv) { } if (argc == 2 && std::strcmp(argv[1], "--image-view-only") == 0) { CheckSampledColorViews(); + CheckSampledVideoOutView(); + return 0; + } + if (argc == 2 && std::strcmp(argv[1], "--image-view-cache-only") == 0) { + VulkanHarness vulkan; + vulkan.CheckRenderTargetViewCache(); + vulkan.CheckDepthTargetSampledViewCache(); + vulkan.CheckVideoOutSampledViewCache(); return 0; } if (argc == 2 && std::strcmp(argv[1], "--sampled-depth-resource-only") == 0) { @@ -12404,7 +12753,8 @@ int main(int argc, char **argv) { std::strcmp(argv[1], "--storage-texture-descriptor-death") == 0) { RunStorageTextureDescriptorDeathCase(argv[2]); } - if (argc == 3 && std::strcmp(argv[1], "--storage-texture-access-death") == 0) { + if (argc == 3 && + std::strcmp(argv[1], "--storage-texture-access-death") == 0) { RunStorageTextureAccessDeathCase(argv[2]); } if (argc == 3 && std::strcmp(argv[1], "--meta-overlap-death") == 0) { @@ -12415,6 +12765,7 @@ int main(int argc, char **argv) { } CheckReverseRenderTargetFormatContract(); CheckSampledColorViews(); + CheckSampledVideoOutView(); CheckSampledDepthResource(); CheckSampledDepthDescriptor(); CheckBufferCacheRangeMerge(); @@ -12456,6 +12807,9 @@ int main(int argc, char **argv) { VulkanHarness vulkan; vulkan.CheckMutableStorageSrgbView(); vulkan.CheckMutableRenderTargetBgraStorageView(); + vulkan.CheckRenderTargetViewCache(); + vulkan.CheckDepthTargetSampledViewCache(); + vulkan.CheckVideoOutSampledViewCache(); const auto tests = MakeCases(); const auto graphics_tests = MakeGraphicsCases(); CheckOpcodeCoverage(tests, graphics_tests);