summaryrefslogtreecommitdiff
path: root/src/video_core/shader
diff options
context:
space:
mode:
authorGravatar Zach Hilman2019-07-05 13:39:13 -0400
committerGravatar GitHub2019-07-05 13:39:13 -0400
commit772c86a260eb446b0fe4232b0a50666511bef25c (patch)
tree013d92268c06454c93565c83eff2b79b56a00839 /src/video_core/shader
parentMerge pull request #2669 from FearlessTobi/move-cpujit-setting (diff)
parenttexture_cache: Address Feedback (diff)
downloadyuzu-772c86a260eb446b0fe4232b0a50666511bef25c.tar.gz
yuzu-772c86a260eb446b0fe4232b0a50666511bef25c.tar.xz
yuzu-772c86a260eb446b0fe4232b0a50666511bef25c.zip
Merge pull request #2601 from FernandoS27/texture_cache
Implement a new Texture Cache
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/decode.cpp1
-rw-r--r--src/video_core/shader/decode/image.cpp120
-rw-r--r--src/video_core/shader/decode/texture.cpp45
-rw-r--r--src/video_core/shader/node.h52
-rw-r--r--src/video_core/shader/shader_ir.h14
5 files changed, 231 insertions, 1 deletions
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index a0554c97e..2c9ff28f2 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -169,6 +169,7 @@ u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) {
169 {OpCode::Type::Conversion, &ShaderIR::DecodeConversion}, 169 {OpCode::Type::Conversion, &ShaderIR::DecodeConversion},
170 {OpCode::Type::Memory, &ShaderIR::DecodeMemory}, 170 {OpCode::Type::Memory, &ShaderIR::DecodeMemory},
171 {OpCode::Type::Texture, &ShaderIR::DecodeTexture}, 171 {OpCode::Type::Texture, &ShaderIR::DecodeTexture},
172 {OpCode::Type::Image, &ShaderIR::DecodeImage},
172 {OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate}, 173 {OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate},
173 {OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate}, 174 {OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate},
174 {OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate}, 175 {OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate},
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
new file mode 100644
index 000000000..24f022cc0
--- /dev/null
+++ b/src/video_core/shader/decode/image.cpp
@@ -0,0 +1,120 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <vector>
7#include <fmt/format.h>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13#include "video_core/engines/shader_bytecode.h"
14#include "video_core/shader/node_helper.h"
15#include "video_core/shader/shader_ir.h"
16
17namespace VideoCommon::Shader {
18
19using Tegra::Shader::Instruction;
20using Tegra::Shader::OpCode;
21
22namespace {
23std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
24 switch (image_type) {
25 case Tegra::Shader::ImageType::Texture1D:
26 case Tegra::Shader::ImageType::TextureBuffer:
27 return 1;
28 case Tegra::Shader::ImageType::Texture1DArray:
29 case Tegra::Shader::ImageType::Texture2D:
30 return 2;
31 case Tegra::Shader::ImageType::Texture2DArray:
32 case Tegra::Shader::ImageType::Texture3D:
33 return 3;
34 }
35 UNREACHABLE();
36 return 1;
37}
38} // Anonymous namespace
39
40u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
41 const Instruction instr = {program_code[pc]};
42 const auto opcode = OpCode::Decode(instr);
43
44 switch (opcode->get().GetId()) {
45 case OpCode::Id::SUST: {
46 UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
47 UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer);
48 UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
49 UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
50
51 std::vector<Node> values;
52 constexpr std::size_t hardcoded_size{4};
53 for (std::size_t i = 0; i < hardcoded_size; ++i) {
54 values.push_back(GetRegister(instr.gpr0.Value() + i));
55 }
56
57 std::vector<Node> coords;
58 const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
59 for (std::size_t i = 0; i < num_coords; ++i) {
60 coords.push_back(GetRegister(instr.gpr8.Value() + i));
61 }
62
63 const auto type{instr.sust.image_type};
64 const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
65 : GetBindlessImage(instr.gpr39, type)};
66 MetaImage meta{image, values};
67 const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
68 bb.push_back(store);
69 break;
70 }
71 default:
72 UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
73 }
74
75 return pc;
76}
77
78const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
79 const auto offset{static_cast<std::size_t>(image.index.Value())};
80
81 // If this image has already been used, return the existing mapping.
82 const auto itr{std::find_if(used_images.begin(), used_images.end(),
83 [=](const Image& entry) { return entry.GetOffset() == offset; })};
84 if (itr != used_images.end()) {
85 ASSERT(itr->GetType() == type);
86 return *itr;
87 }
88
89 // Otherwise create a new mapping for this image.
90 const std::size_t next_index{used_images.size()};
91 const Image entry{offset, next_index, type};
92 return *used_images.emplace(entry).first;
93}
94
95const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
96 Tegra::Shader::ImageType type) {
97 const Node image_register{GetRegister(reg)};
98 const Node base_image{
99 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
100 const auto cbuf{std::get_if<CbufNode>(&*base_image)};
101 const auto cbuf_offset_imm{std::get_if<ImmediateNode>(&*cbuf->GetOffset())};
102 const auto cbuf_offset{cbuf_offset_imm->GetValue()};
103 const auto cbuf_index{cbuf->GetIndex()};
104 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
105
106 // If this image has already been used, return the existing mapping.
107 const auto itr{std::find_if(used_images.begin(), used_images.end(),
108 [=](const Image& entry) { return entry.GetOffset() == cbuf_key; })};
109 if (itr != used_images.end()) {
110 ASSERT(itr->GetType() == type);
111 return *itr;
112 }
113
114 // Otherwise create a new mapping for this image.
115 const std::size_t next_index{used_images.size()};
116 const Image entry{cbuf_index, cbuf_offset, next_index, type};
117 return *used_images.emplace(entry).first;
118}
119
120} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index 4a356dbd4..cb480be9b 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -245,6 +245,18 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
245 } 245 }
246 break; 246 break;
247 } 247 }
248 case OpCode::Id::TLD: {
249 UNIMPLEMENTED_IF_MSG(instr.tld.aoffi, "AOFFI is not implemented");
250 UNIMPLEMENTED_IF_MSG(instr.tld.ms, "MS is not implemented");
251 UNIMPLEMENTED_IF_MSG(instr.tld.cl, "CL is not implemented");
252
253 if (instr.tld.nodep_flag) {
254 LOG_WARNING(HW_GPU, "TLD.NODEP implementation is incomplete");
255 }
256
257 WriteTexInstructionFloat(bb, instr, GetTldCode(instr));
258 break;
259 }
248 case OpCode::Id::TLDS: { 260 case OpCode::Id::TLDS: {
249 const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()}; 261 const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()};
250 const bool is_array{instr.tlds.IsArrayTexture()}; 262 const bool is_array{instr.tlds.IsArrayTexture()};
@@ -575,6 +587,39 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
575 return values; 587 return values;
576} 588}
577 589
590Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
591 const auto texture_type{instr.tld.texture_type};
592 const bool is_array{instr.tld.is_array};
593 const bool lod_enabled{instr.tld.GetTextureProcessMode() == TextureProcessMode::LL};
594 const std::size_t coord_count{GetCoordCount(texture_type)};
595
596 u64 gpr8_cursor{instr.gpr8.Value()};
597 const Node array_register{is_array ? GetRegister(gpr8_cursor++) : nullptr};
598
599 std::vector<Node> coords;
600 coords.reserve(coord_count);
601 for (std::size_t i = 0; i < coord_count; ++i) {
602 coords.push_back(GetRegister(gpr8_cursor++));
603 }
604
605 u64 gpr20_cursor{instr.gpr20.Value()};
606 // const Node bindless_register{is_bindless ? GetRegister(gpr20_cursor++) : nullptr};
607 const Node lod{lod_enabled ? GetRegister(gpr20_cursor++) : Immediate(0u)};
608 // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr};
609 // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr};
610
611 const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false);
612
613 Node4 values;
614 for (u32 element = 0; element < values.size(); ++element) {
615 auto coords_copy = coords;
616 MetaTexture meta{sampler, array_register, {}, {}, {}, lod, {}, element};
617 values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
618 }
619
620 return values;
621}
622
578Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { 623Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) {
579 const std::size_t type_coord_count = GetCoordCount(texture_type); 624 const std::size_t type_coord_count = GetCoordCount(texture_type);
580 const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; 625 const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL;
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 3cfb911bb..0ac83fcf0 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -146,6 +146,8 @@ enum class OperationCode {
146 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 146 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
147 TexelFetch, /// (MetaTexture, int[N], int) -> float4 147 TexelFetch, /// (MetaTexture, int[N], int) -> float4
148 148
149 ImageStore, /// (MetaImage, float[N] coords) -> void
150
149 Branch, /// (uint branch_target) -> void 151 Branch, /// (uint branch_target) -> void
150 PushFlowStack, /// (uint branch_target) -> void 152 PushFlowStack, /// (uint branch_target) -> void
151 PopFlowStack, /// () -> void 153 PopFlowStack, /// () -> void
@@ -263,6 +265,48 @@ private:
263 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. 265 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
264}; 266};
265 267
268class Image {
269public:
270 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
271 : offset{offset}, index{index}, type{type}, is_bindless{false} {}
272
273 explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
274 Tegra::Shader::ImageType type)
275 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
276 is_bindless{true} {}
277
278 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
279 bool is_bindless)
280 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {}
281
282 std::size_t GetOffset() const {
283 return offset;
284 }
285
286 std::size_t GetIndex() const {
287 return index;
288 }
289
290 Tegra::Shader::ImageType GetType() const {
291 return type;
292 }
293
294 bool IsBindless() const {
295 return is_bindless;
296 }
297
298 bool operator<(const Image& rhs) const {
299 return std::tie(offset, index, type, is_bindless) <
300 std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
301 }
302
303private:
304 std::size_t offset{};
305 std::size_t index{};
306 Tegra::Shader::ImageType type{};
307 bool is_bindless{};
308};
309
266struct GlobalMemoryBase { 310struct GlobalMemoryBase {
267 u32 cbuf_index{}; 311 u32 cbuf_index{};
268 u32 cbuf_offset{}; 312 u32 cbuf_offset{};
@@ -289,8 +333,14 @@ struct MetaTexture {
289 u32 element{}; 333 u32 element{};
290}; 334};
291 335
336struct MetaImage {
337 const Image& image;
338 std::vector<Node> values;
339};
340
292/// Parameters that modify an operation but are not part of any particular operand 341/// Parameters that modify an operation but are not part of any particular operand
293using Meta = std::variant<MetaArithmetic, MetaTexture, MetaStackClass, Tegra::Shader::HalfType>; 342using Meta =
343 std::variant<MetaArithmetic, MetaTexture, MetaImage, MetaStackClass, Tegra::Shader::HalfType>;
294 344
295/// Holds any kind of operation that can be done in the IR 345/// Holds any kind of operation that can be done in the IR
296class OperationNode final { 346class OperationNode final {
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index edcf2288e..e22548208 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -104,6 +104,10 @@ public:
104 return used_samplers; 104 return used_samplers;
105 } 105 }
106 106
107 const std::set<Image>& GetImages() const {
108 return used_images;
109 }
110
107 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances() 111 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances()
108 const { 112 const {
109 return used_clip_distances; 113 return used_clip_distances;
@@ -154,6 +158,7 @@ private:
154 u32 DecodeConversion(NodeBlock& bb, u32 pc); 158 u32 DecodeConversion(NodeBlock& bb, u32 pc);
155 u32 DecodeMemory(NodeBlock& bb, u32 pc); 159 u32 DecodeMemory(NodeBlock& bb, u32 pc);
156 u32 DecodeTexture(NodeBlock& bb, u32 pc); 160 u32 DecodeTexture(NodeBlock& bb, u32 pc);
161 u32 DecodeImage(NodeBlock& bb, u32 pc);
157 u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc); 162 u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc);
158 u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc); 163 u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc);
159 u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc); 164 u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc);
@@ -254,6 +259,12 @@ private:
254 Tegra::Shader::TextureType type, bool is_array, 259 Tegra::Shader::TextureType type, bool is_array,
255 bool is_shadow); 260 bool is_shadow);
256 261
262 /// Accesses an image.
263 const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
264
265 /// Access a bindless image sampler.
266 const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
267
257 /// Extracts a sequence of bits from a node 268 /// Extracts a sequence of bits from a node
258 Node BitfieldExtract(Node value, u32 offset, u32 bits); 269 Node BitfieldExtract(Node value, u32 offset, u32 bits);
259 270
@@ -277,6 +288,8 @@ private:
277 Node4 GetTld4Code(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, 288 Node4 GetTld4Code(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
278 bool depth_compare, bool is_array, bool is_aoffi); 289 bool depth_compare, bool is_array, bool is_aoffi);
279 290
291 Node4 GetTldCode(Tegra::Shader::Instruction instr);
292
280 Node4 GetTldsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, 293 Node4 GetTldsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type,
281 bool is_array); 294 bool is_array);
282 295
@@ -327,6 +340,7 @@ private:
327 std::set<Tegra::Shader::Attribute::Index> used_output_attributes; 340 std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
328 std::map<u32, ConstBuffer> used_cbufs; 341 std::map<u32, ConstBuffer> used_cbufs;
329 std::set<Sampler> used_samplers; 342 std::set<Sampler> used_samplers;
343 std::set<Image> used_images;
330 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; 344 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
331 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; 345 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
332 bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes 346 bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes