mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 06:16:55 +01:00
shader: simplify image resource semantics
This commit is contained in:
@@ -103,11 +103,13 @@ SelectSampledDepthView(vk::Format image_format, vk::Format view_format, uint32_t
|
|||||||
|
|
||||||
[[nodiscard]] inline bool
|
[[nodiscard]] inline bool
|
||||||
IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
||||||
if (!ShaderRecompiler::IR::ImageResourceKindMatches(
|
if (resource.resource_class != ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (resource.kind != ShaderRecompiler::IR::ResourceKind::Image && resource.depth_compare) {
|
if (resource.numeric_class == Prospero::TextureNumericClass::Unsupported) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (resource.numeric_class != Prospero::TextureNumericClass::Float && resource.depth_compare) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
|
return (resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
|
||||||
@@ -128,8 +130,9 @@ inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_fo
|
|||||||
|
|
||||||
[[nodiscard]] inline bool
|
[[nodiscard]] inline bool
|
||||||
IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
||||||
return (resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
|
return resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Storage &&
|
||||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint) &&
|
(resource.numeric_class == Prospero::TextureNumericClass::Float ||
|
||||||
|
resource.numeric_class == Prospero::TextureNumericClass::Uint) &&
|
||||||
(resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
|
(resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
|
||||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray ||
|
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray ||
|
||||||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
|
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
|
||||||
@@ -141,19 +144,19 @@ IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resou
|
|||||||
resource.mip_count != 0u)) &&
|
resource.mip_count != 0u)) &&
|
||||||
resource.written &&
|
resource.written &&
|
||||||
(!resource.atomic ||
|
(!resource.atomic ||
|
||||||
(resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint &&
|
(resource.numeric_class == Prospero::TextureNumericClass::Uint && resource.read)) &&
|
||||||
resource.read)) &&
|
|
||||||
!resource.depth_compare;
|
!resource.depth_compare;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
|
||||||
if (!IsSupportedStorageImageResource(resource)) {
|
if (!IsSupportedStorageImageResource(resource)) {
|
||||||
EXIT("unsupported storage color image resource: kind=%u dimension=%u mip=%u "
|
EXIT("unsupported storage color image resource: class=%u numeric=%u dimension=%u mip=%u "
|
||||||
"read=%d written=%d atomic=%d depth_compare=%d\n",
|
"read=%d written=%d atomic=%d depth_compare=%d\n",
|
||||||
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(resource.dimension),
|
static_cast<uint32_t>(resource.resource_class),
|
||||||
static_cast<uint32_t>(resource.mip_mode), resource.read, resource.written,
|
static_cast<uint32_t>(resource.numeric_class),
|
||||||
resource.atomic, resource.depth_compare);
|
static_cast<uint32_t>(resource.dimension), static_cast<uint32_t>(resource.mip_mode),
|
||||||
|
resource.read, resource.written, resource.atomic, resource.depth_compare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,11 +236,10 @@ static bool IsSupportedSampledColorResource(const ShaderRecompiler::IR::ImageRes
|
|||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
const bool sampled_kind = ShaderRecompiler::IR::ImageResourceKindMatches(
|
return resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled &&
|
||||||
resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled);
|
resource.numeric_class != Prospero::TextureNumericClass::Unsupported &&
|
||||||
return sampled_kind && supported_dimension &&
|
supported_dimension && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None &&
|
||||||
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.read &&
|
resource.read && !resource.written && !resource.atomic && !resource.depth_compare;
|
||||||
!resource.written && !resource.atomic && !resource.depth_compare;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetTextureViewInfo ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
|
TargetTextureViewInfo ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
|
||||||
@@ -394,15 +393,17 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
|
|||||||
TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u,
|
TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u,
|
||||||
descriptor.TileMode());
|
descriptor.TileMode());
|
||||||
EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d "
|
EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d "
|
||||||
"kind=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d "
|
"class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d "
|
||||||
"guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u "
|
"guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u "
|
||||||
"descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u "
|
"descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u "
|
||||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||||
" dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
" dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
||||||
resource_ok, descriptor_ok, encoding_ok, format_ok, static_cast<uint32_t>(resource.kind),
|
resource_ok, descriptor_ok, encoding_ok, format_ok,
|
||||||
static_cast<uint32_t>(resource.dimension), static_cast<uint32_t>(resource.mip_mode),
|
static_cast<uint32_t>(resource.resource_class),
|
||||||
resource.read, resource.written, resource.atomic, resource.depth_compare,
|
static_cast<uint32_t>(resource.numeric_class), static_cast<uint32_t>(resource.dimension),
|
||||||
static_cast<uint32_t>(descriptor.Format()), descriptor.DstSelXYZW(),
|
static_cast<uint32_t>(resource.mip_mode), resource.read, resource.written, resource.atomic,
|
||||||
|
resource.depth_compare, static_cast<uint32_t>(descriptor.Format()),
|
||||||
|
descriptor.DstSelXYZW(),
|
||||||
image == nullptr ? static_cast<int>(vk::Format::eUndefined)
|
image == nullptr ? static_cast<int>(vk::Format::eUndefined)
|
||||||
: static_cast<int>(image->info.pixel_format),
|
: static_cast<int>(image->info.pixel_format),
|
||||||
static_cast<int>(view_format), image == nullptr ? 0u : image->info.resources.layers,
|
static_cast<int>(view_format), image == nullptr ? 0u : image->info.resources.layers,
|
||||||
@@ -515,8 +516,7 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
|||||||
const bool resource_ok = IsSupportedStorageImageResource(resource);
|
const bool resource_ok = IsSupportedStorageImageResource(resource);
|
||||||
const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor);
|
const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor);
|
||||||
const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor);
|
const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor);
|
||||||
const bool uint_resource =
|
const bool uint_resource = resource.numeric_class == Prospero::TextureNumericClass::Uint;
|
||||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
|
||||||
const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource &&
|
const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource &&
|
||||||
resource.written && !resource.read && !resource.atomic;
|
resource.written && !resource.read && !resource.atomic;
|
||||||
const auto numeric_class = Prospero::SampledTextureNumericClass(format);
|
const auto numeric_class = Prospero::SampledTextureNumericClass(format);
|
||||||
@@ -530,17 +530,19 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EXIT("unsupported storage texture: resource=%d descriptor=%d encoding=%d format=%d "
|
EXIT("unsupported storage texture: resource=%d descriptor=%d encoding=%d format=%d "
|
||||||
"kind=%u dimension=%u mip_mode=%u atomic=%d compare=%d "
|
"class=%u numeric=%u dimension=%u mip_mode=%u atomic=%d compare=%d "
|
||||||
"base_level=%u last_level=%u max_mip=%u min_lod=%u base_array=%u bc=%u msaa=%d "
|
"base_level=%u last_level=%u max_mip=%u min_lod=%u base_array=%u bc=%u msaa=%d "
|
||||||
"depth_tile_bpe=%u swizzle_ok=%d "
|
"depth_tile_bpe=%u swizzle_ok=%d "
|
||||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||||
" extent=%ux%ux%u type=%u format=%u tile=%u swizzle=0x%03x read=%d written=%d "
|
" extent=%ux%ux%u type=%u format=%u tile=%u swizzle=0x%03x read=%d written=%d "
|
||||||
"dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
"dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
||||||
resource_ok, descriptor_ok, encoding_ok, format_ok, static_cast<uint32_t>(resource.kind),
|
resource_ok, descriptor_ok, encoding_ok, format_ok,
|
||||||
static_cast<uint32_t>(resource.dimension), static_cast<uint32_t>(resource.mip_mode),
|
static_cast<uint32_t>(resource.resource_class),
|
||||||
resource.atomic, resource.depth_compare, descriptor.BaseLevel(), descriptor.LastLevel(),
|
static_cast<uint32_t>(resource.numeric_class), static_cast<uint32_t>(resource.dimension),
|
||||||
descriptor.MaxMip(), descriptor.MinLod(), descriptor.BaseArray5(), descriptor.BCSwizzle(),
|
static_cast<uint32_t>(resource.mip_mode), resource.atomic, resource.depth_compare,
|
||||||
descriptor.MsaaDepth(), Prospero::RenderTargetBytesPerElement(format),
|
descriptor.BaseLevel(), descriptor.LastLevel(), descriptor.MaxMip(), descriptor.MinLod(),
|
||||||
|
descriptor.BaseArray5(), descriptor.BCSwizzle(), descriptor.MsaaDepth(),
|
||||||
|
Prospero::RenderTargetBytesPerElement(format),
|
||||||
IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size,
|
IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size,
|
||||||
static_cast<uint32_t>(descriptor.Width5()) + 1u,
|
static_cast<uint32_t>(descriptor.Width5()) + 1u,
|
||||||
static_cast<uint32_t>(descriptor.Height5()) + 1u,
|
static_cast<uint32_t>(descriptor.Height5()) + 1u,
|
||||||
@@ -557,13 +559,16 @@ struct NullImageSpec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) {
|
static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) {
|
||||||
if (resource.kind == ShaderRecompiler::IR::ResourceKind::ImageSint) {
|
switch (resource.numeric_class) {
|
||||||
|
case Prospero::TextureNumericClass::Float:
|
||||||
|
return {vk::Format::eR32Sfloat, Prospero::BufferFormat::k32Float};
|
||||||
|
case Prospero::TextureNumericClass::Uint:
|
||||||
|
return {vk::Format::eR32Uint, Prospero::BufferFormat::k32UInt};
|
||||||
|
case Prospero::TextureNumericClass::Sint:
|
||||||
return {vk::Format::eR32Sint, Prospero::BufferFormat::k32SInt};
|
return {vk::Format::eR32Sint, Prospero::BufferFormat::k32SInt};
|
||||||
|
case Prospero::TextureNumericClass::Unsupported: break;
|
||||||
}
|
}
|
||||||
const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint ||
|
EXIT("null image has unsupported numeric class\n");
|
||||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
|
||||||
return uint_image ? NullImageSpec {vk::Format::eR32Uint, Prospero::BufferFormat::k32UInt}
|
|
||||||
: NullImageSpec {vk::Format::eR32Sfloat, Prospero::BufferFormat::k32Float};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource,
|
static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource,
|
||||||
@@ -731,15 +736,16 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
!msaa_tile || (descriptor.MsaaDepth() && !depth_tile) ||
|
!msaa_tile || (descriptor.MsaaDepth() && !depth_tile) ||
|
||||||
(!msaa_array && (descriptor.Depth() != 0 || descriptor.BaseArray5() != 0))))) {
|
(!msaa_array && (descriptor.Depth() != 0 || descriptor.BaseArray5() != 0))))) {
|
||||||
EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u "
|
EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u "
|
||||||
"kind=%u dimension=%u mip_mode=%u read=%d written=%d "
|
"class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d "
|
||||||
"dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
"dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n",
|
||||||
base_level, last_level, levels, descriptor.MaxMip(),
|
base_level, last_level, levels, descriptor.MaxMip(),
|
||||||
static_cast<uint32_t>(descriptor.Type()), static_cast<uint32_t>(tile),
|
static_cast<uint32_t>(descriptor.Type()), static_cast<uint32_t>(tile),
|
||||||
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(resource.dimension),
|
static_cast<uint32_t>(resource.resource_class),
|
||||||
static_cast<uint32_t>(resource.mip_mode), resource.read, resource.written,
|
static_cast<uint32_t>(resource.numeric_class),
|
||||||
descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3],
|
static_cast<uint32_t>(resource.dimension), static_cast<uint32_t>(resource.mip_mode),
|
||||||
descriptor.fields[4], descriptor.fields[5], descriptor.fields[6],
|
resource.read, resource.written, descriptor.fields[0], descriptor.fields[1],
|
||||||
descriptor.fields[7]);
|
descriptor.fields[2], descriptor.fields[3], descriptor.fields[4], descriptor.fields[5],
|
||||||
|
descriptor.fields[6], descriptor.fields[7]);
|
||||||
}
|
}
|
||||||
const auto samples = multisampled ? 1u << last_level : 1u;
|
const auto samples = multisampled ? 1u << last_level : 1u;
|
||||||
const auto view_levels =
|
const auto view_levels =
|
||||||
@@ -749,28 +755,12 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
const auto surface_format = TextureGetSurfaceFormatInfo(format);
|
const auto surface_format = TextureGetSurfaceFormatInfo(format);
|
||||||
const bool shader_conversion =
|
const bool shader_conversion =
|
||||||
surface_format.conversion_format != Prospero::BufferFormat::kInvalid;
|
surface_format.conversion_format != Prospero::BufferFormat::kInvalid;
|
||||||
Prospero::TextureNumericClass resource_numeric_class =
|
|
||||||
Prospero::TextureNumericClass::Unsupported;
|
|
||||||
switch (resource.kind) {
|
|
||||||
case ShaderRecompiler::IR::ResourceKind::Image:
|
|
||||||
resource_numeric_class = Prospero::TextureNumericClass::Float;
|
|
||||||
break;
|
|
||||||
case ShaderRecompiler::IR::ResourceKind::ImageUint:
|
|
||||||
resource_numeric_class = Prospero::TextureNumericClass::Uint;
|
|
||||||
break;
|
|
||||||
case ShaderRecompiler::IR::ResourceKind::ImageSint:
|
|
||||||
resource_numeric_class = Prospero::TextureNumericClass::Sint;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
const bool sampled_numeric_class =
|
const bool sampled_numeric_class =
|
||||||
storage || resource_numeric_class == Prospero::SampledTextureNumericClass(format);
|
storage || resource.numeric_class == Prospero::SampledTextureNumericClass(format);
|
||||||
if (!storage &&
|
if (!storage && resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled &&
|
||||||
ShaderRecompiler::IR::ImageResourceKindMatches(
|
|
||||||
resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled) &&
|
|
||||||
!sampled_numeric_class) {
|
!sampled_numeric_class) {
|
||||||
EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n",
|
EXIT("sampled image numeric class mismatch: numeric=%u format=%u addr=0x%016" PRIx64 "\n",
|
||||||
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(format), address);
|
static_cast<uint32_t>(resource.numeric_class), static_cast<uint32_t>(format), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool volume = type == Prospero::ImageType::kColor3D;
|
const bool volume = type == Prospero::ImageType::kColor3D;
|
||||||
|
|||||||
@@ -236,8 +236,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
const auto sampled_images = std::count_if(
|
const auto sampled_images = std::count_if(
|
||||||
program.info.images.begin(), program.info.images.end(), [](const auto& image) {
|
program.info.images.begin(), program.info.images.end(), [](const auto& image) {
|
||||||
return ShaderRecompiler::IR::ImageResourceKindMatches(
|
return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled);
|
|
||||||
});
|
});
|
||||||
const bool has_sampler = !program.info.samplers.empty();
|
const bool has_sampler = !program.info.samplers.empty();
|
||||||
static std::atomic<uint32_t> dispatch_log_count {0};
|
static std::atomic<uint32_t> dispatch_log_count {0};
|
||||||
@@ -265,8 +264,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
LOGF(" CS texture[%u]: source=%u usage=%s sampled=%s addr=0x%010" PRIx64
|
LOGF(" CS texture[%u]: source=%u usage=%s sampled=%s addr=0x%010" PRIx64
|
||||||
" type=%u fmt=%u extent=%ux%u depth=%u levels=%u tile=%u\n",
|
" type=%u fmt=%u extent=%ux%u depth=%u levels=%u tile=%u\n",
|
||||||
i, image.source, image.written ? "read-write" : "read-only",
|
i, image.source, image.written ? "read-write" : "read-only",
|
||||||
ShaderRecompiler::IR::ImageResourceKindMatches(
|
image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled
|
||||||
image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled)
|
|
||||||
? "true"
|
? "true"
|
||||||
: "false",
|
: "false",
|
||||||
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
|
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
|
||||||
@@ -347,8 +345,8 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
std::any_of(program.info.images.begin(), program.info.images.end(),
|
std::any_of(program.info.images.begin(), program.info.images.end(),
|
||||||
[](const auto& image) {
|
[](const auto& image) {
|
||||||
return image.written &&
|
return image.written &&
|
||||||
(image.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
|
image.resource_class ==
|
||||||
image.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint);
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
}) ||
|
}) ||
|
||||||
has_storage_writes;
|
has_storage_writes;
|
||||||
if (has_storage_writes) {
|
if (has_storage_writes) {
|
||||||
|
|||||||
@@ -199,8 +199,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
|
|||||||
const auto& ps_resources = ps_input_info.stage.program->info;
|
const auto& ps_resources = ps_input_info.stage.program->info;
|
||||||
const auto sampled_images = std::count_if(
|
const auto sampled_images = std::count_if(
|
||||||
ps_resources.images.begin(), ps_resources.images.end(), [](const auto& image) {
|
ps_resources.images.begin(), ps_resources.images.end(), [](const auto& image) {
|
||||||
return ShaderRecompiler::IR::ImageResourceKindMatches(
|
return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
vk::Extent2D extent = color.image_id ? color.extent : vk::Extent2D {};
|
vk::Extent2D extent = color.image_id ? color.extent : vk::Extent2D {};
|
||||||
|
|||||||
@@ -186,28 +186,35 @@ uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_cl
|
|||||||
|
|
||||||
StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32_t resource) {
|
StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32_t resource) {
|
||||||
const auto& image = state.program.info.images.at(resource);
|
const auto& image = state.program.info.images.at(resource);
|
||||||
const bool uint_image = image.kind == IR::ResourceKind::StorageImageUint;
|
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||||
EXIT_IF(image.kind != IR::ResourceKind::StorageImage && !uint_image);
|
if (image.atomic) {
|
||||||
EXIT_IF(image.atomic && !uint_image);
|
EXIT_IF(image.numeric_class != Prospero::TextureNumericClass::Uint);
|
||||||
return StorageImageClassFor(uint_image, image.atomic);
|
return StorageImageClass::AtomicUint;
|
||||||
|
}
|
||||||
|
switch (image.numeric_class) {
|
||||||
|
case Prospero::TextureNumericClass::Float: return StorageImageClass::FormatlessFloat;
|
||||||
|
case Prospero::TextureNumericClass::Uint: return StorageImageClass::FormatlessUint;
|
||||||
|
case Prospero::TextureNumericClass::Sint:
|
||||||
|
case Prospero::TextureNumericClass::Unsupported:
|
||||||
|
EXIT("invalid storage image numeric class");
|
||||||
|
}
|
||||||
|
EXIT("invalid storage image numeric class");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t StorageImageVariable(const EmitterState& state, StorageImageClass image_class,
|
uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource) {
|
||||||
ImageDimension dimension) {
|
const auto& image_resource = state.program.info.images.at(resource);
|
||||||
return state.storage_image_variables[StorageImageIndex(image_class, dimension)];
|
EXIT_IF(image_resource.resource_class != IR::ImageResourceClass::Sampled);
|
||||||
}
|
const auto dimension = image_resource.dimension;
|
||||||
|
const auto image_class = SampledImageClassFor(image_resource.numeric_class);
|
||||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem,
|
EXIT_IF(image_class == SampledImageClass::Count);
|
||||||
ImageDimension dimension) {
|
|
||||||
const auto image_class = SampledImageClassFor(mem.kind);
|
|
||||||
const auto kind = SampledBindingKind(image_class, dimension);
|
const auto kind = SampledBindingKind(image_class, dimension);
|
||||||
const auto array_index = ResourceForDescriptor(state, kind, mem.resource);
|
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
||||||
const auto variable = state.sampled_image_variables[SampledImageIndex(image_class, dimension)];
|
const auto variable = state.sampled_image_variables[SampledImageIndex(image_class, dimension)];
|
||||||
const auto pointer_type =
|
const auto pointer_type =
|
||||||
state.builder.Type(OpTypePointer, {StorageClassUniformConstant,
|
state.builder.Type(OpTypePointer, {StorageClassUniformConstant,
|
||||||
ImageViewImageType(state, dimension, image_class)});
|
ImageViewImageType(state, dimension, image_class)});
|
||||||
const auto pointer =
|
const auto pointer =
|
||||||
DescriptorElementPointer(state, pointer_type, variable, array_index, kind, mem.resource,
|
DescriptorElementPointer(state, pointer_type, variable, array_index, kind, resource,
|
||||||
"sampled image descriptor array was not emitted");
|
"sampled image descriptor array was not emitted");
|
||||||
const auto image = state.builder.AllocateId();
|
const auto image = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
@@ -229,43 +236,37 @@ uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler) {
|
|||||||
return sampler_id;
|
return sampler_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem,
|
uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler) {
|
||||||
ImageDimension dimension) {
|
const auto& image_resource = state.program.info.images.at(resource);
|
||||||
const auto image = LoadSampledImageDescriptor(state, mem, dimension);
|
const auto dimension = image_resource.dimension;
|
||||||
const auto sampler = LoadSamplerDescriptor(state, mem.sampler);
|
const auto image_class = SampledImageClassFor(image_resource.numeric_class);
|
||||||
if (image == 0 || sampler == 0) {
|
const auto image = LoadSampledImageDescriptor(state, resource);
|
||||||
ExitDescriptorBindingFailure(
|
const auto sampler_id = LoadSamplerDescriptor(state, sampler);
|
||||||
state, SampledBindingKind(SampledImageClassFor(mem.kind), dimension), mem.resource,
|
if (image == 0 || sampler_id == 0) {
|
||||||
|
ExitDescriptorBindingFailure(state, SampledBindingKind(image_class, dimension), resource,
|
||||||
"sampled image or sampler descriptor load failed");
|
"sampled image or sampler descriptor load failed");
|
||||||
}
|
}
|
||||||
const auto sampled_image = state.builder.AllocateId();
|
const auto sampled_image = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction({OpSampledImage,
|
||||||
{OpSampledImage,
|
ImageViewSampledImageType(state, dimension, image_class),
|
||||||
ImageViewSampledImageType(state, dimension, SampledImageClassFor(mem.kind)), sampled_image,
|
sampled_image, image, sampler_id});
|
||||||
image, sampler});
|
|
||||||
return sampled_image;
|
return sampled_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension,
|
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) {
|
||||||
uint32_t image_resource) {
|
const auto dimension = state.program.info.images.at(resource).dimension;
|
||||||
auto selected = mem;
|
|
||||||
selected.resource = image_resource;
|
|
||||||
return MakeSampledImage(state, selected, dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource,
|
|
||||||
ImageDimension dimension) {
|
|
||||||
const auto image_class = StorageImageClassForResource(state, resource);
|
const auto image_class = StorageImageClassForResource(state, resource);
|
||||||
const auto kind = StorageBindingKind(image_class, dimension);
|
const auto kind = StorageBindingKind(image_class, dimension);
|
||||||
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
||||||
const auto ptr_type = StorageImagePointerType(state, image_class, dimension);
|
const auto ptr_type = StorageImagePointerType(state, image_class, dimension);
|
||||||
const auto variable = StorageImageVariable(state, image_class, dimension);
|
const auto variable = state.storage_image_variables[StorageImageIndex(image_class, dimension)];
|
||||||
return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource,
|
return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource,
|
||||||
"storage image descriptor array was not emitted");
|
"storage image descriptor array was not emitted");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension,
|
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord,
|
||||||
uint32_t mip_lod, uint32_t coord, uint32_t texel) {
|
uint32_t texel) {
|
||||||
|
const auto dimension = state.program.info.images.at(resource).dimension;
|
||||||
const auto image_class = StorageImageClassForResource(state, resource);
|
const auto image_class = StorageImageClassForResource(state, resource);
|
||||||
if (image_class != StorageImageClass::AtomicUint) {
|
if (image_class != StorageImageClass::AtomicUint) {
|
||||||
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
||||||
@@ -276,8 +277,8 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimensio
|
|||||||
const auto LoadAt = [&](uint32_t array_index) {
|
const auto LoadAt = [&](uint32_t array_index) {
|
||||||
const auto pointer = DescriptorElementPointer(
|
const auto pointer = DescriptorElementPointer(
|
||||||
state, StorageImagePointerType(state, image_class, dimension),
|
state, StorageImagePointerType(state, image_class, dimension),
|
||||||
StorageImageVariable(state, image_class, dimension), array_index, kind, resource,
|
state.storage_image_variables[StorageImageIndex(image_class, dimension)], array_index,
|
||||||
"storage image descriptor array was not emitted");
|
kind, resource, "storage image descriptor array was not emitted");
|
||||||
const auto descriptor = state.builder.AllocateId();
|
const auto descriptor = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer});
|
{OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer});
|
||||||
|
|||||||
@@ -145,11 +145,12 @@ uint32_t CubeLayer(EmitterState& state, uint32_t value) {
|
|||||||
|
|
||||||
uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address,
|
uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address,
|
||||||
uint32_t first, uint32_t components) {
|
uint32_t first, uint32_t components) {
|
||||||
|
const bool cube = ctx.state.program.info.images.at(mem.resource).cube;
|
||||||
auto x = AddressF32(ctx, mem, address, first);
|
auto x = AddressF32(ctx, mem, address, first);
|
||||||
if (components == 1u) return x;
|
if (components == 1u) return x;
|
||||||
auto y = mem.image_address_components > first + 1u ? AddressF32(ctx, mem, address, first + 1u)
|
auto y = mem.image_address_components > first + 1u ? AddressF32(ctx, mem, address, first + 1u)
|
||||||
: ZeroF32(ctx.state);
|
: ZeroF32(ctx.state);
|
||||||
if (mem.image_cube) {
|
if (cube) {
|
||||||
x = CubeAxis(ctx.state, x);
|
x = CubeAxis(ctx.state, x);
|
||||||
y = CubeAxis(ctx.state, y);
|
y = CubeAxis(ctx.state, y);
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@ uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In
|
|||||||
auto z = mem.image_address_components > first + 2u
|
auto z = mem.image_address_components > first + 2u
|
||||||
? AddressF32(ctx, mem, address, first + 2u)
|
? AddressF32(ctx, mem, address, first + 2u)
|
||||||
: ZeroF32(ctx.state);
|
: ZeroF32(ctx.state);
|
||||||
if (mem.image_cube) z = CubeLayer(ctx.state, z);
|
if (cube) z = CubeLayer(ctx.state, z);
|
||||||
ctx.state.builder.AddFunction(
|
ctx.state.builder.AddFunction(
|
||||||
{OpCompositeConstruct, TypeF32Vector(ctx.state, 3), result, x, y, z});
|
{OpCompositeConstruct, TypeF32Vector(ctx.state, 3), result, x, y, z});
|
||||||
} else {
|
} else {
|
||||||
@@ -284,9 +285,9 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass i
|
|||||||
|
|
||||||
uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||||
const IR::Inst& address) {
|
const IR::Inst& address) {
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = ctx.state.program.info.images.at(mem.resource).dimension;
|
||||||
const auto& info = ImageDimensionInfoFor(dimension);
|
const auto& info = ImageDimensionInfoFor(dimension);
|
||||||
const auto image = LoadSampledImageDescriptor(ctx.state, mem, dimension);
|
const auto image = LoadSampledImageDescriptor(ctx.state, mem.resource);
|
||||||
const auto size = ctx.state.builder.AllocateId();
|
const auto size = ctx.state.builder.AllocateId();
|
||||||
if (info.multisampled != 0u) {
|
if (info.multisampled != 0u) {
|
||||||
ctx.state.builder.AddFunction(
|
ctx.state.builder.AddFunction(
|
||||||
@@ -464,7 +465,7 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
|||||||
uint32_t coord, SampledImageClass image_class) {
|
uint32_t coord, SampledImageClass image_class) {
|
||||||
auto& state = ctx.state;
|
auto& state = ctx.state;
|
||||||
state.builder.RequireCapability(CapabilityImageQuery);
|
state.builder.RequireCapability(CapabilityImageQuery);
|
||||||
const auto image = LoadSampledImageDescriptor(state, mem, ImageDimension::Dim1D);
|
const auto image = LoadSampledImageDescriptor(state, mem.resource);
|
||||||
const auto width = state.builder.AllocateId();
|
const auto width = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)});
|
{OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)});
|
||||||
@@ -476,7 +477,7 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
|||||||
Binary(state, OpFMul, TypeF32(state), coord, width_f32),
|
Binary(state, OpFMul, TypeF32(state), coord, width_f32),
|
||||||
ConstantF32(state, 0x3f000000u))});
|
ConstantF32(state, 0x3f000000u))});
|
||||||
|
|
||||||
const auto sampled = MakeSampledImage(state, mem, ImageDimension::Dim1D);
|
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||||
const auto vector_type = SampledImageVectorType(state, image_class, 4);
|
const auto vector_type = SampledImageVectorType(state, image_class, 4);
|
||||||
const auto scalar_type = SampledImageScalarType(state, image_class);
|
const auto scalar_type = SampledImageScalarType(state, image_class);
|
||||||
const auto component =
|
const auto component =
|
||||||
@@ -592,6 +593,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
const auto& mem = ctx.Memory(inst);
|
const auto& mem = ctx.Memory(inst);
|
||||||
const auto image_arg = inst.Arg(0);
|
const auto image_arg = inst.Arg(0);
|
||||||
ctx.ResourceIndex(image_arg, IR::ValueOpcode::GetImageResource);
|
ctx.ResourceIndex(image_arg, IR::ValueOpcode::GetImageResource);
|
||||||
|
const auto& image = state.program.info.images.at(mem.resource);
|
||||||
const auto* address = ctx.ImageAddress(inst.Arg(image_info.needs_sampler ? 2 : 1));
|
const auto* address = ctx.ImageAddress(inst.Arg(image_info.needs_sampler ? 2 : 1));
|
||||||
if (address == nullptr) return true;
|
if (address == nullptr) return true;
|
||||||
if (op == IR::ValueOpcode::ImageQueryDimensions) {
|
if (op == IR::ValueOpcode::ImageQueryDimensions) {
|
||||||
@@ -601,8 +603,8 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
if (op == IR::ValueOpcode::ImageQueryLod) {
|
if (op == IR::ValueOpcode::ImageQueryLod) {
|
||||||
state.builder.RequireCapability(CapabilityImageQuery);
|
state.builder.RequireCapability(CapabilityImageQuery);
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = image.dimension;
|
||||||
const auto sampled = MakeSampledImage(state, mem, dimension);
|
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||||
const auto lod = state.builder.AllocateId();
|
const auto lod = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled,
|
{OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled,
|
||||||
@@ -621,27 +623,27 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (op == IR::ValueOpcode::ImageRead) {
|
if (op == IR::ValueOpcode::ImageRead) {
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = image.dimension;
|
||||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||||
const auto image_class = SampledImageClassFor(mem.kind);
|
const auto image_class = SampledImageClassFor(image.numeric_class);
|
||||||
const auto condition = ctx.Arg(inst, 2);
|
const auto condition = ctx.Arg(inst, 2);
|
||||||
ctx.Define(
|
ctx.Define(
|
||||||
inst,
|
inst,
|
||||||
EmitValueOrDefaultIfCondition(
|
EmitValueOrDefaultIfCondition(
|
||||||
state, condition, TypeU32Vector(state, 4), ConstantU32CompositeZero(state, 4),
|
state, condition, TypeU32Vector(state, 4), ConstantU32CompositeZero(state, 4),
|
||||||
[&]() {
|
[&]() {
|
||||||
const auto image = LoadSampledImageDescriptor(state, mem, dimension);
|
const auto descriptor = LoadSampledImageDescriptor(state, mem.resource);
|
||||||
const auto color = state.builder.AllocateId();
|
const auto color = state.builder.AllocateId();
|
||||||
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
||||||
if (dimension_info.multisampled != 0u) {
|
if (dimension_info.multisampled != 0u) {
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpImageFetch, SampledImageVectorType(state, image_class, 4), color,
|
{OpImageFetch, SampledImageVectorType(state, image_class, 4), color,
|
||||||
image, coord, ImageOperandsSampleMask,
|
descriptor, coord, ImageOperandsSampleMask,
|
||||||
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
||||||
} else {
|
} else {
|
||||||
state.builder.AddFunction({OpImageFetch,
|
state.builder.AddFunction({OpImageFetch,
|
||||||
SampledImageVectorType(state, image_class, 4),
|
SampledImageVectorType(state, image_class, 4),
|
||||||
color, image, coord, ImageOperandsLodMask,
|
color, descriptor, coord, ImageOperandsLodMask,
|
||||||
LodU32(ctx, mem, *address, dimension)});
|
LodU32(ctx, mem, *address, dimension)});
|
||||||
}
|
}
|
||||||
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false,
|
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false,
|
||||||
@@ -650,8 +652,8 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (op == IR::ValueOpcode::ImageWrite) {
|
if (op == IR::ValueOpcode::ImageWrite) {
|
||||||
const auto uint_image = mem.kind == IR::ResourceKind::StorageImageUint;
|
const bool uint_image = image.numeric_class == Prospero::TextureNumericClass::Uint;
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = image.dimension;
|
||||||
EmitIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
EmitIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
||||||
const auto mip_lod =
|
const auto mip_lod =
|
||||||
state.program.info.images[mem.resource].mip_mode == IR::ImageMipMode::DynamicStorage
|
state.program.info.images[mem.resource].mip_mode == IR::ImageMipMode::DynamicStorage
|
||||||
@@ -659,15 +661,15 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
: 0u;
|
: 0u;
|
||||||
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
||||||
const auto texel = StoreTexel(ctx, mem, ctx.Arg(inst, 2), uint_image);
|
const auto texel = StoreTexel(ctx, mem, ctx.Arg(inst, 2), uint_image);
|
||||||
EmitStorageImageWrite(state, mem.resource, dimension, mip_lod, coord, texel);
|
EmitStorageImageWrite(state, mem.resource, mip_lod, coord, texel);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (op == IR::ValueOpcode::ImageSampleRaw || op == IR::ValueOpcode::ImageGatherRaw) {
|
if (op == IR::ValueOpcode::ImageSampleRaw || op == IR::ValueOpcode::ImageGatherRaw) {
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = image.dimension;
|
||||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||||
const auto layout = Layout(mem, dimension);
|
const auto layout = Layout(mem, dimension);
|
||||||
const auto image_class = SampledImageClassFor(mem.kind);
|
const auto image_class = SampledImageClassFor(image.numeric_class);
|
||||||
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
||||||
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
||||||
Prospero::BufferFormat::kInvalid) {
|
Prospero::BufferFormat::kInvalid) {
|
||||||
@@ -693,7 +695,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
ctx.Fail(inst, "has an unsupported 1D-array gather");
|
ctx.Fail(inst, "has an unsupported 1D-array gather");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto sampled = MakeSampledImage(state, mem, dimension);
|
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||||
const auto sample = state.builder.AllocateId();
|
const auto sample = state.builder.AllocateId();
|
||||||
std::vector<uint32_t> words =
|
std::vector<uint32_t> words =
|
||||||
dref ? std::vector<uint32_t> {OpImageDrefGather,
|
dref ? std::vector<uint32_t> {OpImageDrefGather,
|
||||||
@@ -759,7 +761,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
operands.push_back(AddressF32(ctx, mem, *address, layout.bias));
|
operands.push_back(AddressF32(ctx, mem, *address, layout.bias));
|
||||||
}
|
}
|
||||||
const auto EmitSample = [&](uint32_t resource) {
|
const auto EmitSample = [&](uint32_t resource) {
|
||||||
const auto sampled = MakeSampledImage(state, mem, dimension, resource);
|
const auto sampled = MakeSampledImage(state, resource, mem.sampler);
|
||||||
const auto sample = state.builder.AllocateId();
|
const auto sample = state.builder.AllocateId();
|
||||||
std::vector<uint32_t> words {opcode, result_type, sample, sampled, coord};
|
std::vector<uint32_t> words {opcode, result_type, sample, sampled, coord};
|
||||||
if (dref) {
|
if (dref) {
|
||||||
@@ -772,7 +774,6 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
state.builder.AddFunction(words);
|
state.builder.AddFunction(words);
|
||||||
return sample;
|
return sample;
|
||||||
};
|
};
|
||||||
const auto& image = state.program.info.images[mem.resource];
|
|
||||||
if (image.indirect_root != mem.resource) {
|
if (image.indirect_root != mem.resource) {
|
||||||
const auto sample = EmitSample(mem.resource);
|
const auto sample = EmitSample(mem.resource);
|
||||||
ctx.Define(inst, ResultVector(ctx, dref ? sample : UnpackImageTexel(ctx, mem, sample),
|
ctx.Define(inst, ResultVector(ctx, dref ? sample : UnpackImageTexel(ctx, mem, sample),
|
||||||
@@ -874,14 +875,14 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
const auto atomic_opcode = ImageAtomicOpcode(op);
|
const auto atomic_opcode = ImageAtomicOpcode(op);
|
||||||
if (atomic_opcode != 0u) {
|
if (atomic_opcode != 0u) {
|
||||||
const auto dimension = mem.image_dimension;
|
const auto dimension = image.dimension;
|
||||||
ctx.Define(inst, EmitValueOrZeroIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
ctx.Define(inst, EmitValueOrZeroIfCondition(state, ctx.Arg(inst, 3), [&]() {
|
||||||
const auto pointer = state.builder.AllocateId();
|
const auto pointer = state.builder.AllocateId();
|
||||||
const auto pointer_type =
|
const auto pointer_type =
|
||||||
state.builder.Type(OpTypePointer, {StorageClassImage, TypeU32(state)});
|
state.builder.Type(OpTypePointer, {StorageClassImage, TypeU32(state)});
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpImageTexelPointer, pointer_type, pointer,
|
{OpImageTexelPointer, pointer_type, pointer,
|
||||||
StorageImageDescriptorPointer(state, mem.resource, dimension),
|
StorageImageDescriptorPointer(state, mem.resource),
|
||||||
CoordU32(ctx, mem, *address, dimension), ConstantU32(state, 0)});
|
CoordU32(ctx, mem, *address, dimension), ConstantU32(state, 0)});
|
||||||
const auto old = state.builder.AllocateId();
|
const auto old = state.builder.AllocateId();
|
||||||
state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer,
|
state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer,
|
||||||
|
|||||||
@@ -482,13 +482,14 @@ struct ImageSampleLayout {
|
|||||||
uint32_t grad_y = NoImageComponent;
|
uint32_t grad_y = NoImageComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr SampledImageClass SampledImageClassFor(IR::ResourceKind kind) {
|
constexpr SampledImageClass SampledImageClassFor(Prospero::TextureNumericClass numeric_class) {
|
||||||
switch (kind) {
|
switch (numeric_class) {
|
||||||
case IR::ResourceKind::Image: return SampledImageClass::Float;
|
case Prospero::TextureNumericClass::Float: return SampledImageClass::Float;
|
||||||
case IR::ResourceKind::ImageUint: return SampledImageClass::Uint;
|
case Prospero::TextureNumericClass::Uint: return SampledImageClass::Uint;
|
||||||
case IR::ResourceKind::ImageSint: return SampledImageClass::Sint;
|
case Prospero::TextureNumericClass::Sint: return SampledImageClass::Sint;
|
||||||
default: return SampledImageClass::Count;
|
case Prospero::TextureNumericClass::Unsupported: return SampledImageClass::Count;
|
||||||
}
|
}
|
||||||
|
return SampledImageClass::Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsIntegerSampledImage(SampledImageClass image_class) {
|
constexpr bool IsIntegerSampledImage(SampledImageClass image_class) {
|
||||||
@@ -500,16 +501,6 @@ inline uint32_t SampledImageIndex(SampledImageClass image_class, ImageDimension
|
|||||||
static_cast<uint32_t>(image_class) * SampledImageDimensionCount;
|
static_cast<uint32_t>(image_class) * SampledImageDimensionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr StorageImageClass StorageImageClassFor(bool uint_image, bool atomic) {
|
|
||||||
if (atomic) {
|
|
||||||
return StorageImageClass::AtomicUint;
|
|
||||||
}
|
|
||||||
if (uint_image) {
|
|
||||||
return StorageImageClass::FormatlessUint;
|
|
||||||
}
|
|
||||||
return StorageImageClass::FormatlessFloat;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t StorageImageIndex(StorageImageClass image_class, ImageDimension dimension) {
|
inline uint32_t StorageImageIndex(StorageImageClass image_class, ImageDimension dimension) {
|
||||||
return ImageDimensionInfoFor(dimension).ordinal +
|
return ImageDimensionInfoFor(dimension).ordinal +
|
||||||
static_cast<uint32_t>(image_class) * StorageImageDimensionCount;
|
static_cast<uint32_t>(image_class) * StorageImageDimensionCount;
|
||||||
@@ -667,20 +658,16 @@ uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class,
|
|||||||
uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class,
|
uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class,
|
||||||
ImageDimension dimension);
|
ImageDimension dimension);
|
||||||
|
|
||||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem,
|
uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource);
|
||||||
ImageDimension dimension);
|
|
||||||
|
|
||||||
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler);
|
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler);
|
||||||
|
|
||||||
uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension);
|
uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler);
|
||||||
uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension,
|
|
||||||
uint32_t image_resource);
|
|
||||||
|
|
||||||
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource,
|
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource);
|
||||||
ImageDimension dimension);
|
|
||||||
|
|
||||||
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension,
|
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord,
|
||||||
uint32_t mip_lod, uint32_t coord, uint32_t texel);
|
uint32_t texel);
|
||||||
|
|
||||||
uint32_t ExecutionModelForStage(ShaderType stage);
|
uint32_t ExecutionModelForStage(ShaderType stage);
|
||||||
|
|
||||||
|
|||||||
@@ -84,18 +84,7 @@ ResourceKind MemoryKind(const Decoder::Instruction& decoded) {
|
|||||||
case Decoder::Family::MTBUF: return ResourceKind::Buffer;
|
case Decoder::Family::MTBUF: return ResourceKind::Buffer;
|
||||||
case Decoder::Family::FLAT: return FlatSegmentResourceKind(decoded.memory_segment);
|
case Decoder::Family::FLAT: return FlatSegmentResourceKind(decoded.memory_segment);
|
||||||
case Decoder::Family::DS: return decoded.gds ? ResourceKind::Gds : ResourceKind::Lds;
|
case Decoder::Family::DS: return decoded.gds ? ResourceKind::Gds : ResourceKind::Lds;
|
||||||
case Decoder::Family::MIMG:
|
case Decoder::Family::MIMG: return ResourceKind::Image;
|
||||||
switch (decoded.opcode) {
|
|
||||||
case Decoder::Opcode::IMAGE_STORE:
|
|
||||||
case Decoder::Opcode::IMAGE_STORE_MIP: return ResourceKind::StorageImage;
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_ADD:
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_UMIN:
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_UMAX:
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_AND:
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_OR:
|
|
||||||
case Decoder::Opcode::IMAGE_ATOMIC_XOR: return ResourceKind::StorageImageUint;
|
|
||||||
default: return ResourceKind::Image;
|
|
||||||
}
|
|
||||||
default: return ResourceKind::None;
|
default: return ResourceKind::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,10 +142,6 @@ IR::MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded) {
|
|||||||
decoded.opcode == Decoder::Opcode::DS_WRITE2ST64_B32) {
|
decoded.opcode == Decoder::Opcode::DS_WRITE2ST64_B32) {
|
||||||
memory.data_dwords = 2u;
|
memory.data_dwords = 2u;
|
||||||
}
|
}
|
||||||
if (memory.kind == ResourceKind::StorageImage ||
|
|
||||||
memory.kind == ResourceKind::StorageImageUint) {
|
|
||||||
memory.sampler = 0;
|
|
||||||
}
|
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +225,10 @@ Decoder::Operand MemorySourceAt(const Decoder::Instruction& decoded, uint32_t in
|
|||||||
decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP ||
|
decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP ||
|
||||||
(decoded.opcode >= Decoder::Opcode::IMAGE_ATOMIC_ADD &&
|
(decoded.opcode >= Decoder::Opcode::IMAGE_ATOMIC_ADD &&
|
||||||
decoded.opcode <= Decoder::Opcode::IMAGE_ATOMIC_XOR);
|
decoded.opcode <= Decoder::Opcode::IMAGE_ATOMIC_XOR);
|
||||||
return store_or_atomic ? (index == 0u ? decoded.dst : decoded.src0) : decoded.src0;
|
if (store_or_atomic) {
|
||||||
|
return index == 0u ? decoded.dst : decoded.src0;
|
||||||
|
}
|
||||||
|
return decoded.src0;
|
||||||
}
|
}
|
||||||
if (decoded.family == Decoder::Family::DS) {
|
if (decoded.family == Decoder::Family::DS) {
|
||||||
switch (decoded.opcode) {
|
switch (decoded.opcode) {
|
||||||
|
|||||||
@@ -450,7 +450,8 @@ void ValidateProgram(const Program& program, bool require_ssa) {
|
|||||||
ValueOpcodeName(inst.GetOpcode())));
|
ValueOpcodeName(inst.GetOpcode())));
|
||||||
}
|
}
|
||||||
const auto& memory = program.memory_info[memory_index];
|
const auto& memory = program.memory_info[memory_index];
|
||||||
if (!ImageResourceKindMatches(memory.kind, image_info.resource_class)) {
|
if (memory.kind != ResourceKind::Image ||
|
||||||
|
image_info.resource_class == ImageResourceClass::None) {
|
||||||
return Fail(fmt::format("{} has invalid image-memory metadata",
|
return Fail(fmt::format("{} has invalid image-memory metadata",
|
||||||
ValueOpcodeName(inst.GetOpcode())));
|
ValueOpcodeName(inst.GetOpcode())));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "common/stringUtils.h"
|
#include "common/stringUtils.h"
|
||||||
#include "graphics/guest_gpu/gpu_defs.h"
|
#include "graphics/guest_gpu/gpu_defs.h"
|
||||||
|
#include "graphics/guest_gpu/gpu_format.h"
|
||||||
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
||||||
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
||||||
#include "graphics/shader/recompiler/ir/Block.h"
|
#include "graphics/shader/recompiler/ir/Block.h"
|
||||||
@@ -30,10 +31,6 @@ enum class ResourceKind {
|
|||||||
Lds,
|
Lds,
|
||||||
Gds,
|
Gds,
|
||||||
Image,
|
Image,
|
||||||
ImageUint,
|
|
||||||
ImageSint,
|
|
||||||
StorageImage,
|
|
||||||
StorageImageUint,
|
|
||||||
Sampler
|
Sampler
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,20 +39,6 @@ enum class ResourceKind {
|
|||||||
kind == ResourceKind::Global || kind == ResourceKind::Scratch;
|
kind == ResourceKind::Global || kind == ResourceKind::Scratch;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool ImageResourceKindMatches(ResourceKind kind,
|
|
||||||
ImageResourceClass resource_class) {
|
|
||||||
switch (resource_class) {
|
|
||||||
case ImageResourceClass::Sampled:
|
|
||||||
return kind == ResourceKind::Image || kind == ResourceKind::ImageUint ||
|
|
||||||
kind == ResourceKind::ImageSint;
|
|
||||||
case ImageResourceClass::Storage:
|
|
||||||
return kind == ResourceKind::StorageImage || kind == ResourceKind::StorageImageUint;
|
|
||||||
case ImageResourceClass::StorageUint: return kind == ResourceKind::StorageImageUint;
|
|
||||||
case ImageResourceClass::None: return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MemoryInfo {
|
struct MemoryInfo {
|
||||||
ResourceKind kind = ResourceKind::None;
|
ResourceKind kind = ResourceKind::None;
|
||||||
uint32_t resource = 0;
|
uint32_t resource = 0;
|
||||||
@@ -80,7 +63,6 @@ struct MemoryInfo {
|
|||||||
bool typed = false;
|
bool typed = false;
|
||||||
bool formatted = false;
|
bool formatted = false;
|
||||||
bool image_has_mip = false;
|
bool image_has_mip = false;
|
||||||
bool image_cube = false;
|
|
||||||
bool image_r128 = false;
|
bool image_r128 = false;
|
||||||
bool glc = false;
|
bool glc = false;
|
||||||
bool slc = false;
|
bool slc = false;
|
||||||
@@ -142,7 +124,8 @@ struct ImageResource {
|
|||||||
|
|
||||||
uint32_t source = 0;
|
uint32_t source = 0;
|
||||||
uint32_t first_use_pc = 0;
|
uint32_t first_use_pc = 0;
|
||||||
ResourceKind kind = ResourceKind::None;
|
ImageResourceClass resource_class = ImageResourceClass::None;
|
||||||
|
Prospero::TextureNumericClass numeric_class = Prospero::TextureNumericClass::Unsupported;
|
||||||
Decoder::ImageDimension dimension = Decoder::ImageDimension::Unknown;
|
Decoder::ImageDimension dimension = Decoder::ImageDimension::Unknown;
|
||||||
ImageMipMode mip_mode = ImageMipMode::None;
|
ImageMipMode mip_mode = ImageMipMode::None;
|
||||||
uint32_t mip_count = 1;
|
uint32_t mip_count = 1;
|
||||||
@@ -335,19 +318,11 @@ DescriptorBindingForImage(const ImageResource& image) {
|
|||||||
using Dimension = Decoder::ImageDimension;
|
using Dimension = Decoder::ImageDimension;
|
||||||
using Kind = DescriptorBindingKind;
|
using Kind = DescriptorBindingKind;
|
||||||
|
|
||||||
switch (image.kind) {
|
switch (image.resource_class) {
|
||||||
case ResourceKind::Image:
|
case ImageResourceClass::Sampled:
|
||||||
switch (image.dimension) {
|
switch (image.numeric_class) {
|
||||||
case Dimension::Dim1D: return Kind::Sampled1D;
|
case Prospero::TextureNumericClass::Float: break;
|
||||||
case Dimension::Dim1DArray: return Kind::Sampled1DArray;
|
case Prospero::TextureNumericClass::Uint:
|
||||||
case Dimension::Dim2D: return Kind::Sampled2D;
|
|
||||||
case Dimension::Dim2DArray: return Kind::Sampled2DArray;
|
|
||||||
case Dimension::Dim2DMsaa: return Kind::Sampled2DMsaa;
|
|
||||||
case Dimension::Dim2DMsaaArray: return Kind::Sampled2DMsaaArray;
|
|
||||||
case Dimension::Dim3D: return Kind::Sampled3D;
|
|
||||||
default: return std::nullopt;
|
|
||||||
}
|
|
||||||
case ResourceKind::ImageUint:
|
|
||||||
switch (image.dimension) {
|
switch (image.dimension) {
|
||||||
case Dimension::Dim1D: return Kind::SampledUint1D;
|
case Dimension::Dim1D: return Kind::SampledUint1D;
|
||||||
case Dimension::Dim1DArray: return Kind::SampledUint1DArray;
|
case Dimension::Dim1DArray: return Kind::SampledUint1DArray;
|
||||||
@@ -358,7 +333,7 @@ DescriptorBindingForImage(const ImageResource& image) {
|
|||||||
case Dimension::Dim3D: return Kind::SampledUint3D;
|
case Dimension::Dim3D: return Kind::SampledUint3D;
|
||||||
default: return std::nullopt;
|
default: return std::nullopt;
|
||||||
}
|
}
|
||||||
case ResourceKind::ImageSint:
|
case Prospero::TextureNumericClass::Sint:
|
||||||
switch (image.dimension) {
|
switch (image.dimension) {
|
||||||
case Dimension::Dim1D: return Kind::SampledSint1D;
|
case Dimension::Dim1D: return Kind::SampledSint1D;
|
||||||
case Dimension::Dim1DArray: return Kind::SampledSint1DArray;
|
case Dimension::Dim1DArray: return Kind::SampledSint1DArray;
|
||||||
@@ -369,10 +344,34 @@ DescriptorBindingForImage(const ImageResource& image) {
|
|||||||
case Dimension::Dim3D: return Kind::SampledSint3D;
|
case Dimension::Dim3D: return Kind::SampledSint3D;
|
||||||
default: return std::nullopt;
|
default: return std::nullopt;
|
||||||
}
|
}
|
||||||
case ResourceKind::StorageImage:
|
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
||||||
|
}
|
||||||
|
switch (image.dimension) {
|
||||||
|
case Dimension::Dim1D: return Kind::Sampled1D;
|
||||||
|
case Dimension::Dim1DArray: return Kind::Sampled1DArray;
|
||||||
|
case Dimension::Dim2D: return Kind::Sampled2D;
|
||||||
|
case Dimension::Dim2DArray: return Kind::Sampled2DArray;
|
||||||
|
case Dimension::Dim2DMsaa: return Kind::Sampled2DMsaa;
|
||||||
|
case Dimension::Dim2DMsaaArray: return Kind::Sampled2DMsaaArray;
|
||||||
|
case Dimension::Dim3D: return Kind::Sampled3D;
|
||||||
|
default: return std::nullopt;
|
||||||
|
}
|
||||||
|
case ImageResourceClass::Storage:
|
||||||
if (image.atomic) {
|
if (image.atomic) {
|
||||||
|
if (image.numeric_class != Prospero::TextureNumericClass::Uint) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
switch (image.dimension) {
|
||||||
|
case Dimension::Dim1D: return Kind::StorageAtomic1D;
|
||||||
|
case Dimension::Dim1DArray: return Kind::StorageAtomic1DArray;
|
||||||
|
case Dimension::Dim2D: return Kind::StorageAtomic2D;
|
||||||
|
case Dimension::Dim2DArray: return Kind::StorageAtomic2DArray;
|
||||||
|
case Dimension::Dim3D: return Kind::StorageAtomic3D;
|
||||||
|
default: return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (image.numeric_class) {
|
||||||
|
case Prospero::TextureNumericClass::Float:
|
||||||
switch (image.dimension) {
|
switch (image.dimension) {
|
||||||
case Dimension::Dim1D: return Kind::Storage1D;
|
case Dimension::Dim1D: return Kind::Storage1D;
|
||||||
case Dimension::Dim1DArray: return Kind::Storage1DArray;
|
case Dimension::Dim1DArray: return Kind::Storage1DArray;
|
||||||
@@ -381,37 +380,21 @@ DescriptorBindingForImage(const ImageResource& image) {
|
|||||||
case Dimension::Dim3D: return Kind::Storage3D;
|
case Dimension::Dim3D: return Kind::Storage3D;
|
||||||
default: return std::nullopt;
|
default: return std::nullopt;
|
||||||
}
|
}
|
||||||
case ResourceKind::StorageImageUint:
|
case Prospero::TextureNumericClass::Uint:
|
||||||
switch (image.dimension) {
|
switch (image.dimension) {
|
||||||
case Dimension::Dim1D:
|
case Dimension::Dim1D: return Kind::StorageUint1D;
|
||||||
if (image.atomic) {
|
case Dimension::Dim1DArray: return Kind::StorageUint1DArray;
|
||||||
return Kind::StorageAtomic1D;
|
case Dimension::Dim2D: return Kind::StorageUint2D;
|
||||||
}
|
case Dimension::Dim2DArray: return Kind::StorageUint2DArray;
|
||||||
return Kind::StorageUint1D;
|
case Dimension::Dim3D: return Kind::StorageUint3D;
|
||||||
case Dimension::Dim1DArray:
|
|
||||||
if (image.atomic) {
|
|
||||||
return Kind::StorageAtomic1DArray;
|
|
||||||
}
|
|
||||||
return Kind::StorageUint1DArray;
|
|
||||||
case Dimension::Dim2D:
|
|
||||||
if (image.atomic) {
|
|
||||||
return Kind::StorageAtomic2D;
|
|
||||||
}
|
|
||||||
return Kind::StorageUint2D;
|
|
||||||
case Dimension::Dim2DArray:
|
|
||||||
if (image.atomic) {
|
|
||||||
return Kind::StorageAtomic2DArray;
|
|
||||||
}
|
|
||||||
return Kind::StorageUint2DArray;
|
|
||||||
case Dimension::Dim3D:
|
|
||||||
if (image.atomic) {
|
|
||||||
return Kind::StorageAtomic3D;
|
|
||||||
}
|
|
||||||
return Kind::StorageUint3D;
|
|
||||||
default: return std::nullopt;
|
default: return std::nullopt;
|
||||||
}
|
}
|
||||||
default: return std::nullopt;
|
case Prospero::TextureNumericClass::Sint:
|
||||||
|
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
||||||
}
|
}
|
||||||
|
case ImageResourceClass::None: return std::nullopt;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DescriptorBinding {
|
struct DescriptorBinding {
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ ImageOpcodeInfo ImageOpcodeInfoOf(ValueOpcode opcode) {
|
|||||||
case ValueOpcode::ImageAtomicAnd32:
|
case ValueOpcode::ImageAtomicAnd32:
|
||||||
case ValueOpcode::ImageAtomicOr32:
|
case ValueOpcode::ImageAtomicOr32:
|
||||||
case ValueOpcode::ImageAtomicXor32:
|
case ValueOpcode::ImageAtomicXor32:
|
||||||
return {ImageAccess::Atomic, ImageResourceClass::StorageUint, false};
|
return {ImageAccess::Atomic, ImageResourceClass::Storage, false};
|
||||||
default: return {};
|
default: return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ enum class BufferAccess { None, Read, Write, Atomic };
|
|||||||
enum class SharedAccess { None, Read, Write, Atomic, Append, Consume };
|
enum class SharedAccess { None, Read, Write, Atomic, Append, Consume };
|
||||||
enum class AddressAccess { None, Read, Write };
|
enum class AddressAccess { None, Read, Write };
|
||||||
enum class ImageAccess { None, Read, Write, Atomic };
|
enum class ImageAccess { None, Read, Write, Atomic };
|
||||||
enum class ImageResourceClass { None, Sampled, Storage, StorageUint };
|
enum class ImageResourceClass { None, Sampled, Storage };
|
||||||
|
|
||||||
struct AddressOpcodeInfo {
|
struct AddressOpcodeInfo {
|
||||||
AddressAccess access = AddressAccess::None;
|
AddressAccess access = AddressAccess::None;
|
||||||
|
|||||||
@@ -89,17 +89,8 @@ Prospero::BufferFormat ImageConversionFormat(Prospero::BufferFormat format) {
|
|||||||
: Prospero::BufferFormat::kInvalid;
|
: Prospero::BufferFormat::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Prospero::TextureNumericClass SampledResourceNumericClass(ResourceKind kind) {
|
|
||||||
switch (kind) {
|
|
||||||
case ResourceKind::Image: return Prospero::TextureNumericClass::Float;
|
|
||||||
case ResourceKind::ImageUint: return Prospero::TextureNumericClass::Uint;
|
|
||||||
case ResourceKind::ImageSint: return Prospero::TextureNumericClass::Sint;
|
|
||||||
default: return Prospero::TextureNumericClass::Unsupported;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RequiresPointSampler(const ImageResource& image) {
|
bool RequiresPointSampler(const ImageResource& image) {
|
||||||
return image.kind == ResourceKind::ImageSint ||
|
return image.numeric_class == Prospero::TextureNumericClass::Sint ||
|
||||||
image.conversion_format != Prospero::BufferFormat::kInvalid;
|
image.conversion_format != Prospero::BufferFormat::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +356,8 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
|||||||
if (image.indirect_root != ImageResource::NoIndirectImage) {
|
if (image.indirect_root != ImageResource::NoIndirectImage) {
|
||||||
const auto root = image.indirect_root;
|
const auto root = image.indirect_root;
|
||||||
if (root >= program.info.images.size() ||
|
if (root >= program.info.images.size() ||
|
||||||
program.info.images[root].kind != image.kind ||
|
program.info.images[root].resource_class != image.resource_class ||
|
||||||
|
program.info.images[root].numeric_class != image.numeric_class ||
|
||||||
program.info.images[root].dimension != image.dimension ||
|
program.info.images[root].dimension != image.dimension ||
|
||||||
program.info.images[root].mip_mode != image.mip_mode ||
|
program.info.images[root].mip_mode != image.mip_mode ||
|
||||||
program.info.images[root].mip_count != image.mip_count ||
|
program.info.images[root].mip_count != image.mip_count ||
|
||||||
@@ -376,13 +368,11 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool canonical_kind =
|
const auto canonical_numeric = image.atomic ? Prospero::TextureNumericClass::Uint
|
||||||
image.kind == ResourceKind::Image || image.kind == ResourceKind::StorageImage;
|
: Prospero::TextureNumericClass::Float;
|
||||||
if (image.atomic) {
|
|
||||||
canonical_kind = image.kind == ResourceKind::StorageImageUint;
|
|
||||||
}
|
|
||||||
if (image.dimension != Decoder::ImageDimension::Dim2D || image.cube ||
|
if (image.dimension != Decoder::ImageDimension::Dim2D || image.cube ||
|
||||||
!canonical_kind) {
|
image.resource_class == ImageResourceClass::None ||
|
||||||
|
image.numeric_class != canonical_numeric) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -392,10 +382,10 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
|||||||
DescriptorIsCube(descriptor) != image.cube) {
|
DescriptorIsCube(descriptor) != image.cube) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ImageResourceKindMatches(image.kind, ImageResourceClass::Sampled) ||
|
if (image.resource_class == ImageResourceClass::None) {
|
||||||
ImageResourceKindMatches(image.kind, ImageResourceClass::Storage)) {
|
return false;
|
||||||
const bool storage = image.kind == ResourceKind::StorageImage ||
|
}
|
||||||
image.kind == ResourceKind::StorageImageUint;
|
const bool storage = image.resource_class == ImageResourceClass::Storage;
|
||||||
const auto format =
|
const auto format =
|
||||||
static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
||||||
if (image.atomic && format != Prospero::BufferFormat::k32UInt) {
|
if (image.atomic && format != Prospero::BufferFormat::k32UInt) {
|
||||||
@@ -409,30 +399,24 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
|||||||
image.shader_swizzle != DescriptorImageSwizzle(descriptor)) {
|
image.shader_swizzle != DescriptorImageSwizzle(descriptor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
auto numeric_class = Prospero::SampledTextureNumericClass(format);
|
||||||
if (storage) {
|
if (storage) {
|
||||||
const bool raw_sint = format == Prospero::BufferFormat::k32SInt && image.written &&
|
const bool raw_sint = format == Prospero::BufferFormat::k32SInt && image.written &&
|
||||||
!image.read && !image.atomic;
|
!image.read && !image.atomic;
|
||||||
const auto numeric_class = Prospero::SampledTextureNumericClass(format);
|
|
||||||
if ((!raw_sint && numeric_class == Prospero::TextureNumericClass::Sint) ||
|
if ((!raw_sint && numeric_class == Prospero::TextureNumericClass::Sint) ||
|
||||||
numeric_class == Prospero::TextureNumericClass::Unsupported) {
|
numeric_class == Prospero::TextureNumericClass::Unsupported) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool uint_descriptor =
|
if (raw_sint) {
|
||||||
numeric_class == Prospero::TextureNumericClass::Uint || raw_sint;
|
numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
const bool uint_program = image.kind == ResourceKind::StorageImageUint;
|
}
|
||||||
if (uint_descriptor != uint_program && !(image.atomic && uint_program)) {
|
} else if (image.depth_compare && numeric_class != Prospero::TextureNumericClass::Float) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
if (image.numeric_class != numeric_class) {
|
||||||
const auto numeric_class = SampledResourceNumericClass(image.kind);
|
|
||||||
if (numeric_class != Prospero::SampledTextureNumericClass(format) ||
|
|
||||||
(image.depth_compare &&
|
|
||||||
numeric_class != Prospero::TextureNumericClass::Float)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,24 +612,20 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) {
|
|||||||
for (uint32_t i = 0; i < next.images.size(); i++) {
|
for (uint32_t i = 0; i < next.images.size(); i++) {
|
||||||
const auto& descriptor = next_snapshot.images[i];
|
const auto& descriptor = next_snapshot.images[i];
|
||||||
auto& image = next.images[i];
|
auto& image = next.images[i];
|
||||||
|
if (image.resource_class == ImageResourceClass::None ||
|
||||||
|
(image.atomic && image.resource_class != ImageResourceClass::Storage)) {
|
||||||
|
return SpecializationFail(fmt::format("image resource {} has an invalid class", i));
|
||||||
|
}
|
||||||
image.mip_count = StorageMipCount(image, descriptor);
|
image.mip_count = StorageMipCount(image, descriptor);
|
||||||
if (image.mip_count == 0u) {
|
if (image.mip_count == 0u) {
|
||||||
return SpecializationFail(
|
return SpecializationFail(
|
||||||
fmt::format("storage image descriptor {} has an invalid mip range", i));
|
fmt::format("storage image descriptor {} has an invalid mip range", i));
|
||||||
}
|
}
|
||||||
if (NullImageDescriptor(descriptor)) {
|
if (NullImageDescriptor(descriptor)) {
|
||||||
|
image.numeric_class = image.atomic ? Prospero::TextureNumericClass::Uint
|
||||||
|
: Prospero::TextureNumericClass::Float;
|
||||||
image.dimension = Decoder::ImageDimension::Dim2D;
|
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||||
image.cube = false;
|
image.cube = false;
|
||||||
switch (image.kind) {
|
|
||||||
case ResourceKind::ImageUint: image.kind = ResourceKind::Image; break;
|
|
||||||
case ResourceKind::ImageSint: image.kind = ResourceKind::Image; break;
|
|
||||||
case ResourceKind::StorageImageUint:
|
|
||||||
if (!image.atomic) {
|
|
||||||
image.kind = ResourceKind::StorageImage;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto descriptor_dimension = DescriptorDimension(descriptor, image.dimension);
|
const auto descriptor_dimension = DescriptorDimension(descriptor, image.dimension);
|
||||||
@@ -666,41 +646,32 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) {
|
|||||||
fmt::format("atomic image descriptor {} uses unsupported format {}", i,
|
fmt::format("atomic image descriptor {} uses unsupported format {}", i,
|
||||||
static_cast<uint32_t>(format)));
|
static_cast<uint32_t>(format)));
|
||||||
}
|
}
|
||||||
const bool storage = image.kind == ResourceKind::StorageImage ||
|
const bool storage = image.resource_class == ImageResourceClass::Storage;
|
||||||
image.kind == ResourceKind::StorageImageUint;
|
|
||||||
image.conversion_format = ImageConversionFormat(format);
|
image.conversion_format = ImageConversionFormat(format);
|
||||||
if (storage || image.conversion_format != Prospero::BufferFormat::kInvalid) {
|
if (storage || image.conversion_format != Prospero::BufferFormat::kInvalid) {
|
||||||
image.shader_swizzle = DescriptorImageSwizzle(descriptor);
|
image.shader_swizzle = DescriptorImageSwizzle(descriptor);
|
||||||
}
|
}
|
||||||
const bool raw_sint_storage = storage && format == Prospero::BufferFormat::k32SInt &&
|
const bool raw_sint_storage = storage && format == Prospero::BufferFormat::k32SInt &&
|
||||||
image.written && !image.read && !image.atomic;
|
image.written && !image.read && !image.atomic;
|
||||||
const auto numeric_class = Prospero::SampledTextureNumericClass(format);
|
image.numeric_class = Prospero::SampledTextureNumericClass(format);
|
||||||
if (storage) {
|
if (storage) {
|
||||||
if ((!raw_sint_storage && numeric_class == Prospero::TextureNumericClass::Sint) ||
|
if ((!raw_sint_storage && image.numeric_class == Prospero::TextureNumericClass::Sint) ||
|
||||||
numeric_class == Prospero::TextureNumericClass::Unsupported) {
|
image.numeric_class == Prospero::TextureNumericClass::Unsupported) {
|
||||||
return SpecializationFail(
|
return SpecializationFail(
|
||||||
fmt::format("storage image descriptor {} uses unsupported format {}", i,
|
fmt::format("storage image descriptor {} uses unsupported format {}", i,
|
||||||
static_cast<uint32_t>(format)));
|
static_cast<uint32_t>(format)));
|
||||||
}
|
}
|
||||||
if (numeric_class == Prospero::TextureNumericClass::Uint || raw_sint_storage) {
|
if (raw_sint_storage) {
|
||||||
image.kind = ResourceKind::StorageImageUint;
|
image.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (image.numeric_class == Prospero::TextureNumericClass::Unsupported ||
|
||||||
switch (numeric_class) {
|
(image.depth_compare &&
|
||||||
case Prospero::TextureNumericClass::Uint:
|
image.numeric_class != Prospero::TextureNumericClass::Float)) {
|
||||||
image.kind = ResourceKind::ImageUint;
|
|
||||||
break;
|
|
||||||
case Prospero::TextureNumericClass::Sint:
|
|
||||||
image.kind = ResourceKind::ImageSint;
|
|
||||||
break;
|
|
||||||
case Prospero::TextureNumericClass::Float: break;
|
|
||||||
case Prospero::TextureNumericClass::Unsupported:
|
|
||||||
return SpecializationFail(
|
return SpecializationFail(
|
||||||
fmt::format("sampled image descriptor {} uses unsupported format {}", i,
|
fmt::format("sampled image descriptor {} uses unsupported format {}", i,
|
||||||
static_cast<uint32_t>(format)));
|
static_cast<uint32_t>(format)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (uint32_t root_index = 0; root_index < next.images.size(); root_index++) {
|
for (uint32_t root_index = 0; root_index < next.images.size(); root_index++) {
|
||||||
auto& root = next.images[root_index];
|
auto& root = next.images[root_index];
|
||||||
if (root.indirect_root != root_index) {
|
if (root.indirect_root != root_index) {
|
||||||
@@ -733,14 +704,17 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (NullImageDescriptor(next_snapshot.images[candidate])) {
|
if (NullImageDescriptor(next_snapshot.images[candidate])) {
|
||||||
image.kind = image_class.kind;
|
image.resource_class = image_class.resource_class;
|
||||||
|
image.numeric_class = image_class.numeric_class;
|
||||||
image.dimension = image_class.dimension;
|
image.dimension = image_class.dimension;
|
||||||
image.mip_count = image_class.mip_count;
|
image.mip_count = image_class.mip_count;
|
||||||
image.conversion_format = image_class.conversion_format;
|
image.conversion_format = image_class.conversion_format;
|
||||||
image.shader_swizzle = image_class.shader_swizzle;
|
image.shader_swizzle = image_class.shader_swizzle;
|
||||||
image.cube = image_class.cube;
|
image.cube = image_class.cube;
|
||||||
}
|
}
|
||||||
if (image.kind != image_class.kind || image.dimension != image_class.dimension ||
|
if (image.resource_class != image_class.resource_class ||
|
||||||
|
image.numeric_class != image_class.numeric_class ||
|
||||||
|
image.dimension != image_class.dimension ||
|
||||||
image.mip_mode != image_class.mip_mode ||
|
image.mip_mode != image_class.mip_mode ||
|
||||||
image.mip_count != image_class.mip_count ||
|
image.mip_count != image_class.mip_count ||
|
||||||
image.conversion_format != image_class.conversion_format ||
|
image.conversion_format != image_class.conversion_format ||
|
||||||
@@ -824,9 +798,6 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) {
|
|||||||
fmt::format("indirect image table at pc 0x{:08x} is used by unsupported {}",
|
fmt::format("indirect image table at pc 0x{:08x} is used by unsupported {}",
|
||||||
inst.Flags<MemoryFlags>().pc, ValueOpcodeName(inst.GetOpcode())));
|
inst.Flags<MemoryFlags>().pc, ValueOpcodeName(inst.GetOpcode())));
|
||||||
}
|
}
|
||||||
memory.kind = image.kind;
|
|
||||||
memory.image_dimension = image.dimension;
|
|
||||||
memory.image_cube = image.cube;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
program.info = std::move(next);
|
program.info = std::move(next);
|
||||||
|
|||||||
@@ -80,17 +80,6 @@ uint32_t ByteExtent(const MemoryInfo& memory) {
|
|||||||
return end > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(end);
|
return end > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStorageImage(ResourceKind kind) {
|
|
||||||
return kind == ResourceKind::StorageImage || kind == ResourceKind::StorageImageUint;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageMipMode MipMode(const MemoryInfo& memory) {
|
|
||||||
if (IsStorageImage(memory.kind) && memory.image_has_mip) {
|
|
||||||
return ImageMipMode::DynamicStorage;
|
|
||||||
}
|
|
||||||
return ImageMipMode::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tracker {
|
class Tracker {
|
||||||
public:
|
public:
|
||||||
explicit Tracker(Program& program): m_program(program), m_info(program.info) {
|
explicit Tracker(Program& program): m_program(program), m_info(program.info) {
|
||||||
@@ -526,18 +515,16 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AddImage(uint32_t source, const MemoryInfo& memory, ValueOpcode op, uint32_t pc) {
|
uint32_t AddImage(uint32_t source, const MemoryInfo& memory, ValueOpcode op, uint32_t pc) {
|
||||||
const auto mip = MipMode(memory);
|
const auto resource_class = ImageOpcodeInfoOf(op).resource_class;
|
||||||
|
const auto mip = resource_class == ImageResourceClass::Storage && memory.image_has_mip
|
||||||
|
? ImageMipMode::DynamicStorage
|
||||||
|
: ImageMipMode::None;
|
||||||
const bool depth = (memory.image_sample_flags & Decoder::ImageSampleFlagCompare) != 0;
|
const bool depth = (memory.image_sample_flags & Decoder::ImageSampleFlagCompare) != 0;
|
||||||
for (uint32_t i = 0; i < m_info.images.size(); i++) {
|
for (uint32_t i = 0; i < m_info.images.size(); i++) {
|
||||||
auto& image = m_info.images[i];
|
auto& image = m_info.images[i];
|
||||||
const bool compatible_kind = image.kind == memory.kind || (IsStorageImage(image.kind) &&
|
if (image.source == source && image.resource_class == resource_class &&
|
||||||
IsStorageImage(memory.kind));
|
|
||||||
if (image.source == source && compatible_kind &&
|
|
||||||
image.dimension == memory.image_dimension && image.mip_mode == mip &&
|
image.dimension == memory.image_dimension && image.mip_mode == mip &&
|
||||||
image.depth_compare == depth && image.r128 == memory.image_r128) {
|
image.depth_compare == depth && image.r128 == memory.image_r128) {
|
||||||
if (memory.kind == ResourceKind::StorageImageUint) {
|
|
||||||
image.kind = ResourceKind::StorageImageUint;
|
|
||||||
}
|
|
||||||
Merge(image, op, pc);
|
Merge(image, op, pc);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -548,7 +535,7 @@ private:
|
|||||||
ImageResource image;
|
ImageResource image;
|
||||||
image.source = source;
|
image.source = source;
|
||||||
image.first_use_pc = pc;
|
image.first_use_pc = pc;
|
||||||
image.kind = memory.kind;
|
image.resource_class = resource_class;
|
||||||
image.dimension = memory.image_dimension;
|
image.dimension = memory.image_dimension;
|
||||||
image.mip_mode = mip;
|
image.mip_mode = mip;
|
||||||
image.depth_compare = depth;
|
image.depth_compare = depth;
|
||||||
@@ -681,7 +668,8 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ImageResourceKindMatches(memory.kind, image_info.resource_class)) {
|
if (memory.kind != ResourceKind::Image ||
|
||||||
|
image_info.resource_class == ImageResourceClass::None) {
|
||||||
Fail(flags.pc, "image operation has invalid resource kind");
|
Fail(flags.pc, "image operation has invalid resource kind");
|
||||||
}
|
}
|
||||||
handle = inst.Arg(0).Resolve().TryInstruction();
|
handle = inst.Arg(0).Resolve().TryInstruction();
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ void TestImagesSamplersAndAliases() {
|
|||||||
|
|
||||||
const auto storage = fixture.Image(image_words, 16);
|
const auto storage = fixture.Image(image_words, 16);
|
||||||
MemoryInfo storage_memory;
|
MemoryInfo storage_memory;
|
||||||
storage_memory.kind = ResourceKind::StorageImageUint;
|
storage_memory.kind = ResourceKind::Image;
|
||||||
storage_memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
storage_memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||||
fixture.Emit(ValueOpcode::ImageAtomicIAdd32,
|
fixture.Emit(ValueOpcode::ImageAtomicIAdd32,
|
||||||
{storage, image_address, Value(1u), Value(true)},
|
{storage, image_address, Value(1u), Value(true)},
|
||||||
@@ -713,7 +713,7 @@ void TestDynamicStorageMipTracking() {
|
|||||||
{Value(0u), Value(0u), lod, Value(0u), Value(0u), Value(0u), Value(0u),
|
{Value(0u), Value(0u), lod, Value(0u), Value(0u), Value(0u), Value(0u),
|
||||||
Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u)});
|
Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u)});
|
||||||
MemoryInfo memory;
|
MemoryInfo memory;
|
||||||
memory.kind = ResourceKind::StorageImage;
|
memory.kind = ResourceKind::Image;
|
||||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||||
memory.image_address_components = has_mip ? 3u : 2u;
|
memory.image_address_components = has_mip ? 3u : 2u;
|
||||||
memory.image_has_mip = has_mip;
|
memory.image_has_mip = has_mip;
|
||||||
@@ -776,7 +776,7 @@ void TestDynamicStorageMipTracking() {
|
|||||||
Program null_program;
|
Program null_program;
|
||||||
null_program.resource_tracking_complete = true;
|
null_program.resource_tracking_complete = true;
|
||||||
ImageResource null_image;
|
ImageResource null_image;
|
||||||
null_image.kind = ResourceKind::StorageImage;
|
null_image.resource_class = ImageResourceClass::Storage;
|
||||||
null_image.dimension = Decoder::ImageDimension::Dim2D;
|
null_image.dimension = Decoder::ImageDimension::Dim2D;
|
||||||
null_image.mip_mode = ImageMipMode::DynamicStorage;
|
null_image.mip_mode = ImageMipMode::DynamicStorage;
|
||||||
null_image.written = true;
|
null_image.written = true;
|
||||||
@@ -1283,40 +1283,6 @@ void TestMalformedMemoryKindsRejected() {
|
|||||||
"image operation has invalid resource kind",
|
"image operation has invalid resource kind",
|
||||||
"resource tracking accepted an image opcode with address metadata");
|
"resource tracking accepted an image opcode with address metadata");
|
||||||
}
|
}
|
||||||
{
|
|
||||||
Fixture fixture;
|
|
||||||
const auto image =
|
|
||||||
fixture.Image({Value(0u), Value(0u), Value(0u), Value(0u), Value(0u),
|
|
||||||
Value(0u), Value(0u), Value(0u)},
|
|
||||||
12);
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImage;
|
|
||||||
fixture.Emit(ValueOpcode::ImageRead,
|
|
||||||
{image, fixture.ImageAddress(), Value(true)},
|
|
||||||
fixture.AddMemory(memory, 12));
|
|
||||||
BuildSrtPlan(fixture.program);
|
|
||||||
CheckFatal(
|
|
||||||
[&] { TrackResources(fixture.program); },
|
|
||||||
"image operation has invalid resource kind",
|
|
||||||
"resource tracking accepted a sampled read with storage metadata");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Fixture fixture;
|
|
||||||
const auto image =
|
|
||||||
fixture.Image({Value(0u), Value(0u), Value(0u), Value(0u), Value(0u),
|
|
||||||
Value(0u), Value(0u), Value(0u)},
|
|
||||||
16);
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImage;
|
|
||||||
fixture.Emit(ValueOpcode::ImageAtomicIAdd32,
|
|
||||||
{image, fixture.ImageAddress(), Value(1u), Value(true)},
|
|
||||||
fixture.AddMemory(memory, 16));
|
|
||||||
BuildSrtPlan(fixture.program);
|
|
||||||
CheckFatal(
|
|
||||||
[&] { TrackResources(fixture.program); },
|
|
||||||
"image operation has invalid resource kind",
|
|
||||||
"resource tracking accepted a uint atomic with float storage metadata");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -7721,7 +7721,9 @@ public:
|
|||||||
null_program.stage = ShaderType::Compute;
|
null_program.stage = ShaderType::Compute;
|
||||||
null_program.resource_tracking_complete = true;
|
null_program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource null_resource{};
|
ShaderRecompiler::IR::ImageResource null_resource{};
|
||||||
null_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
|
null_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
null_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
null_resource.dimension =
|
null_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
null_resource.read = true;
|
null_resource.read = true;
|
||||||
@@ -7730,7 +7732,8 @@ public:
|
|||||||
null_volume.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D;
|
null_volume.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D;
|
||||||
null_program.info.images.push_back(null_volume);
|
null_program.info.images.push_back(null_volume);
|
||||||
auto null_storage = null_resource;
|
auto null_storage = null_resource;
|
||||||
null_storage.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
null_storage.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
null_storage.read = false;
|
null_storage.read = false;
|
||||||
null_storage.written = true;
|
null_storage.written = true;
|
||||||
null_program.info.images.push_back(null_storage);
|
null_program.info.images.push_back(null_storage);
|
||||||
@@ -7826,8 +7829,9 @@ public:
|
|||||||
storage_program.stage = ShaderType::Vertex;
|
storage_program.stage = ShaderType::Vertex;
|
||||||
storage_program.resource_tracking_complete = true;
|
storage_program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource storage_resource{};
|
ShaderRecompiler::IR::ImageResource storage_resource{};
|
||||||
storage_resource.kind =
|
storage_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
storage_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
storage_resource.dimension =
|
storage_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
storage_resource.written = true;
|
storage_resource.written = true;
|
||||||
@@ -7870,8 +7874,10 @@ public:
|
|||||||
ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
|
ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
|
||||||
mipped_storage_resource.mip_count = 3;
|
mipped_storage_resource.mip_count = 3;
|
||||||
auto sampled_overwide_resource = storage_resource;
|
auto sampled_overwide_resource = storage_resource;
|
||||||
sampled_overwide_resource.kind =
|
sampled_overwide_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::ImageUint;
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
sampled_overwide_resource.numeric_class =
|
||||||
|
Prospero::TextureNumericClass::Uint;
|
||||||
sampled_overwide_resource.read = true;
|
sampled_overwide_resource.read = true;
|
||||||
sampled_overwide_resource.written = false;
|
sampled_overwide_resource.written = false;
|
||||||
auto plain_mipped_storage_binding =
|
auto plain_mipped_storage_binding =
|
||||||
@@ -7979,8 +7985,10 @@ public:
|
|||||||
srgb_storage_descriptor.dwords.begin());
|
srgb_storage_descriptor.dwords.begin());
|
||||||
srgb_storage_descriptor.dword_count = 8;
|
srgb_storage_descriptor.dword_count = 8;
|
||||||
auto srgb_storage_resource = storage_resource;
|
auto srgb_storage_resource = storage_resource;
|
||||||
srgb_storage_resource.kind =
|
srgb_storage_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImage;
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
srgb_storage_resource.numeric_class =
|
||||||
|
Prospero::TextureNumericClass::Float;
|
||||||
const auto srgb_storage_binding =
|
const auto srgb_storage_binding =
|
||||||
RenderExecutorTestAccess::ResolveTexture(
|
RenderExecutorTestAccess::ResolveTexture(
|
||||||
executor, srgb_storage_resource, srgb_storage_descriptor);
|
executor, srgb_storage_resource, srgb_storage_descriptor);
|
||||||
@@ -8023,8 +8031,9 @@ public:
|
|||||||
sint_storage_descriptor.dwords.begin());
|
sint_storage_descriptor.dwords.begin());
|
||||||
sint_storage_descriptor.dword_count = 8;
|
sint_storage_descriptor.dword_count = 8;
|
||||||
auto sint_storage_resource = srgb_storage_resource;
|
auto sint_storage_resource = srgb_storage_resource;
|
||||||
sint_storage_resource.kind =
|
sint_storage_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
sint_storage_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
const auto sint_storage_binding =
|
const auto sint_storage_binding =
|
||||||
RenderExecutorTestAccess::ResolveTexture(
|
RenderExecutorTestAccess::ResolveTexture(
|
||||||
executor, sint_storage_resource, sint_storage_descriptor);
|
executor, sint_storage_resource, sint_storage_descriptor);
|
||||||
@@ -8105,7 +8114,9 @@ public:
|
|||||||
sampled_program.stage = ShaderType::Pixel;
|
sampled_program.stage = ShaderType::Pixel;
|
||||||
sampled_program.resource_tracking_complete = true;
|
sampled_program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource sampled_resource{};
|
ShaderRecompiler::IR::ImageResource sampled_resource{};
|
||||||
sampled_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
|
sampled_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
sampled_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
sampled_resource.dimension =
|
sampled_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
sampled_resource.read = true;
|
sampled_resource.read = true;
|
||||||
@@ -8551,8 +8562,10 @@ public:
|
|||||||
sampled_depth_value.dwords.begin());
|
sampled_depth_value.dwords.begin());
|
||||||
sampled_depth_value.dword_count = 8;
|
sampled_depth_value.dword_count = 8;
|
||||||
ShaderRecompiler::IR::ImageResource sampled_depth_resource{};
|
ShaderRecompiler::IR::ImageResource sampled_depth_resource{};
|
||||||
sampled_depth_resource.kind =
|
sampled_depth_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::ImageUint;
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
sampled_depth_resource.numeric_class =
|
||||||
|
Prospero::TextureNumericClass::Uint;
|
||||||
sampled_depth_resource.dimension =
|
sampled_depth_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
sampled_depth_resource.read = true;
|
sampled_depth_resource.read = true;
|
||||||
@@ -8661,7 +8674,9 @@ public:
|
|||||||
array_program.stage = ShaderType::Compute;
|
array_program.stage = ShaderType::Compute;
|
||||||
array_program.resource_tracking_complete = true;
|
array_program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource array_resource{};
|
ShaderRecompiler::IR::ImageResource array_resource{};
|
||||||
array_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
|
array_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
array_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
array_resource.dimension =
|
array_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
||||||
array_resource.read = true;
|
array_resource.read = true;
|
||||||
@@ -9078,7 +9093,9 @@ public:
|
|||||||
program.stage = ShaderType::Compute;
|
program.stage = ShaderType::Compute;
|
||||||
program.resource_tracking_complete = true;
|
program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource stencil_resource{};
|
ShaderRecompiler::IR::ImageResource stencil_resource{};
|
||||||
stencil_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
|
stencil_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
stencil_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
stencil_resource.dimension =
|
stencil_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
stencil_resource.read = true;
|
stencil_resource.read = true;
|
||||||
@@ -9151,8 +9168,8 @@ public:
|
|||||||
stencil_storage_program->stage = ShaderType::Compute;
|
stencil_storage_program->stage = ShaderType::Compute;
|
||||||
stencil_storage_program->resource_tracking_complete = true;
|
stencil_storage_program->resource_tracking_complete = true;
|
||||||
auto stencil_storage_resource = stencil_resource;
|
auto stencil_storage_resource = stencil_resource;
|
||||||
stencil_storage_resource.kind =
|
stencil_storage_resource.resource_class =
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
stencil_storage_resource.read = false;
|
stencil_storage_resource.read = false;
|
||||||
stencil_storage_resource.written = true;
|
stencil_storage_resource.written = true;
|
||||||
stencil_storage_program->info.images.push_back(stencil_storage_resource);
|
stencil_storage_program->info.images.push_back(stencil_storage_resource);
|
||||||
@@ -20509,7 +20526,8 @@ void CheckIndirectImageKeySwitch() {
|
|||||||
ImageResource root{};
|
ImageResource root{};
|
||||||
root.source = 0;
|
root.source = 0;
|
||||||
root.first_use_pc = 0x10f0u;
|
root.first_use_pc = 0x10f0u;
|
||||||
root.kind = ResourceKind::Image;
|
root.resource_class = ImageResourceClass::Sampled;
|
||||||
|
root.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
root.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
root.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
root.read = true;
|
root.read = true;
|
||||||
root.indirect_root = 0;
|
root.indirect_root = 0;
|
||||||
@@ -21963,11 +21981,13 @@ void CheckRenderTargetFormatContract() {
|
|||||||
(void)volume.FindView(view);
|
(void)volume.FindView(view);
|
||||||
} else {
|
} else {
|
||||||
ShaderRecompiler::IR::ImageResource resource{};
|
ShaderRecompiler::IR::ImageResource resource{};
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
|
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
resource.written = true;
|
resource.written = true;
|
||||||
if (std::strcmp(kind, "storage-kind") == 0) {
|
if (std::strcmp(kind, "storage-kind") == 0) {
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
} else if (std::strcmp(kind, "storage-no-write") == 0) {
|
} else if (std::strcmp(kind, "storage-no-write") == 0) {
|
||||||
resource.written = false;
|
resource.written = false;
|
||||||
} else if (std::strcmp(kind, "storage-nonuint-atomic") == 0) {
|
} else if (std::strcmp(kind, "storage-nonuint-atomic") == 0) {
|
||||||
@@ -21992,7 +22012,9 @@ void CheckSampledColorViews() {
|
|||||||
DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7),
|
DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7),
|
||||||
"RGBA did not select the identity view");
|
"RGBA did not select the identity view");
|
||||||
ShaderRecompiler::IR::ImageResource cube_resource{};
|
ShaderRecompiler::IR::ImageResource cube_resource{};
|
||||||
cube_resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
cube_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
cube_resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
cube_resource.dimension =
|
cube_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
||||||
cube_resource.read = true;
|
cube_resource.read = true;
|
||||||
@@ -22164,7 +22186,9 @@ void CheckSampledColorViews() {
|
|||||||
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
|
DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1),
|
||||||
"D32S8 depth target did not select its R001 depth-aspect view");
|
"D32S8 depth target did not select its R001 depth-aspect view");
|
||||||
ShaderRecompiler::IR::ImageResource storage_resource{};
|
ShaderRecompiler::IR::ImageResource storage_resource{};
|
||||||
storage_resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
|
storage_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
storage_resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
storage_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
storage_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
storage_resource.written = true;
|
storage_resource.written = true;
|
||||||
Require("SampledColorViews", "storage resource",
|
Require("SampledColorViews", "storage resource",
|
||||||
@@ -22181,7 +22205,7 @@ void CheckSampledColorViews() {
|
|||||||
Require("SampledColorViews", "write-only 2D-array storage resource",
|
Require("SampledColorViews", "write-only 2D-array storage resource",
|
||||||
IsSupportedStorageImageResource(storage_resource),
|
IsSupportedStorageImageResource(storage_resource),
|
||||||
"basic write-only 2D-array storage resource was rejected");
|
"basic write-only 2D-array storage resource was rejected");
|
||||||
storage_resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
storage_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
Require("SampledColorViews", "write-only uint 2D-array storage resource",
|
Require("SampledColorViews", "write-only uint 2D-array storage resource",
|
||||||
IsSupportedStorageImageResource(storage_resource),
|
IsSupportedStorageImageResource(storage_resource),
|
||||||
"basic write-only uint 2D-array storage resource was rejected");
|
"basic write-only uint 2D-array storage resource was rejected");
|
||||||
@@ -22237,7 +22261,8 @@ void CheckSampledColorViews() {
|
|||||||
|
|
||||||
void CheckSampledDepthResource() {
|
void CheckSampledDepthResource() {
|
||||||
ShaderRecompiler::IR::ImageResource resource{};
|
ShaderRecompiler::IR::ImageResource resource{};
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
resource.read = true;
|
resource.read = true;
|
||||||
resource.depth_compare = true;
|
resource.depth_compare = true;
|
||||||
@@ -22289,7 +22314,7 @@ void CheckSampledDepthResource() {
|
|||||||
static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM),
|
static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM),
|
||||||
"array shader resource accepted a non-array descriptor view");
|
"array shader resource accepted a non-array descriptor view");
|
||||||
resource = basic;
|
resource = basic;
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
|
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
Require("SampledDepthResource", "integer read",
|
Require("SampledDepthResource", "integer read",
|
||||||
IsSupportedSampledDepthResource(resource),
|
IsSupportedSampledDepthResource(resource),
|
||||||
"read-only uint depth resource was rejected");
|
"read-only uint depth resource was rejected");
|
||||||
@@ -22310,7 +22335,8 @@ void CheckSampledVideoOutView(RenderContext &renderer) {
|
|||||||
auto &context = renderer.GetGraphics();
|
auto &context = renderer.GetGraphics();
|
||||||
CommandScheduler scheduler(renderer, context);
|
CommandScheduler scheduler(renderer, context);
|
||||||
ShaderRecompiler::IR::ImageResource resource{};
|
ShaderRecompiler::IR::ImageResource resource{};
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
resource.read = true;
|
resource.read = true;
|
||||||
|
|
||||||
@@ -22758,7 +22784,9 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
|
|||||||
Prospero::ImageType::kColor2D));
|
Prospero::ImageType::kColor2D));
|
||||||
cube_image.usage.depth_target = true;
|
cube_image.usage.depth_target = true;
|
||||||
ShaderRecompiler::IR::ImageResource cube_resource{};
|
ShaderRecompiler::IR::ImageResource cube_resource{};
|
||||||
cube_resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
cube_resource.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
cube_resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
cube_resource.dimension =
|
cube_resource.dimension =
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
||||||
cube_resource.read = true;
|
cube_resource.read = true;
|
||||||
@@ -22845,7 +22873,8 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource BasicStorageTextureResource() {
|
ShaderRecompiler::IR::ImageResource BasicStorageTextureResource() {
|
||||||
ShaderRecompiler::IR::ImageResource resource{};
|
ShaderRecompiler::IR::ImageResource resource{};
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
|
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D;
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D;
|
||||||
resource.read = true;
|
resource.read = true;
|
||||||
resource.written = true;
|
resource.written = true;
|
||||||
@@ -22903,7 +22932,7 @@ ShaderTextureResource Ppsa01340OverwideMipStorageTextureDescriptor() {
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource Ppsa01530MaxMipStorageTextureResource() {
|
ShaderRecompiler::IR::ImageResource Ppsa01530MaxMipStorageTextureResource() {
|
||||||
auto resource = BasicBgraStorageTextureResource();
|
auto resource = BasicBgraStorageTextureResource();
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22940,7 +22969,7 @@ ShaderTextureResource BasicArrayStorageTextureDescriptor() {
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource BasicUintArrayStorageTextureResource() {
|
ShaderRecompiler::IR::ImageResource BasicUintArrayStorageTextureResource() {
|
||||||
auto resource = BasicArrayStorageTextureResource();
|
auto resource = BasicArrayStorageTextureResource();
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22975,7 +23004,7 @@ ShaderTextureResource Ppsa10112D16StorageTextureDescriptor() {
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource BasicUintVolumeStorageTextureResource() {
|
ShaderRecompiler::IR::ImageResource BasicUintVolumeStorageTextureResource() {
|
||||||
auto resource = BasicStorageTextureResource();
|
auto resource = BasicStorageTextureResource();
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
resource.read = false;
|
resource.read = false;
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
@@ -22987,7 +23016,7 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() {
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource AtomicStorageTextureResource() {
|
ShaderRecompiler::IR::ImageResource AtomicStorageTextureResource() {
|
||||||
auto resource = BasicLinearStorageTextureResource();
|
auto resource = BasicLinearStorageTextureResource();
|
||||||
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
resource.read = true;
|
resource.read = true;
|
||||||
resource.atomic = true;
|
resource.atomic = true;
|
||||||
return resource;
|
return resource;
|
||||||
@@ -23346,8 +23375,7 @@ void CheckBasicStorageTextureDescriptor() {
|
|||||||
0x00000000u,
|
0x00000000u,
|
||||||
}};
|
}};
|
||||||
auto standard256b_resource = BasicBgraStorageTextureResource();
|
auto standard256b_resource = BasicBgraStorageTextureResource();
|
||||||
standard256b_resource.kind =
|
standard256b_resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
|
||||||
TileSizeAlign standard256b_size{};
|
TileSizeAlign standard256b_size{};
|
||||||
TileGetTextureTotalSize(standard256b.Format(), standard256b.Width5() + 1u,
|
TileGetTextureTotalSize(standard256b.Format(), standard256b.Width5() + 1u,
|
||||||
standard256b.Height5() + 1u,
|
standard256b.Height5() + 1u,
|
||||||
@@ -23645,7 +23673,8 @@ void CheckImageSamplerSpecialization() {
|
|||||||
ShaderRecompiler::IR::Program mixed_sampler_program;
|
ShaderRecompiler::IR::Program mixed_sampler_program;
|
||||||
mixed_sampler_program.resource_tracking_complete = true;
|
mixed_sampler_program.resource_tracking_complete = true;
|
||||||
ShaderRecompiler::IR::ImageResource sampled_image;
|
ShaderRecompiler::IR::ImageResource sampled_image;
|
||||||
sampled_image.kind = ShaderRecompiler::IR::ResourceKind::Image;
|
sampled_image.resource_class =
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
sampled_image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
sampled_image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
sampled_image.read = true;
|
sampled_image.read = true;
|
||||||
mixed_sampler_program.info.images = {sampled_image, sampled_image,
|
mixed_sampler_program.info.images = {sampled_image, sampled_image,
|
||||||
@@ -23739,7 +23768,8 @@ void CheckShaderRecompilerFatalContracts() {
|
|||||||
program.resource_tracking_complete = true;
|
program.resource_tracking_complete = true;
|
||||||
|
|
||||||
ShaderRecompiler::IR::ImageResource image;
|
ShaderRecompiler::IR::ImageResource image;
|
||||||
image.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
image.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||||
|
image.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||||
image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
image.read = true;
|
image.read = true;
|
||||||
image.written = true;
|
image.written = true;
|
||||||
|
|||||||
@@ -9792,46 +9792,6 @@ void TestNativeWideValueValidation() {
|
|||||||
append_image(program, ValueOpcode::ImageRead, {});
|
append_image(program, ValueOpcode::ImageRead, {});
|
||||||
check_rejected(program, "buffer kind for image read was accepted");
|
check_rejected(program, "buffer kind for image read was accepted");
|
||||||
}
|
}
|
||||||
{
|
|
||||||
auto program = make_program();
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImage;
|
|
||||||
program.memory_info.push_back(memory);
|
|
||||||
append_image(program, ValueOpcode::ImageRead, {});
|
|
||||||
check_rejected(program, "storage kind for image read was accepted");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto program = make_program();
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImageUint;
|
|
||||||
program.memory_info.push_back(memory);
|
|
||||||
append_image(program, ValueOpcode::ImageQueryDimensions, {});
|
|
||||||
check_rejected(program, "storage uint kind for image query was accepted");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto program = make_program();
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::Image;
|
|
||||||
program.memory_info.push_back(memory);
|
|
||||||
append_image(program, ValueOpcode::ImageWrite, {});
|
|
||||||
check_rejected(program, "sampled image kind for image write was accepted");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto program = make_program();
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImage;
|
|
||||||
program.memory_info.push_back(memory);
|
|
||||||
append_image(program, ValueOpcode::ImageSampleRaw, {});
|
|
||||||
check_rejected(program, "storage kind for image sample was accepted");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto program = make_program();
|
|
||||||
MemoryInfo memory;
|
|
||||||
memory.kind = ResourceKind::StorageImage;
|
|
||||||
program.memory_info.push_back(memory);
|
|
||||||
append_image(program, ValueOpcode::ImageAtomicIAdd32, {});
|
|
||||||
check_rejected(program, "untyped storage kind for image atomic was accepted");
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto program = make_program();
|
auto program = make_program();
|
||||||
IREmitter ir(program.blocks.front());
|
IREmitter ir(program.blocks.front());
|
||||||
@@ -10435,8 +10395,10 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
|||||||
|
|
||||||
uint32_t float_storage = UINT32_MAX;
|
uint32_t float_storage = UINT32_MAX;
|
||||||
for (uint32_t i = 0; i < result.program.info.images.size(); i++) {
|
for (uint32_t i = 0; i < result.program.info.images.size(); i++) {
|
||||||
if (result.program.info.images[i].kind ==
|
const auto &image = result.program.info.images[i];
|
||||||
ShaderRecompiler::IR::ResourceKind::StorageImage) {
|
if (image.resource_class ==
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Storage &&
|
||||||
|
image.numeric_class == Prospero::TextureNumericClass::Float) {
|
||||||
float_storage = i;
|
float_storage = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user