centralize swizzles

This commit is contained in:
nmzik
2026-07-18 01:41:44 +02:00
parent 8a6afc428d
commit 94f85bc98a
8 changed files with 673 additions and 507 deletions
+34 -62
View File
@@ -66,32 +66,42 @@ enum class VulkanImageType {
RenderTexture 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<CachedImageView> views;
ImageViewCache() = default;
KYTY_CLASS_NO_COPY(ImageViewCache);
};
struct VulkanImage { struct VulkanImage {
static constexpr int VIEW_MAX = 22; static constexpr int VIEW_MAX = 4;
static constexpr int VIEW_DEFAULT = 0; static constexpr int VIEW_DEFAULT = 0;
static constexpr int VIEW_BGRA = 1; static constexpr int VIEW_DEFAULT_ARRAY = 1;
static constexpr int VIEW_DEPTH_TEXTURE = 2; static constexpr int VIEW_STORAGE = 2;
static constexpr int VIEW_R001 = 3; static constexpr int VIEW_STORAGE_ARRAY = 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;
explicit VulkanImage(VulkanImageType type): type(type) {} explicit VulkanImage(VulkanImageType type): type(type) {}
KYTY_CLASS_NO_COPY(VulkanImage);
VulkanImageType type = VulkanImageType::Unknown; VulkanImageType type = VulkanImageType::Unknown;
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
@@ -103,6 +113,7 @@ struct VulkanImage {
VkImageView image_view[VIEW_MAX] = {}; VkImageView image_view[VIEW_MAX] = {};
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
Graphics::VulkanMemory memory; Graphics::VulkanMemory memory;
ImageViewCache view_cache;
}; };
struct VideoOutVulkanImage: public VulkanImage { struct VideoOutVulkanImage: public VulkanImage {
@@ -130,23 +141,7 @@ struct TextureVulkanImage: public GpuTextureVulkanImage {
}; };
struct StorageTextureVulkanImage: 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) {} StorageTextureVulkanImage(): GpuTextureVulkanImage(VulkanImageType::StorageTexture) {}
std::mutex sampled_view_mutex;
std::vector<SampledView> sampled_views;
std::mutex storage_view_mutex;
std::vector<StorageView> storage_views;
}; };
struct RenderTextureVulkanImage: public VulkanImage { struct RenderTextureVulkanImage: public VulkanImage {
@@ -157,33 +152,10 @@ struct RenderTextureVulkanImage: public VulkanImage {
uint32_t layer_count = 1; uint32_t layer_count = 1;
VkImageView view = nullptr; 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) {} RenderTextureVulkanImage(): VulkanImage(VulkanImageType::RenderTexture) {}
VkImageView render_view[16] = {}; VkImageView render_view[16] = {};
std::mutex attachment_view_mutex; std::mutex attachment_view_mutex;
std::vector<AttachmentView> attachment_views; std::vector<AttachmentView> attachment_views;
std::mutex sampled_view_mutex;
std::vector<SampledView> sampled_views;
std::mutex storage_view_mutex;
std::vector<StorageView> storage_views;
}; };
struct VulkanBuffer { struct VulkanBuffer {
+37 -18
View File
@@ -84,14 +84,6 @@ static int SampledArrayViewIndex(const VulkanImage* image, int view_index) {
switch (view_index) { switch (view_index) {
case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY; 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; 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, bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
const VulkanImage& image) { const VulkanImage& image) {
const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u; const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u;
@@ -588,7 +590,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
image = nullptr; image = nullptr;
} else { } else {
ValidateDepthTargetBinding(resource, descriptor, image, view_format, size.size); 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<DepthStencilVulkanImage*>(image),
view_format, swizzle, 0, 1, VK_IMAGE_VIEW_TYPE_2D, 0, 1);
} }
} else { } else {
if (!(storage ? IsSupportedStorageImageResource(resource) if (!(storage ? IsSupportedStorageImageResource(resource)
@@ -611,19 +615,17 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
image->mip_levels, base_level, descriptor.BaseArray5(), image->mip_levels, base_level, descriptor.BaseArray5(),
static_cast<uint32_t>(type)); static_cast<uint32_t>(type));
} }
view = storage ? SelectStorageColorView(image->format, view_format, swizzle)
: SelectSampledColorView(image->format, view_format, swizzle);
if (storage) { if (storage) {
view = SelectStorageColorView(image->format, view_format, swizzle);
image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView( image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView(
g_render_ctx->GetGraphicCtx(), g_render_ctx->GetGraphicCtx(),
static_cast<RenderTextureVulkanImage*>(image), view_format, base_level, static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
view_levels, target_view.type, target_view.base_layer, view_levels, target_view.type, target_view.base_layer,
target_view.layer_count); target_view.layer_count);
} else { } else {
image_view = g_render_ctx->GetTextureCache()->GetRenderTargetSampledView( image_view = g_render_ctx->GetTextureCache()->GetSampledColorView(
g_render_ctx->GetGraphicCtx(), g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level,
static_cast<RenderTextureVulkanImage*>(image), view_format, view, view_levels, target_view.type, target_view.base_layer,
base_level, view_levels, target_view.type, target_view.base_layer,
target_view.layer_count); target_view.layer_count);
} }
} }
@@ -661,10 +663,27 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
view = VulkanImage::VIEW_STORAGE; view = VulkanImage::VIEW_STORAGE;
g_render_ctx->GetTextureCache()->MarkGpuWritten(image); g_render_ctx->GetTextureCache()->MarkGpuWritten(image);
} else { } else {
image = video.image; const bool exact =
if (swizzle == DstSel(6, 5, 4, 7)) { IsSupportedSampledVideoOutView(resource, descriptor, *video.image) &&
view = VulkanImage::VIEW_BGRA; 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<uint32_t>(resource.kind),
static_cast<uint32_t>(resource.dimension),
static_cast<int>(video.image->format), static_cast<int>(view_format),
swizzle, width, height, video.image->extent.width,
video.image->extent.height, depth, levels, base_level, view_levels,
static_cast<uint32_t>(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);
} }
} }
} }
@@ -12,6 +12,9 @@ struct VulkanImage;
[[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, [[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
const VulkanImage& image); const VulkanImage& image);
[[nodiscard]] bool
IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor, const VulkanImage& image);
void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& resource, void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor, uint64_t size); const ShaderTextureResource& descriptor, uint64_t size);
void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
+55 -29
View File
@@ -86,41 +86,67 @@ namespace Libs::Graphics {
return view_format == BgraSrgbStorageViewFormat(image_format) && swizzle == DstSel(6, 5, 4, 7); return view_format == BgraSrgbStorageViewFormat(image_format) && swizzle == DstSel(6, 5, 4, 7);
} }
[[nodiscard]] inline int SelectSampledColorView(VkFormat image_format, VkFormat view_format, [[nodiscard]] inline bool IsValidSampledColorSwizzle(uint32_t swizzle) noexcept {
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) || if ((IsRgba16UintFloatReinterpretation(image_format, view_format) ||
IsRgba8UnormUintReinterpretation(image_format, view_format)) && IsRgba8UnormUintReinterpretation(image_format, view_format)) &&
swizzle == DstSel(4, 5, 6, 7)) { swizzle == DstSel(4, 5, 6, 7)) {
return VulkanImage::VIEW_DEFAULT; return true;
} }
if (image_format == view_format) { return IsBgraToRgbaSampledView(image_format, view_format) &&
switch (swizzle) { swizzle == DstSel(6, 5, 4, 7);
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; [[nodiscard]] inline uint32_t SelectSampledColorView(VkFormat image_format, VkFormat view_format,
case DstSel(4, 5, 6, 1): return VulkanImage::VIEW_RGB1; uint32_t swizzle) noexcept {
default: break; if (IsSupportedSampledColorView(image_format, view_format, swizzle)) {
} return swizzle;
}
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;
} }
UnsupportedColorView("sampled", image_format, view_format, swizzle); UnsupportedColorView("sampled", image_format, view_format, swizzle);
} }
[[nodiscard]] inline int SelectSampledDepthView(VkFormat image_format, VkFormat view_format, [[nodiscard]] inline bool IsSupportedSampledDepthView(VkFormat image_format, VkFormat view_format,
uint32_t swizzle) noexcept { uint32_t swizzle) noexcept {
if (IsSupportedSampledDepthFormat(image_format, view_format)) { if (!IsSupportedSampledDepthFormat(image_format, view_format)) {
switch (swizzle) { return false;
case DstSel(4, 4, 4, 4): return VulkanImage::VIEW_DEPTH_TEXTURE; }
case DstSel(4, 0, 0, 0): return VulkanImage::VIEW_R000; switch (swizzle) {
case DstSel(4, 0, 0, 1): return VulkanImage::VIEW_R001; case DstSel(4, 4, 4, 4):
default: break; 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", EXIT("unsupported sampled depth image view: image_format=%d view_format=%d swizzle=0x%03x\n",
static_cast<int>(image_format), static_cast<int>(view_format), swizzle); static_cast<int>(image_format), static_cast<int>(view_format), swizzle);
@@ -134,8 +160,8 @@ IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resou
!resource.written && !resource.atomic; !resource.written && !resource.atomic;
} }
[[nodiscard]] inline bool IsSupportedSampledDepthUintResource( [[nodiscard]] inline bool
const ShaderRecompiler::IR::ImageResource& resource) noexcept { IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
return resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint && return resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint &&
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D &&
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.read && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.read &&
+133 -350
View File
@@ -887,32 +887,11 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY, CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 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) { if (image->layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 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_ARRAY); 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)) { if (FormatSupportsStorage(ctx, image->format)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, VK_COMPONENT_SWIZZLE_IDENTITY, 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); 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); CreateRenderAttachmentViews(ctx, image);
} }
@@ -940,24 +912,12 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY, CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, 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, if ((image->format == VK_FORMAT_R8G8B8A8_SRGB || image->format == VK_FORMAT_B8G8R8A8_SRGB) &&
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) &&
FormatSupportsStorage(ctx, VK_FORMAT_R8G8B8A8_UINT)) { 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_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_IMAGE_VIEW_TYPE_2D,
VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_UINT, VK_IMAGE_USAGE_STORAGE_BIT, 1);
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,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
0, 0, 1, 1); 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, DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info,
@@ -1366,147 +1289,128 @@ VkImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext*
return view; return view;
} }
VkImageView TextureCache::GetRenderTargetSampledView(GraphicContext* ctx, VkImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image,
RenderTextureVulkanImage* image, const ImageViewInfo& info) {
VkFormat view_format, int variant, const bool supported_type = info.type == VK_IMAGE_VIEW_TYPE_2D ||
uint32_t base_level, uint32_t level_count, info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ||
VkImageViewType type, uint32_t base_layer, info.type == VK_IMAGE_VIEW_TYPE_3D;
uint32_t layer_count) { const bool valid_shape =
if (ctx == nullptr || image == nullptr || image->image == nullptr || base_level >= 16 || (info.type == VK_IMAGE_VIEW_TYPE_2D && info.layer_count == 1) ||
view_format == VK_FORMAT_UNDEFINED || level_count == 0 || info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ||
base_level + level_count > image->mip_levels || layer_count == 0 || (info.type == VK_IMAGE_VIEW_TYPE_3D && info.base_layer == 0 && info.layer_count == 1);
base_layer >= image->layers || layer_count > image->layers - base_layer || if (ctx == nullptr || image == nullptr || image->image == nullptr ||
(type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) || info.format == VK_FORMAT_UNDEFINED || info.aspect == 0 || info.level_count == 0 ||
(type == VK_IMAGE_VIEW_TYPE_2D && layer_count != 1)) { info.base_level >= (image != nullptr ? image->mip_levels : 0) ||
EXIT("TextureCache: invalid render-target sampled view, image=%p variant=%d" info.level_count > image->mip_levels - info.base_level || info.layer_count == 0 ||
" view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer ||
static_cast<const void*>(image), variant, static_cast<int>(view_format), base_level, !supported_type || !valid_shape) {
level_count, base_layer, layer_count, static_cast<int>(type), EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x"
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); " swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d storage=%d"
} " image_levels=%u image_layers=%u\n",
const bool compatible_variant_format = static_cast<const void*>(image), static_cast<int>(info.format), info.aspect,
view_format == image->format || (variant == VulkanImage::VIEW_BGRA_TO_RGBA && info.swizzle, info.base_level, info.level_count, info.base_layer, info.layer_count,
IsBgraToRgbaSampledView(image->format, view_format)) || static_cast<int>(info.type), info.is_storage, image != nullptr ? image->mip_levels : 0,
(variant == VulkanImage::VIEW_DEFAULT && image != nullptr ? image->layers : 0);
(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<int>(image->format), static_cast<int>(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];
} }
std::lock_guard lock(image->sampled_view_mutex); auto& cache = image->view_cache;
for (const auto& cached: image->sampled_views) { std::lock_guard lock(cache.mutex);
if (cached.format == view_format && cached.type == type && cached.variant == variant && for (const auto& cached: cache.views) {
cached.base_level == base_level && cached.level_count == level_count && if (cached.info == info) {
cached.base_layer == base_layer && cached.layer_count == layer_count) {
return cached.view; 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 {}; VkImageViewUsageCreateInfo usage {};
usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT; usage.usage = info.is_storage ? VK_IMAGE_USAGE_STORAGE_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; VkImageViewCreateInfo create {};
create.pNext = &usage; create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
create.image = image->image; create.pNext = &usage;
create.viewType = type; create.image = image->image;
create.format = view_format; create.viewType = info.type;
create.components = components; create.format = info.format;
create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; create.components =
create.subresourceRange.baseMipLevel = base_level; info.is_storage ? VkComponentMapping {} : TextureGetComponentMapping(info.swizzle);
create.subresourceRange.levelCount = level_count; create.subresourceRange.aspectMask = info.aspect;
create.subresourceRange.baseArrayLayer = base_layer; create.subresourceRange.baseMipLevel = info.base_level;
create.subresourceRange.layerCount = layer_count; create.subresourceRange.levelCount = info.level_count;
create.subresourceRange.baseArrayLayer = info.base_layer;
create.subresourceRange.layerCount = info.layer_count;
VkImageView view = nullptr; VkImageView view = nullptr;
const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view); const auto result = vkCreateImageView(ctx->device, &create, nullptr, &view);
if (result != VK_SUCCESS || view == nullptr) { if (result != VK_SUCCESS || view == nullptr) {
EXIT("TextureCache: failed to create render-target sampled subresource view," EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d"
" result=%d view_format=%d variant=%d mip=%u+%u layer=%u+%u type=%d\n", " aspect=0x%x swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d storage=%d\n",
static_cast<int>(result), static_cast<int>(view_format), variant, base_level, static_cast<int>(result), static_cast<int>(info.format), info.aspect, info.swizzle,
level_count, base_layer, layer_count, static_cast<int>(type)); info.base_level, info.level_count, info.base_layer, info.layer_count,
static_cast<int>(info.type), info.is_storage);
} }
image->sampled_views.push_back( cache.views.push_back({info, view});
{view_format, type, base_level, level_count, base_layer, layer_count, variant, view});
return 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<const void*>(image),
image != nullptr ? static_cast<int>(image->format) : VK_FORMAT_UNDEFINED,
static_cast<int>(view_format), swizzle, base_level, level_count, base_layer,
layer_count, static_cast<int>(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<const void*>(image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(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, VkImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx,
RenderTextureVulkanImage* image, RenderTextureVulkanImage* image,
VkFormat view_format, uint32_t base_level, VkFormat view_format, uint32_t base_level,
uint32_t level_count, VkImageViewType type, uint32_t level_count, VkImageViewType type,
uint32_t base_layer, uint32_t layer_count) { uint32_t base_layer, uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == VK_FORMAT_UNDEFINED || level_count == 0 || view_format == VK_FORMAT_UNDEFINED ||
base_level + level_count > image->mip_levels || layer_count == 0 || (type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
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 storage view, image=%p view_format=%d" 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", " mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(view_format), base_level, static_cast<const void*>(image), static_cast<int>(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)) { if (compatible && !FormatSupportsStorage(ctx, view_format)) {
EXIT("TextureCache: compatible render-target storage format lacks storage support," EXIT("TextureCache: compatible render-target storage format lacks storage support,"
" image_format=%d view_format=%d base=%u count=%u\n", " image_format=%d view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level, static_cast<int>(image->format), static_cast<int>(view_format), base_level,
level_count); level_count);
} }
return GetImageView(ctx, image,
VkImageViewUsageCreateInfo usage {}; {view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, base_level, level_count,
usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; base_layer, layer_count, DstSel(4, 5, 6, 7), true});
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<int>(result), static_cast<int>(image->format),
static_cast<int>(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<int>(image->format), static_cast<int>(view_format), base_level, level_count,
image->extent.width, image->extent.height);
return view;
} }
VkImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx, 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); info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array);
} }
const auto view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled); const auto view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled);
if (view_format != image->format && if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) &&
!IsRgba8SrgbReinterpretation(image->format, view_format) &&
!IsR32UintFloatReinterpretation(image->format, view_format)) { !IsR32UintFloatReinterpretation(image->format, view_format)) {
EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d"
" view_format=%d swizzle=0x%03x\n", " view_format=%d swizzle=0x%03x\n",
static_cast<int>(image->format), static_cast<int>(view_format), info.swizzle); static_cast<int>(image->format), static_cast<int>(view_format), info.swizzle);
} }
std::lock_guard lock(image->sampled_view_mutex); VkImageViewType type = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
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;
switch (shape) { switch (shape) {
case StorageSampledViewShape::Image2D: create.viewType = VK_IMAGE_VIEW_TYPE_2D; break; case StorageSampledViewShape::Image2D: type = VK_IMAGE_VIEW_TYPE_2D; break;
case StorageSampledViewShape::Image2DArray: case StorageSampledViewShape::Image2DArray: type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; break;
create.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; case StorageSampledViewShape::Image3D: type = VK_IMAGE_VIEW_TYPE_3D; break;
break;
case StorageSampledViewShape::Image3D: create.viewType = VK_IMAGE_VIEW_TYPE_3D; break;
case StorageSampledViewShape::Unsupported: case StorageSampledViewShape::Unsupported:
EXIT("TextureCache: unsupported sampled storage-image view shape\n"); EXIT("TextureCache: unsupported sampled storage-image view shape\n");
} }
create.format = view_format; const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u;
create.components = TextureGetComponentMapping(info.swizzle); return GetImageView(ctx, image,
create.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; {view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, info.base_level,
create.subresourceRange.baseMipLevel = info.base_level; info.view_levels, 0, layer_count, info.swizzle});
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<int>(result), static_cast<int>(image->format),
static_cast<int>(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<int>(image->format), static_cast<int>(view_format), info.swizzle, info.type,
info.base_level, info.view_levels);
return view;
} }
VkImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx, VkImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image, StorageTextureVulkanImage* image,
uint32_t base_level) { uint32_t base_level) {
if (base_level >= image->mip_levels) { 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", EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n",
static_cast<const void*>(image), base_level, image != nullptr ? image->mip_levels : 0); static_cast<const void*>(image), base_level, image != nullptr ? image->mip_levels : 0);
} }
if (base_level == 0) { if (base_level == 0) {
return image->image_view[VulkanImage::VIEW_DEFAULT]; return image->image_view[VulkanImage::VIEW_DEFAULT];
} }
std::lock_guard lock(image->storage_view_mutex); return GetImageView(ctx, image,
for (const auto& cached: image->storage_views) { {image->format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT,
if (cached.base_level == base_level) { base_level, 1, 0, 1, DstSel(4, 5, 6, 7), true});
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<int>(result), base_level);
}
image->storage_views.push_back({base_level, view});
return view;
} }
TextureCache::CachedImage* TextureCache::FindGpuReadbackPageCandidateLocked(uint64_t vaddr, TextureCache::CachedImage* TextureCache::FindGpuReadbackPageCandidateLocked(uint64_t vaddr,
@@ -4295,6 +4102,13 @@ void TextureCache::DeleteImageViews(GraphicContext* ctx, VulkanImage* image) {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(image == 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) { for (auto& view: image->image_view) {
if (view != nullptr) { if (view != nullptr) {
vkDestroyImageView(ctx->device, view, nullptr); vkDestroyImageView(ctx->device, view, nullptr);
@@ -4310,23 +4124,6 @@ void TextureCache::DeleteGpuTexture(GraphicContext* ctx, GpuTextureVulkanImage*
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr); EXIT_IF(image == nullptr);
if (image->type == VulkanImageType::StorageTexture) {
auto* storage = static_cast<StorageTextureVulkanImage*>(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); DeleteImageViews(ctx, image);
VulkanDeleteImage(ctx, image, mem); VulkanDeleteImage(ctx, image, mem);
@@ -4360,20 +4157,6 @@ void TextureCache::DeleteRenderTexture(GraphicContext* ctx, RenderTextureVulkanI
} }
} }
image->attachment_views.clear(); 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); DeleteImageViews(ctx, image);
VulkanDeleteImage(ctx, image, mem); VulkanDeleteImage(ctx, image, mem);
delete image; delete image;
+20 -12
View File
@@ -20,6 +20,7 @@ namespace Libs::Graphics {
struct DepthStencilVulkanImage; struct DepthStencilVulkanImage;
struct GpuTextureVulkanImage; struct GpuTextureVulkanImage;
struct GraphicContext; struct GraphicContext;
struct ImageViewInfo;
struct RenderTextureVulkanImage; struct RenderTextureVulkanImage;
struct StorageTextureVulkanImage; struct StorageTextureVulkanImage;
struct VideoOutVulkanImage; struct VideoOutVulkanImage;
@@ -69,12 +70,17 @@ public:
DepthStencilVulkanImage* image, DepthStencilVulkanImage* image,
uint32_t base_layer, uint32_t base_layer,
uint32_t layer_count); uint32_t layer_count);
[[nodiscard]] VkImageView GetRenderTargetSampledView(GraphicContext* ctx, [[nodiscard]] VkImageView GetDepthTargetSampledView(GraphicContext* ctx,
RenderTextureVulkanImage* image, DepthStencilVulkanImage* image,
VkFormat view_format, int variant, VkFormat view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count, uint32_t base_level, uint32_t level_count,
VkImageViewType type, uint32_t base_layer, VkImageViewType type, uint32_t base_layer,
uint32_t layer_count); 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, [[nodiscard]] VkImageView GetRenderTargetStorageView(GraphicContext* ctx,
RenderTextureVulkanImage* image, RenderTextureVulkanImage* image,
VkFormat view_format, uint32_t base_level, VkFormat view_format, uint32_t base_level,
@@ -83,13 +89,13 @@ public:
[[nodiscard]] VkImageView GetStorageTextureSampledView(GraphicContext* ctx, [[nodiscard]] VkImageView GetStorageTextureSampledView(GraphicContext* ctx,
StorageTextureVulkanImage* image, StorageTextureVulkanImage* image,
const ImageInfo& info); const ImageInfo& info);
[[nodiscard]] VkImageView GetStorageTextureStorageView(GraphicContext* ctx, [[nodiscard]] VkImageView GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image, StorageTextureVulkanImage* image,
uint32_t base_level); uint32_t base_level);
[[nodiscard]] DepthStencilVulkanImage* FindDepthTargetByRange(uint64_t vaddr, uint64_t size, [[nodiscard]] DepthStencilVulkanImage*
bool allow_containing_sampled = false); FindDepthTargetByRange(uint64_t vaddr, uint64_t size, bool allow_containing_sampled = false);
[[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size); [[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool HasRangeOverlap(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 HasGpuModifiedRangeOverlap(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool HasGpuTargetPageOverlap(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); void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
@@ -126,6 +132,8 @@ private:
bool gpu_modified = false; bool gpu_modified = false;
}; };
static void DeleteImageViews(GraphicContext* ctx, VulkanImage* image); 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]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
[[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, [[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr,
uint64_t size) const; uint64_t size) const;
@@ -154,8 +154,9 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, VkExtent2D extent, VkFo
return; return;
} }
if (dst.image != nullptr) { if (dst.image != nullptr) {
EXIT_IF(!dst.view_cache.views.empty());
VulkanDeleteImage(ctx, &dst, &dst.memory); VulkanDeleteImage(ctx, &dst, &dst.memory);
dst = VulkanImage(VulkanImageType::Unknown); dst.memory = {};
} }
dst.extent = extent; dst.extent = extent;
+389 -35
View File
@@ -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 { struct TestCase {
const char *name = ""; const char *name = "";
std::vector<u32> code; std::vector<u32> code;
@@ -1047,6 +1052,258 @@ public:
static_cast<int>(view_info.format)); static_cast<int>(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, Buffer CreateStorageBuffer(const char *shader_name,
const std::vector<u32> &initial, const std::vector<u32> &initial,
size_t dword_count) { size_t dword_count) {
@@ -8730,7 +8987,7 @@ void CheckReverseRenderTargetFormatContract() {
if (std::strcmp(kind, "sampled") == 0) { if (std::strcmp(kind, "sampled") == 0) {
(void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, (void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
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) { } else if (std::strcmp(kind, "sampled-compatible-swizzle") == 0) {
(void)SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, (void)SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
@@ -8759,10 +9016,10 @@ void CheckReverseRenderTargetFormatContract() {
(void)SelectSampledColorView(VK_FORMAT_A2B10G10R10_UNORM_PACK32, (void)SelectSampledColorView(VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_UNORM_PACK32,
DstSel(6, 5, 4, 7)); 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, (void)SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
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) { } else if (std::strcmp(kind, "sampled-depth-format") == 0) {
(void)SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, (void)SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_R32_SFLOAT, DstSel(4, 4, 4, 4)); VK_FORMAT_R32_SFLOAT, DstSel(4, 4, 4, 4));
@@ -8811,95 +9068,135 @@ void CheckSampledColorViews() {
Require("SampledColorViews", "identity", Require("SampledColorViews", "identity",
SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
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"); "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", Require("SampledColorViews", "R8 R001",
SelectSampledColorView(VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, 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"); "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", Require("SampledColorViews", "R16G16 RG01",
SelectSampledColorView(VK_FORMAT_R16G16_SFLOAT, SelectSampledColorView(VK_FORMAT_R16G16_SFLOAT,
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"); "R16G16 did not select its RG01 view");
Require("SampledColorViews", "alpha one", Require("SampledColorViews", "alpha one",
SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM, SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
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"); "RGB1 did not select the alpha-one view");
Require("SampledColorViews", "mutable BGRA target", Require("SampledColorViews", "mutable BGRA target",
SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_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"); "BGRA target did not select the exact RGBA/BGRA mutable view");
Require("SampledColorViews", "mutable sRGB view of UNORM BGRA target", Require(
SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, "SampledColorViews", "mutable sRGB view of UNORM BGRA target",
VK_FORMAT_R8G8B8A8_SRGB, SelectSampledColorView(VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB,
DstSel(6, 5, 4, 7)) == VulkanImage::VIEW_BGRA_TO_RGBA, DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7),
"UNORM BGRA target did not select its compatible sRGB RGBA sampled view"); "UNORM BGRA target did not select its compatible sRGB RGBA sampled view");
Require("SampledColorViews", "mutable sRGB BGRA target", Require("SampledColorViews", "mutable sRGB BGRA target",
BgraToRgbaSampledViewFormat(VK_FORMAT_B8G8R8A8_SRGB) == BgraToRgbaSampledViewFormat(VK_FORMAT_B8G8R8A8_SRGB) ==
VK_FORMAT_R8G8B8A8_SRGB && VK_FORMAT_R8G8B8A8_SRGB &&
SelectSampledColorView(VK_FORMAT_B8G8R8A8_SRGB, SelectSampledColorView(VK_FORMAT_B8G8R8A8_SRGB,
VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_SRGB,
DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7),
VulkanImage::VIEW_BGRA_TO_RGBA,
"sRGB BGRA target did not select its matching mutable RGBA view"); "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", Require("SampledColorViews", "mutable packed RGB10 view",
BgraToRgbaSampledViewFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32) == BgraToRgbaSampledViewFormat(VK_FORMAT_A2R10G10B10_UNORM_PACK32) ==
VK_FORMAT_A2B10G10R10_UNORM_PACK32 && VK_FORMAT_A2B10G10R10_UNORM_PACK32 &&
SelectSampledColorView(VK_FORMAT_A2R10G10B10_UNORM_PACK32, SelectSampledColorView(VK_FORMAT_A2R10G10B10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32,
DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7)) == DstSel(6, 5, 4, 7),
VulkanImage::VIEW_BGRA_TO_RGBA,
"packed RGB10 target did not select its matching mutable channel-order view"); "packed RGB10 target did not select its matching mutable channel-order view");
Require("SampledColorViews", "reverse RGBA16F sampled view", Require("SampledColorViews", "reverse RGBA16F sampled view",
SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT, SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT,
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"); "reverse RGBA16F target did not select its reciprocal ABGR sampled view");
Require("SampledColorViews", "mutable integer-class views", Require("SampledColorViews", "mutable integer-class views",
SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT, SelectSampledColorView(VK_FORMAT_R16G16B16A16_SFLOAT,
VK_FORMAT_R16G16B16A16_UINT, 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, SelectSampledColorView(VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_R8G8B8A8_UINT, 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, SelectSampledColorView(VK_FORMAT_R8G8B8A8_UINT,
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),
"compatible integer render-target sampled view was rejected"); "compatible integer render-target sampled view was rejected");
Require("SampledColorViews", "D32 depth target", Require("SampledColorViews", "D32 depth target",
SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT,
DstSel(4, 4, 4, 4)) == DstSel(4, 4, 4, 4)) == DstSel(4, 4, 4, 4),
VulkanImage::VIEW_DEPTH_TEXTURE,
"D32 depth target did not select its depth-aspect view"); "D32 depth target did not select its depth-aspect view");
Require("SampledColorViews", "D16 R000 depth target", Require("SampledColorViews", "D16 R000 depth target",
SelectSampledDepthView(VK_FORMAT_D16_UNORM, VK_FORMAT_R16_UNORM, SelectSampledDepthView(VK_FORMAT_D16_UNORM, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 0)) == DstSel(4, 0, 0, 0)) == DstSel(4, 0, 0, 0),
VulkanImage::VIEW_R000,
"D16 depth target did not select its R000 depth-aspect view"); "D16 depth target did not select its R000 depth-aspect view");
Require("SampledColorViews", "D16S8 R001 depth target", Require("SampledColorViews", "D16S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_R16_UNORM, SelectSampledDepthView(VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
VulkanImage::VIEW_R001,
"D16S8 depth target did not select its R001 depth-aspect view"); "D16S8 depth target did not select its R001 depth-aspect view");
Require("SampledColorViews", "promoted D24S8 R001 depth target", Require("SampledColorViews", "promoted D24S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R16_UNORM, SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
VulkanImage::VIEW_R001,
"D24S8 host fallback did not preserve the guest R16 depth view"); "D24S8 host fallback did not preserve the guest R16 depth view");
Require("SampledColorViews", "promoted D32S8 R001 depth target", Require("SampledColorViews", "promoted D32S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R16_UNORM, SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
VulkanImage::VIEW_R001,
"D32S8 host fallback did not preserve the guest R16 depth view"); "D32S8 host fallback did not preserve the guest R16 depth view");
Require("SampledColorViews", "D32S8 R001 depth target", Require("SampledColorViews", "D32S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT,
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
VulkanImage::VIEW_R001,
"D32S8 depth target did not select its R001 depth-aspect view"); "D32S8 depth target did not select its R001 depth-aspect view");
Require("SampledColorViews", "storage identity", Require("SampledColorViews", "storage identity",
SelectStorageColorView(VK_FORMAT_R8G8B8A8_UNORM, SelectStorageColorView(VK_FORMAT_R8G8B8A8_UNORM,
@@ -8981,7 +9278,7 @@ void CheckSampledColorViews() {
{"sampled", "sampled-compatible-swizzle", "sampled-compatible-reverse", {"sampled", "sampled-compatible-swizzle", "sampled-compatible-reverse",
"sampled-compatible-colorspace", "sampled-compatible-colorspace",
"sampled-compatible-snorm", "sampled-rgb10-swizzle", "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", "sampled-depth-swizzle", "storage", "storage-format",
"storage-compatible-swizzle", "storage-abgr", "storage-kind", "storage-no-write", "storage-compatible-swizzle", "storage-abgr", "storage-kind", "storage-no-write",
"storage-atomic", "storage-compare", "storage-mip", "storage-atomic", "storage-compare", "storage-mip",
@@ -9069,6 +9366,50 @@ void CheckSampledDepthResource() {
std::printf("[host] %-32s ok\n", "SampledDepthResource"); 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() { void CheckSampledDepthDescriptor() {
ShaderTextureResource descriptor{{0x00eb0900u, 0xc1600000u, 0x00bcc14fu, ShaderTextureResource descriptor{{0x00eb0900u, 0xc1600000u, 0x00bcc14fu,
0x91800924u, 0x00000000u, 0x00700000u, 0x91800924u, 0x00000000u, 0x00700000u,
@@ -12358,6 +12699,14 @@ int main(int argc, char **argv) {
} }
if (argc == 2 && std::strcmp(argv[1], "--image-view-only") == 0) { if (argc == 2 && std::strcmp(argv[1], "--image-view-only") == 0) {
CheckSampledColorViews(); 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; return 0;
} }
if (argc == 2 && std::strcmp(argv[1], "--sampled-depth-resource-only") == 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) { std::strcmp(argv[1], "--storage-texture-descriptor-death") == 0) {
RunStorageTextureDescriptorDeathCase(argv[2]); 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]); RunStorageTextureAccessDeathCase(argv[2]);
} }
if (argc == 3 && std::strcmp(argv[1], "--meta-overlap-death") == 0) { if (argc == 3 && std::strcmp(argv[1], "--meta-overlap-death") == 0) {
@@ -12415,6 +12765,7 @@ int main(int argc, char **argv) {
} }
CheckReverseRenderTargetFormatContract(); CheckReverseRenderTargetFormatContract();
CheckSampledColorViews(); CheckSampledColorViews();
CheckSampledVideoOutView();
CheckSampledDepthResource(); CheckSampledDepthResource();
CheckSampledDepthDescriptor(); CheckSampledDepthDescriptor();
CheckBufferCacheRangeMerge(); CheckBufferCacheRangeMerge();
@@ -12456,6 +12807,9 @@ int main(int argc, char **argv) {
VulkanHarness vulkan; VulkanHarness vulkan;
vulkan.CheckMutableStorageSrgbView(); vulkan.CheckMutableStorageSrgbView();
vulkan.CheckMutableRenderTargetBgraStorageView(); vulkan.CheckMutableRenderTargetBgraStorageView();
vulkan.CheckRenderTargetViewCache();
vulkan.CheckDepthTargetSampledViewCache();
vulkan.CheckVideoOutSampledViewCache();
const auto tests = MakeCases(); const auto tests = MakeCases();
const auto graphics_tests = MakeGraphicsCases(); const auto graphics_tests = MakeGraphicsCases();
CheckOpcodeCoverage(tests, graphics_tests); CheckOpcodeCoverage(tests, graphics_tests);