spirv: Guard against typeless image reads on unsupported devices
This commit is contained in:
		| @@ -238,11 +238,13 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||||||
|             ctx.AddCapability(spv::Capability::SubgroupVoteKHR); |             ctx.AddCapability(spv::Capability::SubgroupVoteKHR); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if (info.uses_typeless_image_reads && profile.support_typeless_image_loads) { | ||||||
|  |         ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); | ||||||
|  |     } | ||||||
|     // TODO: Track this usage |     // TODO: Track this usage | ||||||
|     ctx.AddCapability(spv::Capability::ImageGatherExtended); |     ctx.AddCapability(spv::Capability::ImageGatherExtended); | ||||||
|     ctx.AddCapability(spv::Capability::ImageQuery); |     ctx.AddCapability(spv::Capability::ImageQuery); | ||||||
|     ctx.AddCapability(spv::Capability::SampledBuffer); |     ctx.AddCapability(spv::Capability::SampledBuffer); | ||||||
|     ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); |  | ||||||
| } | } | ||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
|  |  | ||||||
|   | |||||||
| @@ -388,6 +388,10 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | |||||||
|  |  | ||||||
| Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { | ||||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; |     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||||
|  |     if (info.image_format == ImageFormat::Typeless && !ctx.profile.support_typeless_image_loads) { | ||||||
|  |         // LOG_WARNING(..., "Typeless image read not supported by host"); | ||||||
|  |         return ctx.ConstantNull(ctx.U32[4]); | ||||||
|  |     } | ||||||
|     return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], |     return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], | ||||||
|                 Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); |                 Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -421,6 +421,13 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||||||
|             inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr; |             inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     case IR::Opcode::ImageRead: { | ||||||
|  |         const auto flags{inst.Flags<IR::TextureInstInfo>()}; | ||||||
|  |         info.uses_typeless_image_reads |= flags.image_format == ImageFormat::Typeless; | ||||||
|  |         info.uses_sparse_residency |= | ||||||
|  |             inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|     case IR::Opcode::SubgroupEqMask: |     case IR::Opcode::SubgroupEqMask: | ||||||
|     case IR::Opcode::SubgroupLtMask: |     case IR::Opcode::SubgroupLtMask: | ||||||
|     case IR::Opcode::SubgroupLeMask: |     case IR::Opcode::SubgroupLeMask: | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ struct Profile { | |||||||
|     bool support_explicit_workgroup_layout{}; |     bool support_explicit_workgroup_layout{}; | ||||||
|     bool support_vote{}; |     bool support_vote{}; | ||||||
|     bool support_viewport_index_layer_non_geometry{}; |     bool support_viewport_index_layer_non_geometry{}; | ||||||
|  |     bool support_typeless_image_loads{}; | ||||||
|     bool warp_size_potentially_larger_than_guest{}; |     bool warp_size_potentially_larger_than_guest{}; | ||||||
|  |  | ||||||
|     // FClamp is broken and OpFMax + OpFMin should be used instead |     // FClamp is broken and OpFMax + OpFMin should be used instead | ||||||
|   | |||||||
| @@ -127,6 +127,7 @@ struct Info { | |||||||
|     bool uses_subgroup_vote{}; |     bool uses_subgroup_vote{}; | ||||||
|     bool uses_subgroup_mask{}; |     bool uses_subgroup_mask{}; | ||||||
|     bool uses_fswzadd{}; |     bool uses_fswzadd{}; | ||||||
|  |     bool uses_typeless_image_reads{}; | ||||||
|  |  | ||||||
|     IR::Type used_constant_buffer_types{}; |     IR::Type used_constant_buffer_types{}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -635,6 +635,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | |||||||
|         .support_vote = true, |         .support_vote = true, | ||||||
|         .support_viewport_index_layer_non_geometry = |         .support_viewport_index_layer_non_geometry = | ||||||
|             device.IsExtShaderViewportIndexLayerSupported(), |             device.IsExtShaderViewportIndexLayerSupported(), | ||||||
|  |         .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), | ||||||
|         .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), |         .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), | ||||||
|         .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, |         .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, | ||||||
|         .generic_input_types{}, |         .generic_input_types{}, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user