summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-04-16 02:07:42 -0300
committerGravatar ReinUsesLisp2020-04-23 18:04:13 -0300
commit4fb921ff6bd6f9596c7e7cd9524932f2a44e9490 (patch)
treee48867fbae160e4f0ebf155f7dc4cf81c5683150
parentshader_ir: Turn classes into data structures (diff)
downloadyuzu-4fb921ff6bd6f9596c7e7cd9524932f2a44e9490.tar.gz
yuzu-4fb921ff6bd6f9596c7e7cd9524932f2a44e9490.tar.xz
yuzu-4fb921ff6bd6f9596c7e7cd9524932f2a44e9490.zip
shader/texture: Support multiple unknown sampler properties
This allows deducing some properties from the texture instruction before asking the runtime. By doing this we can handle type mismatches in some instructions from the renderer instead of the shader decoder. Fixes texelFetch issues with games using 2D texture instructions on a 1D sampler.
Diffstat (limited to '')
-rw-r--r--src/video_core/shader/decode/texture.cpp125
-rw-r--r--src/video_core/shader/shader_ir.h24
2 files changed, 87 insertions, 62 deletions
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 193368c29..8f0bb996e 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -139,7 +139,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
139 } 139 }
140 const Node component = Immediate(static_cast<u32>(instr.tld4s.component)); 140 const Node component = Immediate(static_cast<u32>(instr.tld4s.component));
141 141
142 const SamplerInfo info{TextureType::Texture2D, false, is_depth_compare, false}; 142 SamplerInfo info;
143 info.is_shadow = is_depth_compare;
143 const std::optional<Sampler> sampler = GetSampler(instr.sampler, info); 144 const std::optional<Sampler> sampler = GetSampler(instr.sampler, info);
144 145
145 Node4 values; 146 Node4 values;
@@ -164,20 +165,20 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
164 "AOFFI is not implemented"); 165 "AOFFI is not implemented");
165 166
166 const bool is_array = instr.txd.is_array != 0; 167 const bool is_array = instr.txd.is_array != 0;
167 u64 base_reg = instr.gpr8.Value();
168 const auto derivate_reg = instr.gpr20.Value(); 168 const auto derivate_reg = instr.gpr20.Value();
169 const auto texture_type = instr.txd.texture_type.Value(); 169 const auto texture_type = instr.txd.texture_type.Value();
170 const auto coord_count = GetCoordCount(texture_type); 170 const auto coord_count = GetCoordCount(texture_type);
171 Node index_var{}; 171 u64 base_reg = instr.gpr8.Value();
172 const std::optional<Sampler> sampler = 172 Node index_var;
173 is_bindless 173 SamplerInfo info;
174 ? GetBindlessSampler(base_reg, index_var, {{texture_type, is_array, false, false}}) 174 info.type = texture_type;
175 : GetSampler(instr.sampler, {{texture_type, is_array, false, false}}); 175 info.is_array = is_array;
176 const std::optional<Sampler> sampler = is_bindless
177 ? GetBindlessSampler(base_reg, info, index_var)
178 : GetSampler(instr.sampler, info);
176 Node4 values; 179 Node4 values;
177 if (!sampler) { 180 if (!sampler) {
178 for (u32 element = 0; element < values.size(); ++element) { 181 std::generate(values.begin(), values.end(), [this] { return Immediate(0); });
179 values[element] = Immediate(0);
180 }
181 WriteTexInstructionFloat(bb, instr, values); 182 WriteTexInstructionFloat(bb, instr, values);
182 break; 183 break;
183 } 184 }
@@ -215,12 +216,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
215 is_bindless = true; 216 is_bindless = true;
216 [[fallthrough]]; 217 [[fallthrough]];
217 case OpCode::Id::TXQ: { 218 case OpCode::Id::TXQ: {
218 // TODO: The new commits on the texture refactor, change the way samplers work. 219 Node index_var;
219 // Sadly, not all texture instructions specify the type of texture their sampler 220 const std::optional<Sampler> sampler = is_bindless
220 // uses. This must be fixed at a later instance. 221 ? GetBindlessSampler(instr.gpr8, {}, index_var)
221 Node index_var{}; 222 : GetSampler(instr.sampler, {});
222 const std::optional<Sampler> sampler =
223 is_bindless ? GetBindlessSampler(instr.gpr8, index_var) : GetSampler(instr.sampler);
224 223
225 if (!sampler) { 224 if (!sampler) {
226 u32 indexer = 0; 225 u32 indexer = 0;
@@ -268,10 +267,15 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
268 UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), 267 UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
269 "NDV is not implemented"); 268 "NDV is not implemented");
270 269
271 auto texture_type = instr.tmml.texture_type.Value(); 270 const auto texture_type = instr.tmml.texture_type.Value();
272 Node index_var{}; 271 const bool is_array = instr.tmml.array != 0;
272 SamplerInfo info;
273 info.type = texture_type;
274 info.is_array = is_array;
275 Node index_var;
273 const std::optional<Sampler> sampler = 276 const std::optional<Sampler> sampler =
274 is_bindless ? GetBindlessSampler(instr.gpr20, index_var) : GetSampler(instr.sampler); 277 is_bindless ? GetBindlessSampler(instr.gpr20, info, index_var)
278 : GetSampler(instr.sampler, info);
275 279
276 if (!sampler) { 280 if (!sampler) {
277 u32 indexer = 0; 281 u32 indexer = 0;
@@ -300,12 +304,11 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
300 coords.push_back(GetRegister(instr.gpr8.Value() + 1)); 304 coords.push_back(GetRegister(instr.gpr8.Value() + 1));
301 break; 305 break;
302 default: 306 default:
303 UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<u32>(texture_type)); 307 UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast<int>(texture_type));
304 308
305 // Fallback to interpreting as a 2D texture for now 309 // Fallback to interpreting as a 2D texture for now
306 coords.push_back(GetRegister(instr.gpr8.Value() + 0)); 310 coords.push_back(GetRegister(instr.gpr8.Value() + 0));
307 coords.push_back(GetRegister(instr.gpr8.Value() + 1)); 311 coords.push_back(GetRegister(instr.gpr8.Value() + 1));
308 texture_type = TextureType::Texture2D;
309 } 312 }
310 u32 indexer = 0; 313 u32 indexer = 0;
311 for (u32 element = 0; element < 2; ++element) { 314 for (u32 element = 0; element < 2; ++element) {
@@ -354,23 +357,30 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
354 return pc; 357 return pc;
355} 358}
356 359
357ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset, 360ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(SamplerInfo info, u32 offset,
358 std::optional<u32> buffer) { 361 std::optional<u32> buffer) {
359 if (sampler_info) { 362 if (info.IsComplete()) {
360 return *sampler_info; 363 return info;
361 } 364 }
362 const auto sampler = buffer ? registry.ObtainBindlessSampler(*buffer, offset) 365 const auto sampler = buffer ? registry.ObtainBindlessSampler(*buffer, offset)
363 : registry.ObtainBoundSampler(offset); 366 : registry.ObtainBoundSampler(offset);
364 if (!sampler) { 367 if (!sampler) {
365 LOG_WARNING(HW_GPU, "Unknown sampler info"); 368 LOG_WARNING(HW_GPU, "Unknown sampler info");
366 return SamplerInfo{TextureType::Texture2D, false, false, false}; 369 info.type = info.type.value_or(Tegra::Shader::TextureType::Texture2D);
367 } 370 info.is_array = info.is_array.value_or(false);
368 return SamplerInfo{sampler->texture_type, sampler->is_array != 0, sampler->is_shadow != 0, 371 info.is_shadow = info.is_shadow.value_or(false);
369 sampler->is_buffer != 0}; 372 info.is_buffer = info.is_buffer.value_or(false);
373 return info;
374 }
375 info.type = info.type.value_or(sampler->texture_type);
376 info.is_array = info.is_array.value_or(sampler->is_array != 0);
377 info.is_shadow = info.is_shadow.value_or(sampler->is_shadow != 0);
378 info.is_buffer = info.is_buffer.value_or(sampler->is_buffer != 0);
379 return info;
370} 380}
371 381
372std::optional<Sampler> ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, 382std::optional<Sampler> ShaderIR::GetSampler(Tegra::Shader::Sampler sampler,
373 std::optional<SamplerInfo> sampler_info) { 383 SamplerInfo sampler_info) {
374 const auto offset = static_cast<u32>(sampler.index.Value()); 384 const auto offset = static_cast<u32>(sampler.index.Value());
375 const auto info = GetSamplerInfo(sampler_info, offset); 385 const auto info = GetSamplerInfo(sampler_info, offset);
376 386
@@ -385,12 +395,12 @@ std::optional<Sampler> ShaderIR::GetSampler(const Tegra::Shader::Sampler& sample
385 395
386 // Otherwise create a new mapping for this sampler 396 // Otherwise create a new mapping for this sampler
387 const auto next_index = static_cast<u32>(used_samplers.size()); 397 const auto next_index = static_cast<u32>(used_samplers.size());
388 return used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow, 398 return used_samplers.emplace_back(next_index, offset, *info.type, *info.is_array,
389 info.is_buffer, false); 399 *info.is_shadow, *info.is_buffer, false);
390} 400}
391 401
392std::optional<Sampler> ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var, 402std::optional<Sampler> ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, SamplerInfo info,
393 std::optional<SamplerInfo> sampler_info) { 403 Node& index_var) {
394 const Node sampler_register = GetRegister(reg); 404 const Node sampler_register = GetRegister(reg);
395 const auto [base_node, tracked_sampler_info] = 405 const auto [base_node, tracked_sampler_info] =
396 TrackBindlessSampler(sampler_register, global_code, static_cast<s64>(global_code.size())); 406 TrackBindlessSampler(sampler_register, global_code, static_cast<s64>(global_code.size()));
@@ -403,7 +413,7 @@ std::optional<Sampler> ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
403 std::get_if<BindlessSamplerNode>(&*tracked_sampler_info)) { 413 std::get_if<BindlessSamplerNode>(&*tracked_sampler_info)) {
404 const u32 buffer = bindless_sampler_info->GetIndex(); 414 const u32 buffer = bindless_sampler_info->GetIndex();
405 const u32 offset = bindless_sampler_info->GetOffset(); 415 const u32 offset = bindless_sampler_info->GetOffset();
406 const auto info = GetSamplerInfo(sampler_info, offset, buffer); 416 info = GetSamplerInfo(info, offset, buffer);
407 417
408 // If this sampler has already been used, return the existing mapping. 418 // If this sampler has already been used, return the existing mapping.
409 const auto it = std::find_if(used_samplers.begin(), used_samplers.end(), 419 const auto it = std::find_if(used_samplers.begin(), used_samplers.end(),
@@ -418,13 +428,13 @@ std::optional<Sampler> ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
418 428
419 // Otherwise create a new mapping for this sampler 429 // Otherwise create a new mapping for this sampler
420 const auto next_index = static_cast<u32>(used_samplers.size()); 430 const auto next_index = static_cast<u32>(used_samplers.size());
421 return used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array, 431 return used_samplers.emplace_back(next_index, offset, buffer, *info.type, *info.is_array,
422 info.is_shadow, info.is_buffer, false); 432 *info.is_shadow, *info.is_buffer, false);
423 } 433 }
424 if (const auto array_sampler_info = std::get_if<ArraySamplerNode>(&*tracked_sampler_info)) { 434 if (const auto array_sampler_info = std::get_if<ArraySamplerNode>(&*tracked_sampler_info)) {
425 const u32 base_offset = array_sampler_info->GetBaseOffset() / 4; 435 const u32 base_offset = array_sampler_info->GetBaseOffset() / 4;
426 index_var = GetCustomVariable(array_sampler_info->GetIndexVar()); 436 index_var = GetCustomVariable(array_sampler_info->GetIndexVar());
427 const auto info = GetSamplerInfo(sampler_info, base_offset); 437 info = GetSamplerInfo(info, base_offset);
428 438
429 // If this sampler has already been used, return the existing mapping. 439 // If this sampler has already been used, return the existing mapping.
430 const auto it = std::find_if( 440 const auto it = std::find_if(
@@ -440,8 +450,8 @@ std::optional<Sampler> ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
440 uses_indexed_samplers = true; 450 uses_indexed_samplers = true;
441 // Otherwise create a new mapping for this sampler 451 // Otherwise create a new mapping for this sampler
442 const auto next_index = static_cast<u32>(used_samplers.size()); 452 const auto next_index = static_cast<u32>(used_samplers.size());
443 return used_samplers.emplace_back(next_index, base_offset, info.type, info.is_array, 453 return used_samplers.emplace_back(next_index, base_offset, *info.type, *info.is_array,
444 info.is_shadow, info.is_buffer, true); 454 *info.is_shadow, *info.is_buffer, true);
445 } 455 }
446 return std::nullopt; 456 return std::nullopt;
447} 457}
@@ -528,11 +538,16 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
528 ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow, 538 ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow,
529 "Illegal texture type"); 539 "Illegal texture type");
530 540
531 const SamplerInfo info{texture_type, is_array, is_shadow, false}; 541 SamplerInfo info;
542 info.type = texture_type;
543 info.is_array = is_array;
544 info.is_shadow = is_shadow;
545 info.is_buffer = false;
546
532 Node index_var; 547 Node index_var;
533 std::optional<Sampler> sampler = is_bindless 548 const std::optional<Sampler> sampler = is_bindless
534 ? GetBindlessSampler(*bindless_reg, index_var, info) 549 ? GetBindlessSampler(*bindless_reg, info, index_var)
535 : GetSampler(instr.sampler, info); 550 : GetSampler(instr.sampler, info);
536 if (!sampler) { 551 if (!sampler) {
537 return {Immediate(0), Immediate(0), Immediate(0), Immediate(0)}; 552 return {Immediate(0), Immediate(0), Immediate(0), Immediate(0)};
538 } 553 }
@@ -683,10 +698,14 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
683 698
684 u64 parameter_register = instr.gpr20.Value(); 699 u64 parameter_register = instr.gpr20.Value();
685 700
686 const SamplerInfo info{texture_type, is_array, depth_compare, false}; 701 SamplerInfo info;
687 Node index_var{}; 702 info.type = texture_type;
703 info.is_array = is_array;
704 info.is_shadow = depth_compare;
705
706 Node index_var;
688 const std::optional<Sampler> sampler = 707 const std::optional<Sampler> sampler =
689 is_bindless ? GetBindlessSampler(parameter_register++, index_var, info) 708 is_bindless ? GetBindlessSampler(parameter_register++, info, index_var)
690 : GetSampler(instr.sampler, info); 709 : GetSampler(instr.sampler, info);
691 Node4 values; 710 Node4 values;
692 if (!sampler) { 711 if (!sampler) {
@@ -744,12 +763,12 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
744 // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr}; 763 // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr};
745 // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr}; 764 // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr};
746 765
747 const auto& sampler = *GetSampler(instr.sampler); 766 const std::optional<Sampler> sampler = GetSampler(instr.sampler, {});
748 767
749 Node4 values; 768 Node4 values;
750 for (u32 element = 0; element < values.size(); ++element) { 769 for (u32 element = 0; element < values.size(); ++element) {
751 auto coords_copy = coords; 770 auto coords_copy = coords;
752 MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element, {}}; 771 MetaTexture meta{*sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element, {}};
753 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); 772 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
754 } 773 }
755 774
@@ -757,7 +776,11 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
757} 776}
758 777
759Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { 778Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) {
760 const Sampler& sampler = *GetSampler(instr.sampler); 779 SamplerInfo info;
780 info.type = texture_type;
781 info.is_array = is_array;
782 info.is_shadow = false;
783 const std::optional<Sampler> sampler = GetSampler(instr.sampler, info);
761 784
762 const std::size_t type_coord_count = GetCoordCount(texture_type); 785 const std::size_t type_coord_count = GetCoordCount(texture_type);
763 const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; 786 const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL;
@@ -785,7 +808,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
785 Node4 values; 808 Node4 values;
786 for (u32 element = 0; element < values.size(); ++element) { 809 for (u32 element = 0; element < values.size(); ++element) {
787 auto coords_copy = coords; 810 auto coords_copy = coords;
788 MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}}; 811 MetaTexture meta{*sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}};
789 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); 812 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
790 } 813 }
791 return values; 814 return values;
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index ae5e414cb..748d73087 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -191,10 +191,14 @@ private:
191 friend class ASTDecoder; 191 friend class ASTDecoder;
192 192
193 struct SamplerInfo { 193 struct SamplerInfo {
194 Tegra::Shader::TextureType type; 194 std::optional<Tegra::Shader::TextureType> type;
195 bool is_array; 195 std::optional<bool> is_array;
196 bool is_shadow; 196 std::optional<bool> is_shadow;
197 bool is_buffer; 197 std::optional<bool> is_buffer;
198
199 constexpr bool IsComplete() const noexcept {
200 return type && is_array && is_shadow && is_buffer;
201 }
198 }; 202 };
199 203
200 void Decode(); 204 void Decode();
@@ -327,17 +331,15 @@ private:
327 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); 331 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
328 332
329 /// Queries the missing sampler info from the execution context. 333 /// Queries the missing sampler info from the execution context.
330 SamplerInfo GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset, 334 SamplerInfo GetSamplerInfo(SamplerInfo info, u32 offset,
331 std::optional<u32> buffer = std::nullopt); 335 std::optional<u32> buffer = std::nullopt);
332 336
333 /// Accesses a texture sampler 337 /// Accesses a texture sampler.
334 std::optional<Sampler> GetSampler(const Tegra::Shader::Sampler& sampler, 338 std::optional<Sampler> GetSampler(Tegra::Shader::Sampler sampler, SamplerInfo info);
335 std::optional<SamplerInfo> sampler_info = std::nullopt);
336 339
337 /// Accesses a texture sampler for a bindless texture. 340 /// Accesses a texture sampler for a bindless texture.
338 std::optional<Sampler> GetBindlessSampler( 341 std::optional<Sampler> GetBindlessSampler(Tegra::Shader::Register reg, SamplerInfo info,
339 Tegra::Shader::Register reg, Node& index_var, 342 Node& index_var);
340 std::optional<SamplerInfo> sampler_info = std::nullopt);
341 343
342 /// Accesses an image. 344 /// Accesses an image.
343 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); 345 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);