early-access version 4031
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 4030. | ||||
| This is the source code for early-access 4031. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -196,42 +196,34 @@ Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR | ||||
| } | ||||
|  | ||||
| Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& index) { | ||||
|     if (!index.IsImmediate() || index.U32() != 0) { | ||||
|         throw NotImplementedException("Indirect image indexing"); | ||||
|     } | ||||
|     if (info.type == TextureType::Buffer) { | ||||
|         const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             const Id buffer_pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))}; | ||||
|             return ctx.OpLoad(ctx.image_buffer_type, buffer_pointer); | ||||
|         } else { | ||||
|             return ctx.OpLoad(ctx.image_buffer_type, def.id); | ||||
|             throw NotImplementedException("Indirect texture sample"); | ||||
|         } | ||||
|         return ctx.OpLoad(ctx.image_buffer_type, def.id); | ||||
|     } else { | ||||
|         const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             const Id texture_pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))}; | ||||
|             return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, texture_pointer)); | ||||
|         } else { | ||||
|             return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); | ||||
|             throw NotImplementedException("Indirect texture sample"); | ||||
|         } | ||||
|         return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||||
| std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||||
|     if (!index.IsImmediate() || index.U32() != 0) { | ||||
|         throw NotImplementedException("Indirect image indexing"); | ||||
|     } | ||||
|     if (info.type == TextureType::Buffer) { | ||||
|         const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             const Id image_pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))}; | ||||
|             return ctx.OpLoad(def.image_type, image_pointer); | ||||
|         } else { | ||||
|             return ctx.OpLoad(def.image_type, def.id); | ||||
|         } | ||||
|         return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; | ||||
|     } else { | ||||
|         const ImageDefinition def{ctx.images.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             const Id image_pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))}; | ||||
|             return ctx.OpLoad(def.image_type, image_pointer); | ||||
|         } else { | ||||
|             return ctx.OpLoad(def.image_type, def.id); | ||||
|         } | ||||
|         return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -574,13 +566,23 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co | ||||
|         LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); | ||||
|         return ctx.ConstantNull(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>{}); | ||||
|     const auto [image, is_integer] = Image(ctx, index, info); | ||||
|     const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]}; | ||||
|     Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, | ||||
|                   result_type, image, coords, std::nullopt, std::span<const Id>{})}; | ||||
|     if (!is_integer) { | ||||
|         color = ctx.OpBitcast(ctx.U32[4], color); | ||||
|     } | ||||
|     return color; | ||||
| } | ||||
|  | ||||
| void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { | ||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||
|     ctx.OpImageWrite(Image(ctx, index, info), coords, color); | ||||
|     const auto [image, is_integer] = Image(ctx, index, info); | ||||
|     if (!is_integer) { | ||||
|         color = ctx.OpBitcast(ctx.F32[4], color); | ||||
|     } | ||||
|     ctx.OpImageWrite(image, coords, color); | ||||
| } | ||||
|  | ||||
| Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { | ||||
|   | ||||
| @@ -7,21 +7,13 @@ | ||||
|  | ||||
| namespace Shader::Backend::SPIRV { | ||||
| namespace { | ||||
| Id ImagePointer(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||||
| Id Image(EmitContext& ctx, IR::TextureInstInfo info) { | ||||
|     if (info.type == TextureType::Buffer) { | ||||
|         const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             return ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index)); | ||||
|         } else { | ||||
|             return def.id; | ||||
|         } | ||||
|         return def.id; | ||||
|     } else { | ||||
|         const ImageDefinition def{ctx.images.at(info.descriptor_index)}; | ||||
|         if (def.count > 1) { | ||||
|             return ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index)); | ||||
|         } else { | ||||
|             return def.id; | ||||
|         } | ||||
|         return def.id; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -33,12 +25,15 @@ std::pair<Id, Id> AtomicArgs(EmitContext& ctx) { | ||||
|  | ||||
| Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id value, | ||||
|                   Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) { | ||||
|     if (!index.IsImmediate() || index.U32() != 0) { | ||||
|         // TODO: handle layers | ||||
|         throw NotImplementedException("Image indexing"); | ||||
|     } | ||||
|     const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||||
|     const Id image_pointer{ImagePointer(ctx, index, info)}; | ||||
|     const Id texel_pointer{ | ||||
|         ctx.OpImageTexelPointer(ctx.image_u32, image_pointer, coords, ctx.Const(0U))}; | ||||
|     const Id image{Image(ctx, info)}; | ||||
|     const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, image, coords, ctx.Const(0U))}; | ||||
|     const auto [scope, semantics]{AtomicArgs(ctx)}; | ||||
|     return (ctx.*atomic_func)(ctx.U32[1], texel_pointer, scope, semantics, value); | ||||
|     return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value); | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
|   | ||||
| @@ -74,28 +74,19 @@ spv::ImageFormat GetImageFormat(ImageFormat format) { | ||||
|     throw InvalidArgument("Invalid image format {}", format); | ||||
| } | ||||
|  | ||||
| Id GetImageSampledType(EmitContext& ctx, const ImageDescriptor& desc) { | ||||
|     if (desc.is_float) { | ||||
|         return ctx.F32[1]; | ||||
|     } else { | ||||
|         return ctx.U32[1]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { | ||||
| Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) { | ||||
|     const spv::ImageFormat format{GetImageFormat(desc.format)}; | ||||
|     const Id type{GetImageSampledType(ctx, desc)}; | ||||
|     switch (desc.type) { | ||||
|     case TextureType::Color1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); | ||||
|         return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format); | ||||
|     case TextureType::ColorArray1D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); | ||||
|         return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format); | ||||
|     case TextureType::Color2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); | ||||
|         return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format); | ||||
|     case TextureType::ColorArray2D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); | ||||
|         return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format); | ||||
|     case TextureType::Color3D: | ||||
|         return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); | ||||
|         return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format); | ||||
|     case TextureType::Buffer: | ||||
|         throw NotImplementedException("Image buffer"); | ||||
|     default: | ||||
| @@ -1253,20 +1244,18 @@ void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) { | ||||
|     const spv::ImageFormat format{spv::ImageFormat::Unknown}; | ||||
|     image_buffer_type = TypeImage(F32[1], spv::Dim::Buffer, 0U, false, false, 1, format); | ||||
|  | ||||
|     const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_buffer_type)}; | ||||
|     const Id type{TypePointer(spv::StorageClass::UniformConstant, image_buffer_type)}; | ||||
|     texture_buffers.reserve(info.texture_buffer_descriptors.size()); | ||||
|     for (const TextureBufferDescriptor& desc : info.texture_buffer_descriptors) { | ||||
|         if (desc.count != 1) { | ||||
|             LOG_WARNING(Shader_SPIRV, "Array of texture buffers"); | ||||
|             throw NotImplementedException("Array of texture buffers"); | ||||
|         } | ||||
|         const Id desc_type{DescType(*this, image_buffer_type, pointer_type, desc.count)}; | ||||
|         const Id id{AddGlobalVariable(desc_type, spv::StorageClass::UniformConstant)}; | ||||
|         const Id id{AddGlobalVariable(type, spv::StorageClass::UniformConstant)}; | ||||
|         Decorate(id, spv::Decoration::Binding, binding); | ||||
|         Decorate(id, spv::Decoration::DescriptorSet, 0U); | ||||
|         Name(id, NameOf(stage, desc, "texbuf")); | ||||
|         texture_buffers.push_back({ | ||||
|             .id = id, | ||||
|             .pointer_type = pointer_type, | ||||
|             .count = desc.count, | ||||
|         }); | ||||
|         if (profile.supported_spirv >= 0x00010400) { | ||||
| @@ -1280,10 +1269,12 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { | ||||
|     image_buffers.reserve(info.image_buffer_descriptors.size()); | ||||
|     for (const ImageBufferDescriptor& desc : info.image_buffer_descriptors) { | ||||
|         if (desc.count != 1) { | ||||
|             LOG_WARNING(Shader_SPIRV, "Array of image buffers"); | ||||
|             throw NotImplementedException("Array of image buffers"); | ||||
|         } | ||||
|         const spv::ImageFormat format{GetImageFormat(desc.format)}; | ||||
|         const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; | ||||
|         const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; | ||||
|         const Id image_type{ | ||||
|             TypeImage(sampled_type, spv::Dim::Buffer, false, false, false, 2, format)}; | ||||
|         const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | ||||
|         const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | ||||
|         Decorate(id, spv::Decoration::Binding, binding); | ||||
| @@ -1292,8 +1283,8 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { | ||||
|         image_buffers.push_back({ | ||||
|             .id = id, | ||||
|             .image_type = image_type, | ||||
|             .pointer_type = pointer_type, | ||||
|             .count = desc.count, | ||||
|             .is_integer = desc.is_integer, | ||||
|         }); | ||||
|         if (profile.supported_spirv >= 0x00010400) { | ||||
|             interfaces.push_back(id); | ||||
| @@ -1336,20 +1327,20 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde | ||||
|     images.reserve(info.image_descriptors.size()); | ||||
|     for (const ImageDescriptor& desc : info.image_descriptors) { | ||||
|         if (desc.count != 1) { | ||||
|             LOG_WARNING(Shader_SPIRV, "Array of images"); | ||||
|             throw NotImplementedException("Array of images"); | ||||
|         } | ||||
|         const Id image_type{ImageType(*this, desc)}; | ||||
|         const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; | ||||
|         const Id image_type{ImageType(*this, desc, sampled_type)}; | ||||
|         const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | ||||
|         const Id desc_type{DescType(*this, image_type, pointer_type, desc.count)}; | ||||
|         const Id id{AddGlobalVariable(desc_type, spv::StorageClass::UniformConstant)}; | ||||
|         const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | ||||
|         Decorate(id, spv::Decoration::Binding, binding); | ||||
|         Decorate(id, spv::Decoration::DescriptorSet, 0U); | ||||
|         Name(id, NameOf(stage, desc, "img")); | ||||
|         images.push_back({ | ||||
|             .id = id, | ||||
|             .image_type = image_type, | ||||
|             .pointer_type = pointer_type, | ||||
|             .count = desc.count, | ||||
|             .is_integer = desc.is_integer, | ||||
|         }); | ||||
|         if (profile.supported_spirv >= 0x00010400) { | ||||
|             interfaces.push_back(id); | ||||
|   | ||||
| @@ -40,22 +40,21 @@ struct TextureDefinition { | ||||
|  | ||||
| struct TextureBufferDefinition { | ||||
|     Id id; | ||||
|     Id pointer_type; | ||||
|     u32 count; | ||||
| }; | ||||
|  | ||||
| struct ImageBufferDefinition { | ||||
|     Id id; | ||||
|     Id image_type; | ||||
|     Id pointer_type; | ||||
|     u32 count; | ||||
|     bool is_integer; | ||||
| }; | ||||
|  | ||||
| struct ImageDefinition { | ||||
|     Id id; | ||||
|     Id image_type; | ||||
|     Id pointer_type; | ||||
|     u32 count; | ||||
|     bool is_integer; | ||||
| }; | ||||
|  | ||||
| struct UniformDefinitions { | ||||
|   | ||||
| @@ -24,6 +24,8 @@ public: | ||||
|  | ||||
|     [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; | ||||
|   | ||||
| @@ -512,7 +512,7 @@ OPCODE(ImageQueryDimensions,                                U32x4,          Opaq | ||||
| OPCODE(ImageQueryLod,                                       F32x4,          Opaque,         Opaque,                                                         ) | ||||
| OPCODE(ImageGradient,                                       F32x4,          Opaque,         Opaque,         Opaque,         Opaque,         Opaque,         ) | ||||
| OPCODE(ImageRead,                                           U32x4,          Opaque,         Opaque,                                                         ) | ||||
| OPCODE(ImageWrite,                                          Void,           Opaque,         Opaque,         Opaque,                                         ) | ||||
| OPCODE(ImageWrite,                                          Void,           Opaque,         Opaque,         U32x4,                                          ) | ||||
|  | ||||
| OPCODE(IsTextureScaled,                                     U1,             U32,                                                                            ) | ||||
| OPCODE(IsImageScaled,                                       U1,             U32,                                                                            ) | ||||
|   | ||||
| @@ -19,10 +19,8 @@ struct HostTranslateInfo { | ||||
|     u32 min_ssbo_alignment{};            ///< Minimum alignment supported by the device for SSBOs | ||||
|     bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry | ||||
|                                                 ///< passthrough shaders | ||||
|     bool support_conditional_barrier{};  ///< True when the device supports barriers in conditional | ||||
|                                          ///< control flow | ||||
|     bool support_ufloat_write_as_uint{}; ///< True when the device supports writing float images | ||||
|                                          ///< as bitcasts to uint | ||||
|     bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional | ||||
|                                         ///< control flow | ||||
| }; | ||||
|  | ||||
| } // namespace Shader | ||||
|   | ||||
| @@ -815,6 +815,15 @@ bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coor | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void ConvertDerivatives(std::array<IR::Value, 3>& results, IR::IREmitter& ir) { | ||||
|     for (size_t i = 0; i < 3; i++) { | ||||
|         if (results[i].Type() == IR::Type::U32) { | ||||
|             results[i] = results[i].IsImmediate() ? ir.Imm32(Common::BitCast<f32>(results[i].U32())) | ||||
|                                                   : ir.BitCast<IR::F32>(IR::U32(results[i])); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | ||||
|     IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>(); | ||||
|     auto orig_opcode = inst.GetOpcode(); | ||||
| @@ -831,12 +840,14 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | ||||
|     if (!offset.IsImmediate()) { | ||||
|         return; | ||||
|     } | ||||
|     IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|     IR::Inst* const inst2 = coords.InstRecursive(); | ||||
|     std::array<std::array<IR::Value, 3>, 3> results_matrix; | ||||
|     for (size_t i = 0; i < 3; i++) { | ||||
|         if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) { | ||||
|             return; | ||||
|         } | ||||
|         ConvertDerivatives(results_matrix[i], ir); | ||||
|     } | ||||
|     IR::F32 lod_clamp{}; | ||||
|     if (info.has_lod_clamp != 0) { | ||||
| @@ -846,7 +857,6 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | ||||
|             lod_clamp = IR::F32{bias_lc}; | ||||
|         } | ||||
|     } | ||||
|     IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|     IR::Value new_coords = | ||||
|         ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]); | ||||
|     IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], | ||||
|   | ||||
| @@ -372,8 +372,8 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd | ||||
|     return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); | ||||
| } | ||||
|  | ||||
| bool TexturePixelFormatIsFloat(Environment& env, const ConstBufferAddr& cbuf) { | ||||
|     return ReadTexturePixelFormat(env, cbuf) == TexturePixelFormat::B10G11R11_FLOAT; | ||||
| bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) { | ||||
|     return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf)); | ||||
| } | ||||
|  | ||||
| class Descriptors { | ||||
| @@ -407,6 +407,7 @@ public: | ||||
|         })}; | ||||
|         image_buffer_descriptors[index].is_written |= desc.is_written; | ||||
|         image_buffer_descriptors[index].is_read |= desc.is_read; | ||||
|         image_buffer_descriptors[index].is_integer |= desc.is_integer; | ||||
|         return index; | ||||
|     } | ||||
|  | ||||
| @@ -432,11 +433,11 @@ public: | ||||
|             return desc.type == existing.type && desc.format == existing.format && | ||||
|                    desc.cbuf_index == existing.cbuf_index && | ||||
|                    desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count && | ||||
|                    desc.size_shift == existing.size_shift && desc.is_float == existing.is_float; | ||||
|                    desc.size_shift == existing.size_shift; | ||||
|         })}; | ||||
|         // TODO: handle is_float? | ||||
|         image_descriptors[index].is_written |= desc.is_written; | ||||
|         image_descriptors[index].is_read |= desc.is_read; | ||||
|         image_descriptors[index].is_integer |= desc.is_integer; | ||||
|         return index; | ||||
|     } | ||||
|  | ||||
| @@ -474,6 +475,20 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | ||||
|                         ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); | ||||
| } | ||||
|  | ||||
| bool IsPixelFormatSNorm(TexturePixelFormat pixel_format) { | ||||
|     switch (pixel_format) { | ||||
|     case TexturePixelFormat::A8B8G8R8_SNORM: | ||||
|     case TexturePixelFormat::R8G8_SNORM: | ||||
|     case TexturePixelFormat::R8_SNORM: | ||||
|     case TexturePixelFormat::R16G16B16A16_SNORM: | ||||
|     case TexturePixelFormat::R16G16_SNORM: | ||||
|     case TexturePixelFormat::R16_SNORM: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { | ||||
|     const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|     IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
| @@ -505,19 +520,6 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_ | ||||
|                               ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(w)), max_value)); | ||||
|     inst.ReplaceUsesWith(converted); | ||||
| } | ||||
|  | ||||
| void PatchSmallFloatImageWrite(IR::Block& block, IR::Inst& inst) { | ||||
|     IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|  | ||||
|     const IR::Value old_value{inst.Arg(2)}; | ||||
|     const IR::F32 x(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 0)))); | ||||
|     const IR::F32 y(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 1)))); | ||||
|     const IR::F32 z(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 2)))); | ||||
|     const IR::F32 w(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 3)))); | ||||
|     const IR::Value converted = ir.CompositeConstruct(x, y, z, w); | ||||
|     inst.SetArg(2, converted); | ||||
| } | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) { | ||||
| @@ -549,9 +551,6 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | ||||
|         inst->ReplaceOpcode(IndexedInstruction(*inst)); | ||||
|  | ||||
|         const auto& cbuf{texture_inst.cbuf}; | ||||
|         const bool is_float_write{!host_info.support_ufloat_write_as_uint && | ||||
|                                   inst->GetOpcode() == IR::Opcode::ImageWrite && | ||||
|                                   TexturePixelFormatIsFloat(env, cbuf)}; | ||||
|         auto flags{inst->Flags<IR::TextureInstInfo>()}; | ||||
|         bool is_multisample{false}; | ||||
|         switch (inst->GetOpcode()) { | ||||
| @@ -608,11 +607,13 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | ||||
|             } | ||||
|             const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; | ||||
|             const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; | ||||
|             const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)}; | ||||
|             if (flags.type == TextureType::Buffer) { | ||||
|                 index = descriptors.Add(ImageBufferDescriptor{ | ||||
|                     .format = flags.image_format, | ||||
|                     .is_written = is_written, | ||||
|                     .is_read = is_read, | ||||
|                     .is_integer = is_integer, | ||||
|                     .cbuf_index = cbuf.index, | ||||
|                     .cbuf_offset = cbuf.offset, | ||||
|                     .count = cbuf.count, | ||||
| @@ -624,7 +625,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | ||||
|                     .format = flags.image_format, | ||||
|                     .is_written = is_written, | ||||
|                     .is_read = is_read, | ||||
|                     .is_float = is_float_write, | ||||
|                     .is_integer = is_integer, | ||||
|                     .cbuf_index = cbuf.index, | ||||
|                     .cbuf_offset = cbuf.offset, | ||||
|                     .count = cbuf.count, | ||||
| @@ -680,14 +681,10 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | ||||
|         if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && | ||||
|             flags.type == TextureType::Buffer) { | ||||
|             const auto pixel_format = ReadTexturePixelFormat(env, cbuf); | ||||
|             if (pixel_format != TexturePixelFormat::OTHER) { | ||||
|             if (IsPixelFormatSNorm(pixel_format)) { | ||||
|                 PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (is_float_write) { | ||||
|             PatchSmallFloatImageWrite(*texture_inst.block, *inst); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -35,15 +35,109 @@ enum class TextureType : u32 { | ||||
| }; | ||||
| constexpr u32 NUM_TEXTURE_TYPES = 9; | ||||
|  | ||||
| enum class TexturePixelFormat : u32 { | ||||
| enum class TexturePixelFormat { | ||||
|     A8B8G8R8_UNORM, | ||||
|     A8B8G8R8_SNORM, | ||||
|     A8B8G8R8_SINT, | ||||
|     A8B8G8R8_UINT, | ||||
|     R5G6B5_UNORM, | ||||
|     B5G6R5_UNORM, | ||||
|     A1R5G5B5_UNORM, | ||||
|     A2B10G10R10_UNORM, | ||||
|     A2B10G10R10_UINT, | ||||
|     A2R10G10B10_UNORM, | ||||
|     A1B5G5R5_UNORM, | ||||
|     A5B5G5R1_UNORM, | ||||
|     R8_UNORM, | ||||
|     R8_SNORM, | ||||
|     R8G8_SNORM, | ||||
|     R8_SINT, | ||||
|     R8_UINT, | ||||
|     R16G16B16A16_FLOAT, | ||||
|     R16G16B16A16_UNORM, | ||||
|     R16G16B16A16_SNORM, | ||||
|     R16G16_SNORM, | ||||
|     R16_SNORM, | ||||
|     R16G16B16A16_SINT, | ||||
|     R16G16B16A16_UINT, | ||||
|     B10G11R11_FLOAT, | ||||
|     OTHER | ||||
|     R32G32B32A32_UINT, | ||||
|     BC1_RGBA_UNORM, | ||||
|     BC2_UNORM, | ||||
|     BC3_UNORM, | ||||
|     BC4_UNORM, | ||||
|     BC4_SNORM, | ||||
|     BC5_UNORM, | ||||
|     BC5_SNORM, | ||||
|     BC7_UNORM, | ||||
|     BC6H_UFLOAT, | ||||
|     BC6H_SFLOAT, | ||||
|     ASTC_2D_4X4_UNORM, | ||||
|     B8G8R8A8_UNORM, | ||||
|     R32G32B32A32_FLOAT, | ||||
|     R32G32B32A32_SINT, | ||||
|     R32G32_FLOAT, | ||||
|     R32G32_SINT, | ||||
|     R32_FLOAT, | ||||
|     R16_FLOAT, | ||||
|     R16_UNORM, | ||||
|     R16_SNORM, | ||||
|     R16_UINT, | ||||
|     R16_SINT, | ||||
|     R16G16_UNORM, | ||||
|     R16G16_FLOAT, | ||||
|     R16G16_UINT, | ||||
|     R16G16_SINT, | ||||
|     R16G16_SNORM, | ||||
|     R32G32B32_FLOAT, | ||||
|     A8B8G8R8_SRGB, | ||||
|     R8G8_UNORM, | ||||
|     R8G8_SNORM, | ||||
|     R8G8_SINT, | ||||
|     R8G8_UINT, | ||||
|     R32G32_UINT, | ||||
|     R16G16B16X16_FLOAT, | ||||
|     R32_UINT, | ||||
|     R32_SINT, | ||||
|     ASTC_2D_8X8_UNORM, | ||||
|     ASTC_2D_8X5_UNORM, | ||||
|     ASTC_2D_5X4_UNORM, | ||||
|     B8G8R8A8_SRGB, | ||||
|     BC1_RGBA_SRGB, | ||||
|     BC2_SRGB, | ||||
|     BC3_SRGB, | ||||
|     BC7_SRGB, | ||||
|     A4B4G4R4_UNORM, | ||||
|     G4R4_UNORM, | ||||
|     ASTC_2D_4X4_SRGB, | ||||
|     ASTC_2D_8X8_SRGB, | ||||
|     ASTC_2D_8X5_SRGB, | ||||
|     ASTC_2D_5X4_SRGB, | ||||
|     ASTC_2D_5X5_UNORM, | ||||
|     ASTC_2D_5X5_SRGB, | ||||
|     ASTC_2D_10X8_UNORM, | ||||
|     ASTC_2D_10X8_SRGB, | ||||
|     ASTC_2D_6X6_UNORM, | ||||
|     ASTC_2D_6X6_SRGB, | ||||
|     ASTC_2D_10X6_UNORM, | ||||
|     ASTC_2D_10X6_SRGB, | ||||
|     ASTC_2D_10X5_UNORM, | ||||
|     ASTC_2D_10X5_SRGB, | ||||
|     ASTC_2D_10X10_UNORM, | ||||
|     ASTC_2D_10X10_SRGB, | ||||
|     ASTC_2D_12X10_UNORM, | ||||
|     ASTC_2D_12X10_SRGB, | ||||
|     ASTC_2D_12X12_UNORM, | ||||
|     ASTC_2D_12X12_SRGB, | ||||
|     ASTC_2D_8X6_UNORM, | ||||
|     ASTC_2D_8X6_SRGB, | ||||
|     ASTC_2D_6X5_UNORM, | ||||
|     ASTC_2D_6X5_SRGB, | ||||
|     E5B9G9R9_FLOAT, | ||||
|     D32_FLOAT, | ||||
|     D16_UNORM, | ||||
|     X8_D24_UNORM, | ||||
|     S8_UINT, | ||||
|     D24_UNORM_S8_UINT, | ||||
|     S8_UINT_D24_UNORM, | ||||
|     D32_FLOAT_S8_UINT, | ||||
| }; | ||||
|  | ||||
| enum class ImageFormat : u32 { | ||||
| @@ -98,6 +192,7 @@ struct ImageBufferDescriptor { | ||||
|     ImageFormat format; | ||||
|     bool is_written; | ||||
|     bool is_read; | ||||
|     bool is_integer; | ||||
|     u32 cbuf_index; | ||||
|     u32 cbuf_offset; | ||||
|     u32 count; | ||||
| @@ -130,7 +225,7 @@ struct ImageDescriptor { | ||||
|     ImageFormat format; | ||||
|     bool is_written; | ||||
|     bool is_read; | ||||
|     bool is_float; | ||||
|     bool is_integer; | ||||
|     u32 cbuf_index; | ||||
|     u32 cbuf_offset; | ||||
|     u32 count; | ||||
|   | ||||
| @@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines; | ||||
| using VideoCommon::SerializePipeline; | ||||
| using Context = ShaderContext::Context; | ||||
|  | ||||
| constexpr u32 CACHE_VERSION = 9; | ||||
| constexpr u32 CACHE_VERSION = 10; | ||||
|  | ||||
| template <typename Container> | ||||
| auto MakeSpan(Container& container) { | ||||
| @@ -245,7 +245,6 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | ||||
|           .min_ssbo_alignment = static_cast<u32>(device.GetShaderStorageBufferAlignment()), | ||||
|           .support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(), | ||||
|           .support_conditional_barrier = device.SupportsConditionalBarriers(), | ||||
|           .support_ufloat_write_as_uint = true, | ||||
|       } { | ||||
|     if (use_asynchronous_shaders) { | ||||
|         workers = CreateWorkers(); | ||||
|   | ||||
| @@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment; | ||||
| using VideoCommon::GenericEnvironment; | ||||
| using VideoCommon::GraphicsEnvironment; | ||||
|  | ||||
| constexpr u32 CACHE_VERSION = 10; | ||||
| constexpr u32 CACHE_VERSION = 11; | ||||
| constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; | ||||
|  | ||||
| template <typename Container> | ||||
| @@ -388,9 +388,6 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | ||||
|         .min_ssbo_alignment = static_cast<u32>(device.GetStorageBufferAlignment()), | ||||
|         .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), | ||||
|         .support_conditional_barrier = device.SupportsConditionalBarriers(), | ||||
|         .support_ufloat_write_as_uint = driver_id != VK_DRIVER_ID_QUALCOMM_PROPRIETARY && | ||||
|                                         driver_id != VK_DRIVER_ID_MESA_TURNIP && | ||||
|                                         driver_id != VK_DRIVER_ID_ARM_PROPRIETARY, | ||||
|     }; | ||||
|  | ||||
|     if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) { | ||||
|   | ||||
| @@ -62,25 +62,9 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en | ||||
| } | ||||
|  | ||||
| static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { | ||||
|     switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, | ||||
|                                        entry.a_type, entry.srgb_conversion)) { | ||||
|     case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM: | ||||
|         return Shader::TexturePixelFormat::A8B8G8R8_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::R8_SNORM: | ||||
|         return Shader::TexturePixelFormat::R8_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::R8G8_SNORM: | ||||
|         return Shader::TexturePixelFormat::R8G8_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM: | ||||
|         return Shader::TexturePixelFormat::R16G16B16A16_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::R16G16_SNORM: | ||||
|         return Shader::TexturePixelFormat::R16G16_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::R16_SNORM: | ||||
|         return Shader::TexturePixelFormat::R16_SNORM; | ||||
|     case VideoCore::Surface::PixelFormat::B10G11R11_FLOAT: | ||||
|         return Shader::TexturePixelFormat::B10G11R11_FLOAT; | ||||
|     default: | ||||
|         return Shader::TexturePixelFormat::OTHER; | ||||
|     } | ||||
|     return static_cast<Shader::TexturePixelFormat>( | ||||
|         PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, | ||||
|                                    entry.a_type, entry.srgb_conversion)); | ||||
| } | ||||
|  | ||||
| static std::string_view StageToPrefix(Shader::Stage stage) { | ||||
| @@ -400,6 +384,11 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||||
|     return VideoCore::Surface::IsPixelFormatInteger( | ||||
|         static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||||
| } | ||||
|  | ||||
| u32 GraphicsEnvironment::ReadViewportTransformState() { | ||||
|     const auto& regs{maxwell3d->regs}; | ||||
|     viewport_transform_state = regs.viewport_scale_offset_enabled; | ||||
| @@ -450,6 +439,11 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||||
|     return VideoCore::Surface::IsPixelFormatInteger( | ||||
|         static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||||
| } | ||||
|  | ||||
| u32 ComputeEnvironment::ReadViewportTransformState() { | ||||
|     return viewport_transform_state; | ||||
| } | ||||
| @@ -553,6 +547,11 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) { | ||||
|     return it->second; | ||||
| } | ||||
|  | ||||
| bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||||
|     return VideoCore::Surface::IsPixelFormatInteger( | ||||
|         static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||||
| } | ||||
|  | ||||
| u32 FileEnvironment::ReadViewportTransformState() { | ||||
|     return viewport_transform_state; | ||||
| } | ||||
|   | ||||
| @@ -115,6 +115,8 @@ public: | ||||
|  | ||||
|     Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||||
|  | ||||
|     bool IsTexturePixelFormatInteger(u32 handle) override; | ||||
|  | ||||
|     u32 ReadViewportTransformState() override; | ||||
|  | ||||
|     std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override; | ||||
| @@ -139,6 +141,8 @@ public: | ||||
|  | ||||
|     Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||||
|  | ||||
|     bool IsTexturePixelFormatInteger(u32 handle) override; | ||||
|  | ||||
|     u32 ReadViewportTransformState() override; | ||||
|  | ||||
|     std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer( | ||||
| @@ -171,6 +175,8 @@ public: | ||||
|  | ||||
|     [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||||
|  | ||||
|     [[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override; | ||||
|  | ||||
|     [[nodiscard]] u32 ReadViewportTransformState() override; | ||||
|  | ||||
|     [[nodiscard]] u32 LocalMemorySize() const override; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user