summaryrefslogtreecommitdiff
path: root/src/video_core/shader/node.h
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-06-04 23:03:49 -0300
committerGravatar ReinUsesLisp2020-06-05 00:24:51 -0300
commit5b2b6d594c6cfa77c3fb92faee63ad524bfe7204 (patch)
tree807efa01ce6b050f9660ab50a15d355d0be05bd5 /src/video_core/shader/node.h
parentshader/track: Move bindless tracking to a separate function (diff)
downloadyuzu-5b2b6d594c6cfa77c3fb92faee63ad524bfe7204.tar.gz
yuzu-5b2b6d594c6cfa77c3fb92faee63ad524bfe7204.tar.xz
yuzu-5b2b6d594c6cfa77c3fb92faee63ad524bfe7204.zip
shader/texture: Join separate image and sampler pairs offline
Games using D3D idioms can join images and samplers when a shader executes, instead of baking them into a combined sampler image. This is also possible on Vulkan. One approach to this solution would be to use separate samplers on Vulkan and leave this unimplemented on OpenGL, but we can't do this because there's no consistent way of determining which constant buffer holds a sampler and which one an image. We could in theory find the first bit and if it's in the TIC area, it's an image; but this falls apart when an image or sampler handle use an index of zero. The used approach is to track for a LOP.OR operation (this is done at an IR level, not at an ISA level), track again the constant buffers used as source and store this pair. Then, outside of shader execution, join the sample and image pair with a bitwise or operation. This approach won't work on games that truly use separate samplers in a meaningful way. For example, pooling textures in a 2D array and determining at runtime what sampler to use. This invalidates OpenGL's disk shader cache :) - Used mostly by D3D ports to Switch
Diffstat (limited to 'src/video_core/shader/node.h')
-rw-r--r--src/video_core/shader/node.h75
1 files changed, 32 insertions, 43 deletions
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index c5e5165ff..8f230d57a 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -275,10 +275,11 @@ using Node = std::shared_ptr<NodeData>;
275using Node4 = std::array<Node, 4>; 275using Node4 = std::array<Node, 4>;
276using NodeBlock = std::vector<Node>; 276using NodeBlock = std::vector<Node>;
277 277
278class BindlessSamplerNode; 278struct ArraySamplerNode;
279class ArraySamplerNode; 279struct BindlessSamplerNode;
280struct SeparateSamplerNode;
280 281
281using TrackSamplerData = std::variant<BindlessSamplerNode, ArraySamplerNode>; 282using TrackSamplerData = std::variant<BindlessSamplerNode, SeparateSamplerNode, ArraySamplerNode>;
282using TrackSampler = std::shared_ptr<TrackSamplerData>; 283using TrackSampler = std::shared_ptr<TrackSamplerData>;
283 284
284struct Sampler { 285struct Sampler {
@@ -288,63 +289,51 @@ struct Sampler {
288 : index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow}, 289 : index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow},
289 is_buffer{is_buffer}, is_indexed{is_indexed} {} 290 is_buffer{is_buffer}, is_indexed{is_indexed} {}
290 291
292 /// Separate sampler constructor
293 constexpr explicit Sampler(u32 index, std::pair<u32, u32> offsets, std::pair<u32, u32> buffers,
294 Tegra::Shader::TextureType type, bool is_array, bool is_shadow,
295 bool is_buffer)
296 : index{index}, offset{offsets.first}, secondary_offset{offsets.second},
297 buffer{buffers.first}, secondary_buffer{buffers.second}, type{type}, is_array{is_array},
298 is_shadow{is_shadow}, is_buffer{is_buffer}, is_separated{true} {}
299
291 /// Bindless samplers constructor 300 /// Bindless samplers constructor
292 constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type, 301 constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type,
293 bool is_array, bool is_shadow, bool is_buffer, bool is_indexed) 302 bool is_array, bool is_shadow, bool is_buffer, bool is_indexed)
294 : index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array}, 303 : index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array},
295 is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true}, is_indexed{is_indexed} {} 304 is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true}, is_indexed{is_indexed} {}
296 305
297 u32 index = 0; ///< Emulated index given for the this sampler. 306 u32 index = 0; ///< Emulated index given for the this sampler.
298 u32 offset = 0; ///< Offset in the const buffer from where the sampler is being read. 307 u32 offset = 0; ///< Offset in the const buffer from where the sampler is being read.
299 u32 buffer = 0; ///< Buffer where the bindless sampler is being read (unused on bound samplers). 308 u32 secondary_offset = 0; ///< Secondary offset in the const buffer.
300 u32 size = 1; ///< Size of the sampler. 309 u32 buffer = 0; ///< Buffer where the bindless sampler is read.
310 u32 secondary_buffer = 0; ///< Secondary buffer where the bindless sampler is read.
311 u32 size = 1; ///< Size of the sampler.
301 312
302 Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) 313 Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
303 bool is_array = false; ///< Whether the texture is being sampled as an array texture or not. 314 bool is_array = false; ///< Whether the texture is being sampled as an array texture or not.
304 bool is_shadow = false; ///< Whether the texture is being sampled as a depth texture or not. 315 bool is_shadow = false; ///< Whether the texture is being sampled as a depth texture or not.
305 bool is_buffer = false; ///< Whether the texture is a texture buffer without sampler. 316 bool is_buffer = false; ///< Whether the texture is a texture buffer without sampler.
306 bool is_bindless = false; ///< Whether this sampler belongs to a bindless texture or not. 317 bool is_bindless = false; ///< Whether this sampler belongs to a bindless texture or not.
307 bool is_indexed = false; ///< Whether this sampler is an indexed array of textures. 318 bool is_indexed = false; ///< Whether this sampler is an indexed array of textures.
319 bool is_separated = false; ///< Whether the image and sampler is separated or not.
308}; 320};
309 321
310/// Represents a tracked bindless sampler into a direct const buffer 322/// Represents a tracked bindless sampler into a direct const buffer
311class ArraySamplerNode final { 323struct ArraySamplerNode {
312public:
313 explicit ArraySamplerNode(u32 index, u32 base_offset, u32 bindless_var)
314 : index{index}, base_offset{base_offset}, bindless_var{bindless_var} {}
315
316 constexpr u32 GetIndex() const {
317 return index;
318 }
319
320 constexpr u32 GetBaseOffset() const {
321 return base_offset;
322 }
323
324 constexpr u32 GetIndexVar() const {
325 return bindless_var;
326 }
327
328private:
329 u32 index; 324 u32 index;
330 u32 base_offset; 325 u32 base_offset;
331 u32 bindless_var; 326 u32 bindless_var;
332}; 327};
333 328
334/// Represents a tracked bindless sampler into a direct const buffer 329/// Represents a tracked separate sampler image pair that was folded statically
335class BindlessSamplerNode final { 330struct SeparateSamplerNode {
336public: 331 std::pair<u32, u32> indices;
337 explicit BindlessSamplerNode(u32 index, u32 offset) : index{index}, offset{offset} {} 332 std::pair<u32, u32> offsets;
338 333};
339 constexpr u32 GetIndex() const {
340 return index;
341 }
342
343 constexpr u32 GetOffset() const {
344 return offset;
345 }
346 334
347private: 335/// Represents a tracked bindless sampler into a direct const buffer
336struct BindlessSamplerNode {
348 u32 index; 337 u32 index;
349 u32 offset; 338 u32 offset;
350}; 339};