diff options
| author | 2021-04-20 19:48:45 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:28 -0400 | |
| commit | dd860b684c7695097107c1186e96a70e754e5990 (patch) | |
| tree | 14cbd25c655798f846b75582d5364aef0508f8b0 /src/shader_recompiler/ir_opt/texture_pass.cpp | |
| parent | shader: Add constant propagation for arithmetic right shifts (diff) | |
| download | yuzu-dd860b684c7695097107c1186e96a70e754e5990.tar.gz yuzu-dd860b684c7695097107c1186e96a70e754e5990.tar.xz yuzu-dd860b684c7695097107c1186e96a70e754e5990.zip | |
shader: Implement D3D samplers
Diffstat (limited to 'src/shader_recompiler/ir_opt/texture_pass.cpp')
| -rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 80 |
1 files changed, 69 insertions, 11 deletions
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index e1d5a2ce1..5ac485522 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -19,6 +19,9 @@ namespace { | |||
| 19 | struct ConstBufferAddr { | 19 | struct ConstBufferAddr { |
| 20 | u32 index; | 20 | u32 index; |
| 21 | u32 offset; | 21 | u32 offset; |
| 22 | u32 secondary_index; | ||
| 23 | u32 secondary_offset; | ||
| 24 | bool has_secondary; | ||
| 22 | }; | 25 | }; |
| 23 | 26 | ||
| 24 | struct TextureInst { | 27 | struct TextureInst { |
| @@ -109,9 +112,38 @@ bool IsTextureInstruction(const IR::Inst& inst) { | |||
| 109 | return IndexedInstruction(inst) != IR::Opcode::Void; | 112 | return IndexedInstruction(inst) != IR::Opcode::Void; |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 115 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst); | ||
| 116 | |||
| 117 | std::optional<ConstBufferAddr> Track(const IR::Value& value) { | ||
| 118 | return IR::BreadthFirstSearch(value, TryGetConstBuffer); | ||
| 119 | } | ||
| 120 | |||
| 112 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | 121 | std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { |
| 113 | if (inst->GetOpcode() != IR::Opcode::GetCbufU32) { | 122 | switch (inst->GetOpcode()) { |
| 123 | default: | ||
| 114 | return std::nullopt; | 124 | return std::nullopt; |
| 125 | case IR::Opcode::BitwiseOr32: { | ||
| 126 | std::optional lhs{Track(inst->Arg(0))}; | ||
| 127 | std::optional rhs{Track(inst->Arg(1))}; | ||
| 128 | if (!lhs || !rhs) { | ||
| 129 | return std::nullopt; | ||
| 130 | } | ||
| 131 | if (lhs->has_secondary || rhs->has_secondary) { | ||
| 132 | return std::nullopt; | ||
| 133 | } | ||
| 134 | if (lhs->index > rhs->index || lhs->offset > rhs->offset) { | ||
| 135 | std::swap(lhs, rhs); | ||
| 136 | } | ||
| 137 | return ConstBufferAddr{ | ||
| 138 | .index = lhs->index, | ||
| 139 | .offset = lhs->offset, | ||
| 140 | .secondary_index = rhs->index, | ||
| 141 | .secondary_offset = rhs->offset, | ||
| 142 | .has_secondary = true, | ||
| 143 | }; | ||
| 144 | } | ||
| 145 | case IR::Opcode::GetCbufU32: | ||
| 146 | break; | ||
| 115 | } | 147 | } |
| 116 | const IR::Value index{inst->Arg(0)}; | 148 | const IR::Value index{inst->Arg(0)}; |
| 117 | const IR::Value offset{inst->Arg(1)}; | 149 | const IR::Value offset{inst->Arg(1)}; |
| @@ -127,13 +159,12 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { | |||
| 127 | return ConstBufferAddr{ | 159 | return ConstBufferAddr{ |
| 128 | .index{index.U32()}, | 160 | .index{index.U32()}, |
| 129 | .offset{offset.U32()}, | 161 | .offset{offset.U32()}, |
| 162 | .secondary_index = 0, | ||
| 163 | .secondary_offset = 0, | ||
| 164 | .has_secondary = false, | ||
| 130 | }; | 165 | }; |
| 131 | } | 166 | } |
| 132 | 167 | ||
| 133 | std::optional<ConstBufferAddr> Track(const IR::Value& value) { | ||
| 134 | return IR::BreadthFirstSearch(value, TryGetConstBuffer); | ||
| 135 | } | ||
| 136 | |||
| 137 | TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | 168 | TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { |
| 138 | ConstBufferAddr addr; | 169 | ConstBufferAddr addr; |
| 139 | if (IsBindless(inst)) { | 170 | if (IsBindless(inst)) { |
| @@ -146,6 +177,9 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | |||
| 146 | addr = ConstBufferAddr{ | 177 | addr = ConstBufferAddr{ |
| 147 | .index = env.TextureBoundBuffer(), | 178 | .index = env.TextureBoundBuffer(), |
| 148 | .offset = inst.Arg(0).U32(), | 179 | .offset = inst.Arg(0).U32(), |
| 180 | .secondary_index = 0, | ||
| 181 | .secondary_offset = 0, | ||
| 182 | .has_secondary = false, | ||
| 149 | }; | 183 | }; |
| 150 | } | 184 | } |
| 151 | return TextureInst{ | 185 | return TextureInst{ |
| @@ -155,6 +189,14 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | |||
| 155 | }; | 189 | }; |
| 156 | } | 190 | } |
| 157 | 191 | ||
| 192 | TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { | ||
| 193 | const u32 secondary_index{cbuf.has_secondary ? cbuf.index : cbuf.secondary_index}; | ||
| 194 | const u32 secondary_offset{cbuf.has_secondary ? cbuf.offset : cbuf.secondary_offset}; | ||
| 195 | const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)}; | ||
| 196 | const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)}; | ||
| 197 | return env.ReadTextureType(lhs_raw | rhs_raw); | ||
| 198 | } | ||
| 199 | |||
| 158 | class Descriptors { | 200 | class Descriptors { |
| 159 | public: | 201 | public: |
| 160 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, | 202 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, |
| @@ -167,8 +209,11 @@ public: | |||
| 167 | 209 | ||
| 168 | u32 Add(const TextureBufferDescriptor& desc) { | 210 | u32 Add(const TextureBufferDescriptor& desc) { |
| 169 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { | 211 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { |
| 170 | return desc.cbuf_index == existing.cbuf_index && | 212 | return desc.has_secondary == existing.has_secondary && |
| 171 | desc.cbuf_offset == existing.cbuf_offset; | 213 | desc.cbuf_index == existing.cbuf_index && |
| 214 | desc.cbuf_offset == existing.cbuf_offset && | ||
| 215 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && | ||
| 216 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset; | ||
| 172 | }); | 217 | }); |
| 173 | } | 218 | } |
| 174 | 219 | ||
| @@ -181,8 +226,12 @@ public: | |||
| 181 | 226 | ||
| 182 | u32 Add(const TextureDescriptor& desc) { | 227 | u32 Add(const TextureDescriptor& desc) { |
| 183 | return Add(texture_descriptors, desc, [&desc](const auto& existing) { | 228 | return Add(texture_descriptors, desc, [&desc](const auto& existing) { |
| 184 | return desc.cbuf_index == existing.cbuf_index && | 229 | return desc.type == existing.type && desc.is_depth == existing.is_depth && |
| 185 | desc.cbuf_offset == existing.cbuf_offset && desc.type == existing.type; | 230 | desc.has_secondary == existing.has_secondary && |
| 231 | desc.cbuf_index == existing.cbuf_index && | ||
| 232 | desc.cbuf_offset == existing.cbuf_offset && | ||
| 233 | desc.secondary_cbuf_index == existing.secondary_cbuf_index && | ||
| 234 | desc.secondary_cbuf_offset == existing.secondary_cbuf_offset; | ||
| 186 | }); | 235 | }); |
| 187 | } | 236 | } |
| 188 | 237 | ||
| @@ -247,14 +296,14 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 247 | auto flags{inst->Flags<IR::TextureInstInfo>()}; | 296 | auto flags{inst->Flags<IR::TextureInstInfo>()}; |
| 248 | switch (inst->GetOpcode()) { | 297 | switch (inst->GetOpcode()) { |
| 249 | case IR::Opcode::ImageQueryDimensions: | 298 | case IR::Opcode::ImageQueryDimensions: |
| 250 | flags.type.Assign(env.ReadTextureType(cbuf.index, cbuf.offset)); | 299 | flags.type.Assign(ReadTextureType(env, cbuf)); |
| 251 | inst->SetFlags(flags); | 300 | inst->SetFlags(flags); |
| 252 | break; | 301 | break; |
| 253 | case IR::Opcode::ImageFetch: | 302 | case IR::Opcode::ImageFetch: |
| 254 | if (flags.type != TextureType::Color1D) { | 303 | if (flags.type != TextureType::Color1D) { |
| 255 | break; | 304 | break; |
| 256 | } | 305 | } |
| 257 | if (env.ReadTextureType(cbuf.index, cbuf.offset) == TextureType::Buffer) { | 306 | if (ReadTextureType(env, cbuf) == TextureType::Buffer) { |
| 258 | // Replace with the bound texture type only when it's a texture buffer | 307 | // Replace with the bound texture type only when it's a texture buffer |
| 259 | // If the instruction is 1D and the bound type is 2D, don't change the code and let | 308 | // If the instruction is 1D and the bound type is 2D, don't change the code and let |
| 260 | // the rasterizer robustness handle it | 309 | // the rasterizer robustness handle it |
| @@ -270,6 +319,9 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 270 | switch (inst->GetOpcode()) { | 319 | switch (inst->GetOpcode()) { |
| 271 | case IR::Opcode::ImageRead: | 320 | case IR::Opcode::ImageRead: |
| 272 | case IR::Opcode::ImageWrite: { | 321 | case IR::Opcode::ImageWrite: { |
| 322 | if (cbuf.has_secondary) { | ||
| 323 | throw NotImplementedException("Unexpected separate sampler"); | ||
| 324 | } | ||
| 273 | const bool is_written{inst->GetOpcode() == IR::Opcode::ImageWrite}; | 325 | const bool is_written{inst->GetOpcode() == IR::Opcode::ImageWrite}; |
| 274 | if (flags.type == TextureType::Buffer) { | 326 | if (flags.type == TextureType::Buffer) { |
| 275 | index = descriptors.Add(ImageBufferDescriptor{ | 327 | index = descriptors.Add(ImageBufferDescriptor{ |
| @@ -294,16 +346,22 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 294 | default: | 346 | default: |
| 295 | if (flags.type == TextureType::Buffer) { | 347 | if (flags.type == TextureType::Buffer) { |
| 296 | index = descriptors.Add(TextureBufferDescriptor{ | 348 | index = descriptors.Add(TextureBufferDescriptor{ |
| 349 | .has_secondary = cbuf.has_secondary, | ||
| 297 | .cbuf_index = cbuf.index, | 350 | .cbuf_index = cbuf.index, |
| 298 | .cbuf_offset = cbuf.offset, | 351 | .cbuf_offset = cbuf.offset, |
| 352 | .secondary_cbuf_index = cbuf.secondary_index, | ||
| 353 | .secondary_cbuf_offset = cbuf.secondary_offset, | ||
| 299 | .count = 1, | 354 | .count = 1, |
| 300 | }); | 355 | }); |
| 301 | } else { | 356 | } else { |
| 302 | index = descriptors.Add(TextureDescriptor{ | 357 | index = descriptors.Add(TextureDescriptor{ |
| 303 | .type = flags.type, | 358 | .type = flags.type, |
| 304 | .is_depth = flags.is_depth != 0, | 359 | .is_depth = flags.is_depth != 0, |
| 360 | .has_secondary = cbuf.has_secondary, | ||
| 305 | .cbuf_index = cbuf.index, | 361 | .cbuf_index = cbuf.index, |
| 306 | .cbuf_offset = cbuf.offset, | 362 | .cbuf_offset = cbuf.offset, |
| 363 | .secondary_cbuf_index = cbuf.secondary_index, | ||
| 364 | .secondary_cbuf_offset = cbuf.secondary_offset, | ||
| 307 | .count = 1, | 365 | .count = 1, |
| 308 | }); | 366 | }); |
| 309 | } | 367 | } |