mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
graphics: bind unbound textures as native null descriptors
This commit is contained in:
+17
-52
@@ -199,9 +199,7 @@ TextureCache::BindingType TextureCache::UploadBinding(const Image& image) {
|
|||||||
|
|
||||||
ImageId TextureCache::InsertImage(const ImageInfo& info) {
|
ImageId TextureCache::InsertImage(const ImageInfo& info) {
|
||||||
const auto id = m_slot_images.insert(m_graphics, m_scheduler, info);
|
const auto id = m_slot_images.insert(m_graphics, m_scheduler, info);
|
||||||
if (!info.data.Empty()) {
|
RegisterImage(id);
|
||||||
RegisterImage(id);
|
|
||||||
}
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +406,7 @@ void TextureCache::UntrackImageTail(ImageId id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::TrackImageDownload(ImageId id, Image& image) {
|
void TextureCache::TrackImageDownload(ImageId id, Image& image) {
|
||||||
if (m_readback_linear_images && !image.info.IsTiled() && !image.info.data.Empty()) {
|
if (m_readback_linear_images && !image.info.IsTiled()) {
|
||||||
if (!image.IsGpuModified()) {
|
if (!image.IsGpuModified()) {
|
||||||
EXIT("TextureCache: cannot enroll a non-GPU-owned image for download\n");
|
EXIT("TextureCache: cannot enroll a non-GPU-owned image for download\n");
|
||||||
}
|
}
|
||||||
@@ -452,27 +450,6 @@ TextureCache::ImageIds TextureCache::FindImagesInRegion(uint64_t address, uint64
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageId TextureCache::GetNullImage(const ImageDesc& desc) {
|
|
||||||
const auto format = desc.info.pixel_format;
|
|
||||||
if (const auto found = m_null_images.find(format); found != m_null_images.end()) {
|
|
||||||
return found->second;
|
|
||||||
}
|
|
||||||
ImageInfo info {};
|
|
||||||
info.pixel_format = desc.info.pixel_format;
|
|
||||||
info.guest_format = desc.info.guest_format;
|
|
||||||
info.type = Prospero::ImageType::kColor2D;
|
|
||||||
info.extent = {1, 1, 1};
|
|
||||||
info.resources = {1, 1};
|
|
||||||
info.pitch = 1;
|
|
||||||
info.bytes_per_block = std::max(desc.info.bytes_per_block, 1u);
|
|
||||||
info.samples = 1;
|
|
||||||
info.tile_mode = Prospero::TileMode::kLinear;
|
|
||||||
info.mip_layout[0] = {0, info.bytes_per_block, 1, 1};
|
|
||||||
const auto id = InsertImage(info);
|
|
||||||
m_null_images.emplace(format, id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::ValidateImageDesc(const ImageDesc& desc) const {
|
void TextureCache::ValidateImageDesc(const ImageDesc& desc) const {
|
||||||
ImageOps::Validate(desc.info);
|
ImageOps::Validate(desc.info);
|
||||||
if (desc.view_info.format == vk::Format::eUndefined || desc.view_info.level_count == 0 ||
|
if (desc.view_info.format == vk::Format::eUndefined || desc.view_info.level_count == 0 ||
|
||||||
@@ -1026,9 +1003,6 @@ void TextureCache::UploadImage(Image& image, Buffer& source, uint64_t source_off
|
|||||||
|
|
||||||
void TextureCache::InitializeImage(ImageId id) {
|
void TextureCache::InitializeImage(ImageId id) {
|
||||||
auto& image = m_slot_images[id];
|
auto& image = m_slot_images[id];
|
||||||
if (image.info.data.Empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TrackImage(id);
|
TrackImage(id);
|
||||||
if (image.info.metadata.compression != VideoOutCompression::Uncompressed) {
|
if (image.info.metadata.compression != VideoOutCompression::Uncompressed) {
|
||||||
if (image.IsCpuDirty()) {
|
if (image.IsCpuDirty()) {
|
||||||
@@ -1215,10 +1189,7 @@ ImageId TextureCache::FindImage(ImageDesc& desc, bool exact_format) {
|
|||||||
EXIT("TextureCache: image lookup requires a valid command buffer\n");
|
EXIT("TextureCache: image lookup requires a valid command buffer\n");
|
||||||
}
|
}
|
||||||
ValidateImageDesc(desc);
|
ValidateImageDesc(desc);
|
||||||
if (desc.info.data.Empty()) {
|
EXIT_IF(desc.info.data.Empty());
|
||||||
std::scoped_lock lock {m_lock};
|
|
||||||
return GetNullImage(desc);
|
|
||||||
}
|
|
||||||
const auto metadata_base_layer = desc.view_info.base_layer;
|
const auto metadata_base_layer = desc.view_info.base_layer;
|
||||||
|
|
||||||
ImageId result {};
|
ImageId result {};
|
||||||
@@ -1370,36 +1341,30 @@ vk::ImageView TextureCache::FindTexture(ImageId id, const ImageDesc& desc) {
|
|||||||
std::scoped_lock lock {m_lock};
|
std::scoped_lock lock {m_lock};
|
||||||
auto& image = m_slot_images[id];
|
auto& image = m_slot_images[id];
|
||||||
TouchImage(image);
|
TouchImage(image);
|
||||||
if (!image.info.data.Empty()) {
|
if (!image.registered || image.depth_id || image.binding.needs_rebind) {
|
||||||
if (!image.registered || image.depth_id || image.binding.needs_rebind) {
|
EXIT("TextureCache: texture requires rediscovery before final acquisition\n");
|
||||||
EXIT("TextureCache: texture requires rediscovery before final acquisition\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (desc.type == BindingType::Storage) {
|
if (desc.type == BindingType::Storage) {
|
||||||
image.MarkGpuModified();
|
image.MarkGpuModified();
|
||||||
}
|
}
|
||||||
if (!image.info.data.Empty()) {
|
RefreshImage(id);
|
||||||
RefreshImage(id);
|
if (image.info.HasStencil() &&
|
||||||
if (image.info.HasStencil() &&
|
desc.info.data.address >= image.info.stencil.address &&
|
||||||
desc.info.data.address >= image.info.stencil.address &&
|
desc.info.data.End() <= image.info.stencil.End()) {
|
||||||
desc.info.data.End() <= image.info.stencil.End()) {
|
for (const auto stencil_id:
|
||||||
for (const auto stencil_id:
|
FindImagesInRegion(image.info.stencil.address, image.info.stencil.size, false)) {
|
||||||
FindImagesInRegion(image.info.stencil.address, image.info.stencil.size, false)) {
|
const auto* stencil = m_slot_images.try_get(stencil_id);
|
||||||
const auto* stencil = m_slot_images.try_get(stencil_id);
|
if (stencil != nullptr && stencil->depth_id == id &&
|
||||||
if (stencil != nullptr && stencil->depth_id == id &&
|
stencil->info.data == image.info.stencil) {
|
||||||
stencil->info.data == image.info.stencil) {
|
RefreshImage(stencil_id);
|
||||||
RefreshImage(stencil_id);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (desc.type) {
|
switch (desc.type) {
|
||||||
case BindingType::Texture: break;
|
case BindingType::Texture: break;
|
||||||
case BindingType::Storage:
|
case BindingType::Storage:
|
||||||
if (!image.info.data.Empty()) {
|
CommitGpuWrite(image);
|
||||||
CommitGpuWrite(image);
|
|
||||||
}
|
|
||||||
TrackImageDownload(id, image);
|
TrackImageDownload(id, image);
|
||||||
break;
|
break;
|
||||||
default: EXIT("TextureCache: invalid texture binding\n");
|
default: EXIT("TextureCache: invalid texture binding\n");
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -114,7 +113,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ImageId InsertImage(const ImageInfo& info);
|
[[nodiscard]] ImageId InsertImage(const ImageInfo& info);
|
||||||
[[nodiscard]] ImageId GetNullImage(const ImageDesc& desc);
|
|
||||||
void RegisterImage(ImageId id);
|
void RegisterImage(ImageId id);
|
||||||
void UnregisterImage(ImageId id);
|
void UnregisterImage(ImageId id);
|
||||||
void DeleteImage(ImageId id);
|
void DeleteImage(ImageId id);
|
||||||
@@ -173,7 +171,6 @@ private:
|
|||||||
BufferCache& m_buffer_cache;
|
BufferCache& m_buffer_cache;
|
||||||
Common::SlotVector<Image> m_slot_images;
|
Common::SlotVector<Image> m_slot_images;
|
||||||
ImagePageTable m_image_page_table;
|
ImagePageTable m_image_page_table;
|
||||||
std::unordered_map<vk::Format, ImageId> m_null_images;
|
|
||||||
Common::LeastRecentlyUsedCache<ImageId, uint64_t> m_lru_cache;
|
Common::LeastRecentlyUsedCache<ImageId, uint64_t> m_lru_cache;
|
||||||
std::unordered_set<ImageId> m_download_images;
|
std::unordered_set<ImageId> m_download_images;
|
||||||
std::map<uint64_t, MetaDataInfo> m_surface_metas;
|
std::map<uint64_t, MetaDataInfo> m_surface_metas;
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ vk::DescriptorType NativeDescriptorType(BindingKind kind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vk::DescriptorImageInfo MakeImageInfo(const TextureBinding& texture, uint32_t element) {
|
vk::DescriptorImageInfo MakeImageInfo(const TextureBinding& texture, uint32_t element) {
|
||||||
|
if (!texture.image_id) {
|
||||||
|
EXIT_IF(texture.image_view != nullptr || !texture.mip_views.empty());
|
||||||
|
return {nullptr, nullptr, vk::ImageLayout::eGeneral};
|
||||||
|
}
|
||||||
vk::ImageView view = nullptr;
|
vk::ImageView view = nullptr;
|
||||||
if (texture.mip_views.empty()) {
|
if (texture.mip_views.empty()) {
|
||||||
if (element == 0u) {
|
if (element == 0u) {
|
||||||
@@ -84,7 +88,7 @@ vk::DescriptorImageInfo MakeImageInfo(const TextureBinding& texture, uint32_t el
|
|||||||
} else if (element < texture.mip_views.size()) {
|
} else if (element < texture.mip_views.size()) {
|
||||||
view = texture.mip_views[element];
|
view = texture.mip_views[element];
|
||||||
}
|
}
|
||||||
EXIT_IF(!texture.image_id || view == nullptr || texture.layout == vk::ImageLayout::eUndefined);
|
EXIT_IF(view == nullptr || texture.layout == vk::ImageLayout::eUndefined);
|
||||||
return {nullptr, view, texture.layout};
|
return {nullptr, view, texture.layout};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,39 +352,6 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
|||||||
descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource,
|
|
||||||
TextureCache::BindingType binding) {
|
|
||||||
TextureCache::ImageDesc desc {};
|
|
||||||
switch (resource.numeric_class) {
|
|
||||||
case Prospero::TextureNumericClass::Float:
|
|
||||||
desc.info.guest_format = Prospero::BufferFormat::k32Float;
|
|
||||||
break;
|
|
||||||
case Prospero::TextureNumericClass::Uint:
|
|
||||||
desc.info.guest_format = resource.atomic64 ? Prospero::BufferFormat::k32_32UInt
|
|
||||||
: Prospero::BufferFormat::k32UInt;
|
|
||||||
break;
|
|
||||||
case Prospero::TextureNumericClass::Sint:
|
|
||||||
desc.info.guest_format = Prospero::BufferFormat::k32SInt;
|
|
||||||
break;
|
|
||||||
default: EXIT("null image has unsupported numeric class\n");
|
|
||||||
}
|
|
||||||
desc.info.pixel_format = VulkanFormat(desc.info.guest_format);
|
|
||||||
desc.info.type = Prospero::ImageType::kColor2D;
|
|
||||||
desc.info.extent = {1, 1, 1};
|
|
||||||
desc.info.resources = {1, 1};
|
|
||||||
desc.info.bytes_per_block = Prospero::NumBytesPerElement(desc.info.guest_format);
|
|
||||||
desc.info.samples = 1;
|
|
||||||
desc.info.mip_layout[0] = {0, 0, 1, 1};
|
|
||||||
desc.view_info.format = resource.atomic64 ? vk::Format::eR64Uint : desc.info.pixel_format;
|
|
||||||
desc.view_info.type = vk::ImageViewType::e2D;
|
|
||||||
desc.view_info.aspect = vk::ImageAspectFlagBits::eColor;
|
|
||||||
desc.view_info.usage = binding == TextureCache::BindingType::Storage
|
|
||||||
? vk::ImageUsageFlagBits::eStorage
|
|
||||||
: vk::ImageUsageFlagBits::eSampled;
|
|
||||||
desc.type = binding;
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource,
|
static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource,
|
||||||
const ShaderTextureResource& descriptor, vk::Format format,
|
const ShaderTextureResource& descriptor, vk::Format format,
|
||||||
const SurfaceFormatInfo& surface_format, bool storage,
|
const SurfaceFormatInfo& surface_format, bool storage,
|
||||||
@@ -516,10 +487,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
|
|
||||||
auto& texture_cache = m_context.GetTextureCache();
|
auto& texture_cache = m_context.GetTextureCache();
|
||||||
if (descriptor.IsNull()) {
|
if (descriptor.IsNull()) {
|
||||||
auto desc = NullTextureDesc(resource, storage ? TextureCache::BindingType::Storage
|
return {.layout = vk::ImageLayout::eGeneral};
|
||||||
: TextureCache::BindingType::Texture);
|
|
||||||
const auto id = texture_cache.FindImage(desc);
|
|
||||||
return {id, nullptr, std::move(desc)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto address = descriptor.Base40();
|
const auto address = descriptor.Base40();
|
||||||
@@ -689,10 +657,10 @@ static vk::DescriptorBufferInfo NativeUpload(RenderContext& context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RenderExecutor::BindImage(ImageId id, bool storage) {
|
void RenderExecutor::BindImage(ImageId id, bool storage) {
|
||||||
auto& image = m_context.GetTextureCache().GetImage(id);
|
if (!id) {
|
||||||
if (image.info.data.Empty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto& image = m_context.GetTextureCache().GetImage(id);
|
||||||
if (image.binding.is_bound) {
|
if (image.binding.is_bound) {
|
||||||
image.binding.force_general |= image.binding.shader_write != storage;
|
image.binding.force_general |= image.binding.shader_write != storage;
|
||||||
}
|
}
|
||||||
@@ -845,8 +813,9 @@ void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
|||||||
auto& texture_cache = m_context.GetTextureCache();
|
auto& texture_cache = m_context.GetTextureCache();
|
||||||
// Acquire each view before a later overlapping descriptor can replace its image.
|
// Acquire each view before a later overlapping descriptor can replace its image.
|
||||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||||
|
if (!images[i].image_id) continue;
|
||||||
const auto old_image = texture_cache.m_slot_images.try_get(images[i].image_id);
|
const auto old_image = texture_cache.m_slot_images.try_get(images[i].image_id);
|
||||||
if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
|
if (old_image == nullptr || !old_image->registered ||
|
||||||
old_image->binding.needs_rebind) {
|
old_image->binding.needs_rebind) {
|
||||||
if (old_image != nullptr) {
|
if (old_image != nullptr) {
|
||||||
old_image->binding = {};
|
old_image->binding = {};
|
||||||
@@ -897,7 +866,7 @@ void RenderExecutor::PrepareGraphicsBindings(std::span<PreparedBindings* const>
|
|||||||
for (auto& target: colors) {
|
for (auto& target: colors) {
|
||||||
EXIT_IF(!target.image_id);
|
EXIT_IF(!target.image_id);
|
||||||
const auto old_image = cache.m_slot_images.try_get(target.image_id);
|
const auto old_image = cache.m_slot_images.try_get(target.image_id);
|
||||||
if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
|
if (old_image == nullptr || !old_image->registered ||
|
||||||
old_image->binding.needs_rebind) {
|
old_image->binding.needs_rebind) {
|
||||||
if (old_image != nullptr) {
|
if (old_image != nullptr) {
|
||||||
old_image->binding = {};
|
old_image->binding = {};
|
||||||
@@ -1007,19 +976,14 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||||
auto& image = m_context.GetTextureCache().GetImage(descriptors.images[i].image_id);
|
|
||||||
auto& binding = descriptors.images[i];
|
auto& binding = descriptors.images[i];
|
||||||
|
if (!binding.image_id) continue;
|
||||||
|
auto& image = m_context.GetTextureCache().GetImage(binding.image_id);
|
||||||
const auto& view = binding.desc.view_info;
|
const auto& view = binding.desc.view_info;
|
||||||
const ImageSubresourceRange range {view.base_level, view.level_count, view.base_layer,
|
const ImageSubresourceRange range {view.base_level, view.level_count, view.base_layer,
|
||||||
view.layer_count};
|
view.layer_count};
|
||||||
const bool storage = binding.desc.type == TextureCache::BindingType::Storage;
|
const bool storage = binding.desc.type == TextureCache::BindingType::Storage;
|
||||||
if (image.info.data.Empty()) {
|
if (image.binding.is_target) {
|
||||||
image.Transit(vk::ImageLayout::eGeneral,
|
|
||||||
storage ? vk::AccessFlagBits2::eShaderRead |
|
|
||||||
vk::AccessFlagBits2::eShaderWrite
|
|
||||||
: vk::AccessFlagBits2::eShaderRead,
|
|
||||||
range, vk_buffer);
|
|
||||||
} else if (image.binding.is_target) {
|
|
||||||
const auto layout = image.binding.attachment_layout;
|
const auto layout = image.binding.attachment_layout;
|
||||||
EXIT_IF(layout == vk::ImageLayout::eUndefined);
|
EXIT_IF(layout == vk::ImageLayout::eUndefined);
|
||||||
if (image.info.IsDepth()) {
|
if (image.info.IsDepth()) {
|
||||||
@@ -1120,7 +1084,8 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
for (uint32_t i = 0; i < program.info.images.size(); ++i) {
|
for (uint32_t i = 0; i < program.info.images.size(); ++i) {
|
||||||
const auto& resource = program.info.images[i];
|
const auto& resource = program.info.images[i];
|
||||||
const auto& texture = descriptors.images[i];
|
const auto& texture = descriptors.images[i];
|
||||||
EXIT_IF(resource.mip_count != (texture.mip_views.empty() ? 1u : texture.mip_views.size()));
|
EXIT_IF(texture.image_id &&
|
||||||
|
resource.mip_count != (texture.mip_views.empty() ? 1u : texture.mip_views.size()));
|
||||||
const auto kind = *ShaderRecompiler::IR::DescriptorBindingForImage(resource);
|
const auto kind = *ShaderRecompiler::IR::DescriptorBindingForImage(resource);
|
||||||
const auto start = image_starts[ShaderRecompiler::IR::ImageBindingIndex(kind)] +
|
const auto start = image_starts[ShaderRecompiler::IR::ImageBindingIndex(kind)] +
|
||||||
resource.descriptor_index;
|
resource.descriptor_index;
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
|||||||
|
|
||||||
vk::PhysicalDeviceVulkan12Features features12 {};
|
vk::PhysicalDeviceVulkan12Features features12 {};
|
||||||
vk::PhysicalDeviceVulkan11Features features11 {};
|
vk::PhysicalDeviceVulkan11Features features11 {};
|
||||||
|
vk::PhysicalDeviceRobustness2FeaturesEXT robustness2 {};
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
features12.pNext = &depth_clip_control;
|
features12.pNext = &depth_clip_control;
|
||||||
#else
|
#else
|
||||||
@@ -223,7 +224,8 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
|||||||
fragment_barycentric.pNext = &depth_clip_control;
|
fragment_barycentric.pNext = &depth_clip_control;
|
||||||
features12.pNext = &fragment_barycentric;
|
features12.pNext = &fragment_barycentric;
|
||||||
#endif
|
#endif
|
||||||
features11.pNext = features12.pNext;
|
robustness2.pNext = features12.pNext;
|
||||||
|
features11.pNext = &robustness2;
|
||||||
features12.pNext = &features11;
|
features12.pNext = &features11;
|
||||||
features13.pNext = &features12;
|
features13.pNext = &features12;
|
||||||
device_features2.pNext = &features13;
|
device_features2.pNext = &features13;
|
||||||
@@ -289,6 +291,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
|||||||
"shaderStorageBufferArrayNonUniformIndexing",
|
"shaderStorageBufferArrayNonUniformIndexing",
|
||||||
required_features12.shaderStorageBufferArrayNonUniformIndexing);
|
required_features12.shaderStorageBufferArrayNonUniformIndexing);
|
||||||
check_feature(features13.robustImageAccess, "robustImageAccess");
|
check_feature(features13.robustImageAccess, "robustImageAccess");
|
||||||
|
check_feature(robustness2.nullDescriptor, "nullDescriptor");
|
||||||
check_feature(features13.dynamicRendering, "dynamicRendering",
|
check_feature(features13.dynamicRendering, "dynamicRendering",
|
||||||
required_features13.dynamicRendering);
|
required_features13.dynamicRendering);
|
||||||
check_feature(features13.synchronization2, "synchronization2",
|
check_feature(features13.synchronization2, "synchronization2",
|
||||||
@@ -450,14 +453,9 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
|
|||||||
vk::PhysicalDeviceVulkan13Features supported_features13 {};
|
vk::PhysicalDeviceVulkan13Features supported_features13 {};
|
||||||
supported_features13.pNext = &supported_features12;
|
supported_features13.pNext = &supported_features12;
|
||||||
|
|
||||||
const auto robustness2_ext_enabled =
|
|
||||||
HasExtension(device_extensions, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
|
||||||
|
|
||||||
vk::PhysicalDeviceRobustness2FeaturesEXT supported_robustness2 {};
|
vk::PhysicalDeviceRobustness2FeaturesEXT supported_robustness2 {};
|
||||||
if (robustness2_ext_enabled) {
|
supported_robustness2.pNext = supported_features13.pNext;
|
||||||
supported_robustness2.pNext = supported_features13.pNext;
|
supported_features13.pNext = &supported_robustness2;
|
||||||
supported_features13.pNext = &supported_robustness2;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool mesh_extension = HasExtension(device_extensions, VK_EXT_MESH_SHADER_EXTENSION_NAME);
|
const bool mesh_extension = HasExtension(device_extensions, VK_EXT_MESH_SHADER_EXTENSION_NAME);
|
||||||
vk::PhysicalDeviceMeshShaderFeaturesEXT supported_mesh {};
|
vk::PhysicalDeviceMeshShaderFeaturesEXT supported_mesh {};
|
||||||
@@ -611,27 +609,19 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
|
|||||||
fragment_barycentric.fragmentShaderBarycentric = VK_TRUE;
|
fragment_barycentric.fragmentShaderBarycentric = VK_TRUE;
|
||||||
robustness2.pNext = &fragment_barycentric;
|
robustness2.pNext = &fragment_barycentric;
|
||||||
#endif
|
#endif
|
||||||
if (robustness2_ext_enabled) {
|
robustness2.robustBufferAccess2 = supported_robustness2.robustBufferAccess2;
|
||||||
robustness2.robustBufferAccess2 = supported_robustness2.robustBufferAccess2;
|
robustness2.robustImageAccess2 = supported_robustness2.robustImageAccess2;
|
||||||
robustness2.robustImageAccess2 = supported_robustness2.robustImageAccess2;
|
robustness2.nullDescriptor = VK_TRUE;
|
||||||
robustness2.nullDescriptor = supported_robustness2.nullDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto features13 = WindowContext::RequiredVulkan13Features();
|
auto features13 = WindowContext::RequiredVulkan13Features();
|
||||||
#if defined(__APPLE__)
|
features13.pNext = &robustness2;
|
||||||
features13.pNext = robustness2_ext_enabled ? static_cast<void*>(&robustness2)
|
|
||||||
: static_cast<void*>(&features12);
|
|
||||||
#else
|
|
||||||
features13.pNext = robustness2_ext_enabled ? static_cast<void*>(&robustness2)
|
|
||||||
: static_cast<void*>(&fragment_barycentric);
|
|
||||||
#endif
|
|
||||||
features13.robustImageAccess = supported_features13.robustImageAccess;
|
features13.robustImageAccess = supported_features13.robustImageAccess;
|
||||||
features13.subgroupSizeControl =
|
features13.subgroupSizeControl =
|
||||||
graphics.compute_subgroup_size_control_enabled ? VK_TRUE : VK_FALSE;
|
graphics.compute_subgroup_size_control_enabled ? VK_TRUE : VK_FALSE;
|
||||||
|
|
||||||
LOGF("Vulkan robustness: robustImageAccess=%s robustImageAccess2=%s\n",
|
LOGF("Vulkan robustness: robustImageAccess=%s robustImageAccess2=%s\n",
|
||||||
features13.robustImageAccess == VK_TRUE ? "true" : "false",
|
features13.robustImageAccess == VK_TRUE ? "true" : "false",
|
||||||
robustness2_ext_enabled && robustness2.robustImageAccess2 == VK_TRUE ? "true" : "false");
|
robustness2.robustImageAccess2 == VK_TRUE ? "true" : "false");
|
||||||
|
|
||||||
vk::DeviceCreateInfo create_info {};
|
vk::DeviceCreateInfo create_info {};
|
||||||
vk::PhysicalDeviceMeshShaderFeaturesEXT mesh_features {};
|
vk::PhysicalDeviceMeshShaderFeaturesEXT mesh_features {};
|
||||||
@@ -961,7 +951,7 @@ void WindowContext::CreateVulkan() {
|
|||||||
std::vector<const char*> device_extensions = {
|
std::vector<const char*> device_extensions = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME,
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME,
|
||||||
VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||||
"VK_KHR_maintenance1"};
|
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, "VK_KHR_maintenance1"};
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// MoltenVK lacks VK_EXT_depth_clip_enable and VK_EXT_color_write_enable; the renderer
|
// MoltenVK lacks VK_EXT_depth_clip_enable and VK_EXT_color_write_enable; the renderer
|
||||||
@@ -1024,8 +1014,7 @@ void WindowContext::CreateVulkan() {
|
|||||||
device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
|
device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
|
||||||
graphic_ctx.memory_budget_ext_enabled = true;
|
graphic_ctx.memory_budget_ext_enabled = true;
|
||||||
}
|
}
|
||||||
for (const auto* extension: {VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
|
for (const auto* extension: {VK_KHR_MAINTENANCE_8_EXTENSION_NAME,
|
||||||
VK_KHR_MAINTENANCE_8_EXTENSION_NAME,
|
|
||||||
VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
|
VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
|
||||||
VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME,
|
VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME,
|
||||||
VK_EXT_MESH_SHADER_EXTENSION_NAME,
|
VK_EXT_MESH_SHADER_EXTENSION_NAME,
|
||||||
|
|||||||
@@ -356,10 +356,6 @@ struct TextureCacheTestAccess {
|
|||||||
return cache.m_download_images.contains(id);
|
return cache.m_download_images.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t NullImageCount(const TextureCache &cache) {
|
|
||||||
return cache.m_null_images.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TrackDownload(TextureCache &cache, ImageId id) {
|
static void TrackDownload(TextureCache &cache, ImageId id) {
|
||||||
std::lock_guard lock(cache.m_lock);
|
std::lock_guard lock(cache.m_lock);
|
||||||
cache.TrackImageDownload(id, cache.m_slot_images[id]);
|
cache.TrackImageDownload(id, cache.m_slot_images[id]);
|
||||||
@@ -10376,6 +10372,110 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckNullTextureDescriptors() {
|
||||||
|
constexpr const char *name = "NullTextureDescriptors";
|
||||||
|
constexpr uintptr_t base = 0x0000000204900000ull;
|
||||||
|
constexpr uint64_t size = 0x10000;
|
||||||
|
std::vector<u32> reader{
|
||||||
|
EncodeVop2(0x1a, 20, InlineU32(5), 0),
|
||||||
|
EncodeVop1(0x01, 21, InlineU32(0)),
|
||||||
|
EncodeVop1(0x01, 22, InlineU32(0)),
|
||||||
|
EncodeMimg0(0x00, 0xf), EncodeMimg1(1, 21)};
|
||||||
|
AppendVMovLiteral(&reader, 23, std::bit_cast<u32>(0.5f));
|
||||||
|
AppendVMovLiteral(&reader, 24, std::bit_cast<u32>(0.5f));
|
||||||
|
reader.insert(reader.end(), {
|
||||||
|
EncodeMimg0(0x27, 0xf), EncodeMimg1(5, 23, 0, 2),
|
||||||
|
0xbf8c3f70u,
|
||||||
|
EncodeMubuf0(0x1e), EncodeMubuf1(1, 3, 20),
|
||||||
|
EncodeMubuf0(0x1e, 16), EncodeMubuf1(5, 3, 20)});
|
||||||
|
AppendEnd(&reader);
|
||||||
|
std::vector<u32> writer{
|
||||||
|
EncodeVopc(0xd2, InlineU32(0), 0),
|
||||||
|
EncodeVop1(0x01, 21, InlineU32(0)),
|
||||||
|
EncodeVop1(0x01, 22, InlineU32(0))};
|
||||||
|
for (u32 i = 1; i <= 4; ++i)
|
||||||
|
AppendVMovLiteral(&writer, i, std::bit_cast<u32>(-1000000.0f));
|
||||||
|
writer.insert(writer.end(), {EncodeMimg0(0x08, 0xf), EncodeMimg1(1, 21)});
|
||||||
|
AppendEnd(&writer);
|
||||||
|
for (const auto *code : {&reader, &writer})
|
||||||
|
ShaderMapUserData(reinterpret_cast<uint64_t>(code->data()),
|
||||||
|
{.type = Prospero::ShaderBinaryType::kCs,
|
||||||
|
.code_size_bytes = static_cast<u32>(code->size() * sizeof(u32))});
|
||||||
|
|
||||||
|
EnsureRuntimeContext();
|
||||||
|
int64_t physical = -1;
|
||||||
|
Require(name, "allocate", LibKernel::Memory::KernelAllocateDirectMemory(
|
||||||
|
0, LibKernel::Memory::KernelGetDirectMemorySize(), size, size, 0, &physical) == 0,
|
||||||
|
"null texture output allocation failed");
|
||||||
|
void *mapped = reinterpret_cast<void *>(base);
|
||||||
|
Require(name, "map", LibKernel::Memory::KernelMapDirectMemory(
|
||||||
|
&mapped, size, 0x3, 0x10, physical, size) == 0 && mapped == reinterpret_cast<void *>(base),
|
||||||
|
"null texture output mapping failed");
|
||||||
|
std::memset(mapped, 0xa5, size);
|
||||||
|
RenderContext context(m_runtime_context);
|
||||||
|
context.InitializeGpu(nullptr);
|
||||||
|
LibKernel::Memory::InstallGpuResources(&context);
|
||||||
|
context.GetGpu().SendCommandSync([&] {
|
||||||
|
CommandProcessor processor(context, 0);
|
||||||
|
processor.BufferInit();
|
||||||
|
context.MapMemory(base, size);
|
||||||
|
auto &shaders = processor.GetShCtx();
|
||||||
|
auto &executor = context.GetRenderExecutor();
|
||||||
|
for (u32 wave_size : {32u, 64u}) {
|
||||||
|
const auto output_address = [&](u32 phase) {
|
||||||
|
return base + (wave_size == 64 ? 0x8000u : 0u) + 0x100u + phase * 0x2000u;
|
||||||
|
};
|
||||||
|
for (u32 sgpr = 0; sgpr < 16; ++sgpr)
|
||||||
|
shaders.SetCsUserSgpr(sgpr, 0, HW::UserSgprType::Unknown);
|
||||||
|
shaders.SetCsUserSgpr(8, 0x92u, HW::UserSgprType::Unknown);
|
||||||
|
for (u32 phase = 0; phase < 3; ++phase) {
|
||||||
|
const auto &code = phase == 1 ? writer : reader;
|
||||||
|
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(code.data()),
|
||||||
|
.num_thread_x = wave_size, .num_thread_y = 1, .num_thread_z = 1,
|
||||||
|
.wave_size = static_cast<uint8_t>(wave_size), .user_sgpr = 16});
|
||||||
|
ShaderBufferResource output{};
|
||||||
|
output.UpdateAddress48(output_address(phase));
|
||||||
|
output.fields[2] = wave_size * 8u * sizeof(u32);
|
||||||
|
output.fields[3] = DstSel(4, 5, 6, 7) |
|
||||||
|
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||||
|
for (u32 i = 0; i < 4; ++i)
|
||||||
|
shaders.SetCsUserSgpr(12 + i, output.fields[i], HW::UserSgprType::Unknown);
|
||||||
|
ShaderComputeInputInfo input{};
|
||||||
|
(void)context.GetPipelineCache().GetComputeProgram(
|
||||||
|
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||||
|
PreparedBindings bindings;
|
||||||
|
executor.PrepareBindings(input.stage, bindings);
|
||||||
|
executor.RebindImages(bindings);
|
||||||
|
Require(name, "native null image bindings", !bindings.images.empty() &&
|
||||||
|
std::ranges::all_of(bindings.images, [](const auto &binding) {
|
||||||
|
return !binding.image_id && binding.image_view == nullptr &&
|
||||||
|
binding.mip_views.empty() &&
|
||||||
|
MakeImageInfo(binding).imageView == nullptr &&
|
||||||
|
binding.layout == vk::ImageLayout::eGeneral;
|
||||||
|
}), "an all-zero guest descriptor allocated or bound a backing image");
|
||||||
|
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||||
|
}
|
||||||
|
for (u32 phase : {0u, 2u}) {
|
||||||
|
const auto address = output_address(phase);
|
||||||
|
std::vector<u32> actual(wave_size * 8u);
|
||||||
|
context.GetBufferCache().ReadMemory(address, actual.size() * sizeof(u32));
|
||||||
|
Require(name, "null RGBA before and after storage write",
|
||||||
|
LibKernel::Memory::TryReadBacking(address, actual.data(), actual.size() * sizeof(u32)) &&
|
||||||
|
std::ranges::all_of(actual, [](u32 value) { return value == 0; }),
|
||||||
|
"wave" + std::to_string(wave_size) + " phase" + std::to_string(phase) +
|
||||||
|
" returned nonzero load/sample components from an unbound texture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.UnmapMemory(base, size);
|
||||||
|
context.GetCommandScheduler().Finish();
|
||||||
|
});
|
||||||
|
LibKernel::Memory::InstallGpuResources(nullptr);
|
||||||
|
context.ShutdownGpu();
|
||||||
|
Require(name, "release", LibKernel::Memory::KernelCheckedReleaseDirectMemory(physical, size) == 0,
|
||||||
|
"null texture output release failed");
|
||||||
|
std::printf("[gpu] %-32s ok\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckScalarLeafCall() {
|
void CheckScalarLeafCall() {
|
||||||
constexpr const char* name = "ScalarLeafCall";
|
constexpr const char* name = "ScalarLeafCall";
|
||||||
constexpr uintptr_t base = 0x0000000204800000ull;
|
constexpr uintptr_t base = 0x0000000204800000ull;
|
||||||
@@ -13007,6 +13107,8 @@ public:
|
|||||||
}
|
}
|
||||||
ShaderRecompiler::IR::ApplyResourceSpecialization(
|
ShaderRecompiler::IR::ApplyResourceSpecialization(
|
||||||
null_program, null_specialization);
|
null_program, null_specialization);
|
||||||
|
null_program.info.images.back().mip_mode = ShaderRecompiler::IR::ImageMipMode::Dynamic;
|
||||||
|
null_program.info.images.back().mip_count = 3;
|
||||||
set_image_bindings(null_program);
|
set_image_bindings(null_program);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo null_info{};
|
ShaderRecompiler::IR::CompiledShaderInfo null_info{};
|
||||||
null_info.stage = null_program.stage;
|
null_info.stage = null_program.stage;
|
||||||
@@ -13019,38 +13121,27 @@ public:
|
|||||||
Require(name, "null descriptor count",
|
Require(name, "null descriptor count",
|
||||||
null_bindings.images.size() == 3,
|
null_bindings.images.size() == 3,
|
||||||
"null descriptor preparation lost an image binding");
|
"null descriptor preparation lost an image binding");
|
||||||
const auto null_image_id = null_bindings.images[0].image_id;
|
|
||||||
const auto &null_image = texture_cache.GetImage(null_image_id);
|
|
||||||
Require(name, "one null image per format",
|
|
||||||
null_bindings.images[1].image_id == null_image_id &&
|
|
||||||
null_bindings.images[2].image_id == null_image_id &&
|
|
||||||
TextureCacheTestAccess::NullImageCount(texture_cache) == 1,
|
|
||||||
"null view dimension or usage created another image allocation");
|
|
||||||
Require(name, "null descriptors share final cache acquisition",
|
|
||||||
null_image.info.data.Empty() && !null_image.binding.is_bound &&
|
|
||||||
!null_image.binding.is_target &&
|
|
||||||
!null_image.binding.needs_rebind &&
|
|
||||||
null_image.usage.storage &&
|
|
||||||
null_image.IsGpuModified() &&
|
|
||||||
!TextureCacheTestAccess::PendingDownload(texture_cache,
|
|
||||||
null_image_id),
|
|
||||||
"the shared null image did not preserve texture/storage "
|
|
||||||
"acquisition without guest readback or RenderExecutor ownership");
|
|
||||||
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
||||||
executor, scheduler.Current(), null_bindings));
|
executor, scheduler.Current(), null_bindings));
|
||||||
Require(name, "null descriptor general layouts",
|
Require(name, "null descriptors have no cache image or native view",
|
||||||
std::ranges::all_of(null_bindings.images,
|
std::ranges::all_of(null_bindings.images,
|
||||||
[](const auto &binding) {
|
[](const auto &binding) {
|
||||||
const auto info = MakeImageInfo(binding);
|
const auto info = MakeImageInfo(binding);
|
||||||
return binding.layout ==
|
return !binding.image_id &&
|
||||||
|
binding.image_view == nullptr &&
|
||||||
|
binding.mip_views.empty() &&
|
||||||
|
binding.layout ==
|
||||||
vk::ImageLayout::eGeneral &&
|
vk::ImageLayout::eGeneral &&
|
||||||
info.imageView ==
|
info.imageView == nullptr &&
|
||||||
binding.image_view &&
|
|
||||||
info.imageLayout == binding.layout;
|
info.imageLayout == binding.layout;
|
||||||
}) &&
|
}),
|
||||||
null_image.backing.state.layout == vk::ImageLayout::eGeneral,
|
"sampled/storage null descriptors acquired a backing image or lost their general layout");
|
||||||
"shared sampled/storage null descriptors did not retain "
|
for (u32 mip = 0; mip < 3; ++mip) {
|
||||||
"the general layout through descriptor generation");
|
const auto info = MakeImageInfo(null_bindings.images.back(), mip);
|
||||||
|
Require(name, "null storage mip descriptors",
|
||||||
|
info.imageView == nullptr && info.imageLayout == vk::ImageLayout::eGeneral,
|
||||||
|
"a null storage mip acquired a backing image");
|
||||||
|
}
|
||||||
|
|
||||||
constexpr uint64_t target_mip_size = 0x10000;
|
constexpr uint64_t target_mip_size = 0x10000;
|
||||||
const auto make_target_desc = [&](uint64_t address, uint64_t size,
|
const auto make_target_desc = [&](uint64_t address, uint64_t size,
|
||||||
@@ -19244,10 +19335,14 @@ private:
|
|||||||
available_min_lod.pNext = &available_provoking_vertex;
|
available_min_lod.pNext = &available_provoking_vertex;
|
||||||
vk::PhysicalDeviceMaintenance8FeaturesKHR available_maintenance8{};
|
vk::PhysicalDeviceMaintenance8FeaturesKHR available_maintenance8{};
|
||||||
available_maintenance8.pNext = &available_min_lod;
|
available_maintenance8.pNext = &available_min_lod;
|
||||||
|
vk::PhysicalDeviceRobustness2FeaturesEXT available_robustness2{};
|
||||||
|
available_robustness2.pNext = &available_maintenance8;
|
||||||
vk::PhysicalDeviceFeatures2 available_features2{};
|
vk::PhysicalDeviceFeatures2 available_features2{};
|
||||||
available_features2.sType = vk::StructureType::ePhysicalDeviceFeatures2;
|
available_features2.sType = vk::StructureType::ePhysicalDeviceFeatures2;
|
||||||
available_features2.pNext = &available_maintenance8;
|
available_features2.pNext = &available_robustness2;
|
||||||
m_physical_device.getFeatures2(&available_features2);
|
m_physical_device.getFeatures2(&available_features2);
|
||||||
|
Require("VulkanHarness", "dispatch", available_robustness2.nullDescriptor == true,
|
||||||
|
"null descriptors are not supported");
|
||||||
Require("VulkanHarness", "dispatch",
|
Require("VulkanHarness", "dispatch",
|
||||||
available_features.shaderStorageImageWriteWithoutFormat == true,
|
available_features.shaderStorageImageWriteWithoutFormat == true,
|
||||||
"shaderStorageImageWriteWithoutFormat is not supported");
|
"shaderStorageImageWriteWithoutFormat is not supported");
|
||||||
@@ -19367,7 +19462,10 @@ private:
|
|||||||
vk::PhysicalDeviceMaintenance8FeaturesKHR maintenance8{};
|
vk::PhysicalDeviceMaintenance8FeaturesKHR maintenance8{};
|
||||||
maintenance8.maintenance8 = true;
|
maintenance8.maintenance8 = true;
|
||||||
maintenance8.pNext = &min_lod;
|
maintenance8.pNext = &min_lod;
|
||||||
device_info.pNext = &maintenance8;
|
vk::PhysicalDeviceRobustness2FeaturesEXT robustness2{};
|
||||||
|
robustness2.nullDescriptor = true;
|
||||||
|
robustness2.pNext = &maintenance8;
|
||||||
|
device_info.pNext = &robustness2;
|
||||||
vk::PhysicalDeviceFeatures device_features{};
|
vk::PhysicalDeviceFeatures device_features{};
|
||||||
device_features.shaderStorageImageWriteWithoutFormat = true;
|
device_features.shaderStorageImageWriteWithoutFormat = true;
|
||||||
device_features.shaderImageGatherExtended = true;
|
device_features.shaderImageGatherExtended = true;
|
||||||
@@ -19384,6 +19482,7 @@ private:
|
|||||||
VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME,
|
VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME,
|
||||||
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME,
|
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME,
|
||||||
VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
|
VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
|
||||||
|
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
|
||||||
VK_KHR_MAINTENANCE_8_EXTENSION_NAME,
|
VK_KHR_MAINTENANCE_8_EXTENSION_NAME,
|
||||||
VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME};
|
VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME};
|
||||||
if (m_rasterization_supported) {
|
if (m_rasterization_supported) {
|
||||||
@@ -46678,6 +46777,7 @@ int main(int argc, char **argv) {
|
|||||||
if (argc == 2 && std::strcmp(argv[1], "--indirect-image-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--indirect-image-only") == 0) {
|
||||||
CheckImageSamplerSpecialization();
|
CheckImageSamplerSpecialization();
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
|
vulkan.CheckNullTextureDescriptors();
|
||||||
CheckCountedRowImageSelector(vulkan);
|
CheckCountedRowImageSelector(vulkan);
|
||||||
CheckPointerImageTable(vulkan);
|
CheckPointerImageTable(vulkan);
|
||||||
CheckNestedPointerImageTable(vulkan);
|
CheckNestedPointerImageTable(vulkan);
|
||||||
@@ -46872,6 +46972,7 @@ int main(int argc, char **argv) {
|
|||||||
vulkan.CheckGpuTilerCpuParity();
|
vulkan.CheckGpuTilerCpuParity();
|
||||||
vulkan.CheckNativeIndirectDispatch();
|
vulkan.CheckNativeIndirectDispatch();
|
||||||
CheckComputeLdsLimit(vulkan);
|
CheckComputeLdsLimit(vulkan);
|
||||||
|
vulkan.CheckNullTextureDescriptors();
|
||||||
vulkan.CheckBdaPageTableUploads();
|
vulkan.CheckBdaPageTableUploads();
|
||||||
vulkan.CheckLargeSparseImageUpload();
|
vulkan.CheckLargeSparseImageUpload();
|
||||||
vulkan.CheckUnifiedTextureCacheFlow();
|
vulkan.CheckUnifiedTextureCacheFlow();
|
||||||
|
|||||||
Reference in New Issue
Block a user