Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VideoBackends: support multiple compute images for some backends #11923

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions Source/Core/VideoBackends/D3D/D3DGfx.cpp
Expand Up @@ -239,9 +239,10 @@ void Gfx::SetSamplerState(u32 index, const SamplerState& state)
D3D::stateman->SetSampler(index, m_state_cache.Get(state));
}

void Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
void Gfx::SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write)
{
D3D::stateman->SetComputeUAV(texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
D3D::stateman->SetComputeUAV(index,
texture ? static_cast<DXTexture*>(texture)->GetD3DUAV() : nullptr);
}

void Gfx::UnbindTexture(const AbstractTexture* texture)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/D3D/D3DGfx.h
Expand Up @@ -52,7 +52,7 @@ class Gfx final : public ::AbstractGfx
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
Expand Down
9 changes: 5 additions & 4 deletions Source/Core/VideoBackends/D3D/D3DState.cpp
Expand Up @@ -222,13 +222,14 @@ void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceVie
}
}

void StateManager::SetComputeUAV(ID3D11UnorderedAccessView* uav)
void StateManager::SetComputeUAV(u32 index, ID3D11UnorderedAccessView* uav)
{
if (m_compute_image == uav)
if (m_compute_images[index] == uav)
return;

m_compute_image = uav;
D3D::context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr);
m_compute_images[index] = uav;
D3D::context->CSSetUnorderedAccessViews(0, static_cast<u32>(m_compute_images.size()),
m_compute_images.data(), nullptr);
}

void StateManager::SetComputeShader(ID3D11ComputeShader* shader)
Expand Down
10 changes: 6 additions & 4 deletions Source/Core/VideoBackends/D3D/D3DState.h
Expand Up @@ -218,7 +218,7 @@ class StateManager

// Binds constant buffers/textures/samplers to the compute shader stage.
// We don't track these explicitly because it's not often-used.
void SetComputeUAV(ID3D11UnorderedAccessView* uav);
void SetComputeUAV(u32 index, ID3D11UnorderedAccessView* uav);
void SetComputeShader(ID3D11ComputeShader* shader);
void SyncComputeBindings();

Expand Down Expand Up @@ -277,9 +277,11 @@ class StateManager

// Compute resources are synced with the graphics resources when we need them.
ID3D11Buffer* m_compute_constants = nullptr;
std::array<ID3D11ShaderResourceView*, 8> m_compute_textures{};
std::array<ID3D11SamplerState*, 8> m_compute_samplers{};
ID3D11UnorderedAccessView* m_compute_image = nullptr;
std::array<ID3D11ShaderResourceView*, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS>
m_compute_textures{};
std::array<ID3D11SamplerState*, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS> m_compute_samplers{};
std::array<ID3D11UnorderedAccessView*, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS>
m_compute_images{};
ID3D11ComputeShader* m_compute_shader = nullptr;
};

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp
Expand Up @@ -263,7 +263,7 @@ void Gfx::SetSamplerState(u32 index, const SamplerState& state)
m_dirty_bits |= DirtyState_Samplers;
}

void Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
void Gfx::SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write)
{
const DXTexture* dxtex = static_cast<const DXTexture*>(texture);
if (m_state.compute_image_texture == dxtex)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/D3D12/D3D12Gfx.h
Expand Up @@ -60,7 +60,7 @@ class Gfx final : public ::AbstractGfx
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/Metal/MTLGfx.h
Expand Up @@ -59,7 +59,7 @@ class Gfx final : public ::AbstractGfx
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/VideoBackends/Metal/MTLGfx.mm
Expand Up @@ -386,7 +386,7 @@
g_state_tracker->SetSampler(index, state);
}

void Metal::Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
void Metal::Gfx::SetComputeImageTexture(u32, AbstractTexture* texture, bool read, bool write)
{
g_state_tracker->SetComputeTexture(static_cast<const Texture*>(texture));
}
Expand Down
25 changes: 16 additions & 9 deletions Source/Core/VideoBackends/OGL/OGLGfx.cpp
Expand Up @@ -22,6 +22,7 @@
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"

#include <algorithm>
#include <string_view>

namespace OGL
Expand Down Expand Up @@ -303,8 +304,11 @@ void OGLGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x
static_cast<const OGLPipeline*>(m_current_pipeline)->GetProgram()->shader.Bind();

// Barrier to texture can be used for reads.
if (m_bound_image_texture)
if (std::any_of(m_bound_image_textures.begin(), m_bound_image_textures.end(),
[](auto image) { return image != nullptr; }))
{
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
}

void OGLGfx::SelectLeftBuffer()
Expand Down Expand Up @@ -652,23 +656,23 @@ void OGLGfx::SetSamplerState(u32 index, const SamplerState& state)
g_sampler_cache->SetSamplerState(index, state);
}

void OGLGfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
void OGLGfx::SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write)
{
if (m_bound_image_texture == texture)
if (m_bound_image_textures[index] == texture)
return;

if (texture)
{
const GLenum access = read ? (write ? GL_READ_WRITE : GL_READ_ONLY) : GL_WRITE_ONLY;
glBindImageTexture(0, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
glBindImageTexture(index, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}

m_bound_image_texture = texture;
m_bound_image_textures[index] = texture;
}

void OGLGfx::UnbindTexture(const AbstractTexture* texture)
Expand All @@ -683,10 +687,13 @@ void OGLGfx::UnbindTexture(const AbstractTexture* texture)
m_bound_textures[i] = nullptr;
}

if (m_bound_image_texture == texture)
for (size_t i = 0; i < m_bound_image_textures.size(); i++)
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
m_bound_image_texture = nullptr;
if (m_bound_image_textures[i] != texture)
continue;

glBindImageTexture(static_cast<GLuint>(i), 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
m_bound_image_textures[i] = nullptr;
}
}

Expand Down
4 changes: 3 additions & 1 deletion Source/Core/VideoBackends/OGL/OGLGfx.h
Expand Up @@ -49,7 +49,7 @@ class OGLGfx final : public AbstractGfx
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void SetComputeImageTexture(u32 index, AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
Expand Down Expand Up @@ -103,6 +103,8 @@ class OGLGfx final : public AbstractGfx
std::unique_ptr<GLContext> m_main_gl_context;
std::unique_ptr<OGLFramebuffer> m_system_framebuffer;
std::array<const OGLTexture*, VideoCommon::MAX_PIXEL_SHADER_SAMPLERS> m_bound_textures{};
std::array<const AbstractTexture*, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS>
m_bound_image_textures{};
AbstractTexture* m_bound_image_texture = nullptr;
RasterizationState m_current_rasterization_state;
DepthState m_current_depth_state;
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp
Expand Up @@ -157,8 +157,9 @@ VkDescriptorPool CommandBufferManager::CreateDescriptorPool(u32 max_descriptor_s
const std::array<VkDescriptorPoolSize, 5> pool_sizes{{
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, max_descriptor_sets * 3},
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
max_descriptor_sets * (VideoCommon::MAX_PIXEL_SHADER_SAMPLERS + NUM_COMPUTE_SHADER_SAMPLERS +
NUM_UTILITY_PIXEL_SAMPLERS)},
max_descriptor_sets *
(VideoCommon::MAX_PIXEL_SHADER_SAMPLERS + VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS +
NUM_UTILITY_PIXEL_SAMPLERS)},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, max_descriptor_sets * 2},
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, max_descriptor_sets * 3},
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, max_descriptor_sets * 1},
Expand Down
7 changes: 3 additions & 4 deletions Source/Core/VideoBackends/Vulkan/Constants.h
Expand Up @@ -49,9 +49,9 @@ enum DESCRIPTOR_SET_LAYOUT
// - 1 texel buffer (accessible from PS) [set=1, binding=8]
// - Compute
// - 1 uniform buffer [set=0, binding=0]
// - 2 combined image samplers [set=0, binding=1-2]
// - 2 texel buffers [set=0, binding=3-4]
// - 1 storage image [set=0, binding=5]
// - 8 combined image samplers [set=0, binding=1-8]
// - 2 texel buffers [set=0, binding=9-10]
// - 8 storage image [set=0, binding=11-18]
//
// All four pipeline layout share the first two descriptor sets (uniform buffers, PS samplers).
// The third descriptor set (see bind points above) is used for storage or texel buffers.
Expand All @@ -78,7 +78,6 @@ enum UNIFORM_BUFFER_DESCRIPTOR_SET_BINDING
constexpr u32 MAX_VERTEX_ATTRIBUTES = 16;

// Number of pixel shader texture slots
constexpr u32 NUM_COMPUTE_SHADER_SAMPLERS = 2;
constexpr u32 NUM_UTILITY_PIXEL_SAMPLERS = 8;

// Number of texel buffer binding points.
Expand Down
21 changes: 17 additions & 4 deletions Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
Expand Up @@ -148,13 +148,26 @@ bool ObjectCache::CreateDescriptorSetLayouts()
{8, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
}};

static const std::array<VkDescriptorSetLayoutBinding, 6> compute_set_bindings{{
static const std::array<VkDescriptorSetLayoutBinding, 19> compute_set_bindings{{
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{3, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{4, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{6, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{7, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{8, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{9, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{10, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{11, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{12, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{13, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{14, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{15, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{16, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{17, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
{18, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT},
}};

std::array<VkDescriptorSetLayoutBinding, 3> ubo_bindings = standard_ubo_bindings;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp
Expand Up @@ -58,8 +58,8 @@ static const char COMPUTE_SHADER_HEADER[] = R"(
// All resources are packed into one descriptor set for compute.
#define UBO_BINDING(packing, x) layout(packing, set = 0, binding = (x - 1))
#define SAMPLER_BINDING(x) layout(set = 0, binding = (1 + x))
#define TEXEL_BUFFER_BINDING(x) layout(set = 0, binding = (3 + x))
#define IMAGE_BINDING(format, x) layout(format, set = 0, binding = (5 + x))
#define TEXEL_BUFFER_BINDING(x) layout(set = 0, binding = (9 + x))
#define IMAGE_BINDING(format, x) layout(format, set = 0, binding = (11 + x))

// hlsl to glsl function translation
#define API_VULKAN 1
Expand Down
46 changes: 33 additions & 13 deletions Source/Core/VideoBackends/Vulkan/StateTracker.cpp
Expand Up @@ -49,8 +49,10 @@ void StateTracker::DestroyInstance()
// Clear everything out so this doesn't happen.
for (auto& it : s_state_tracker->m_bindings.samplers)
it.imageView = VK_NULL_HANDLE;
s_state_tracker->m_bindings.image_texture.imageView = VK_NULL_HANDLE;
for (auto& it : s_state_tracker->m_bindings.image_textures)
it.imageView = VK_NULL_HANDLE;
s_state_tracker->m_dummy_texture.reset();
s_state_tracker->m_dummy_compute_texture.reset();

s_state_tracker.reset();
}
Expand All @@ -64,6 +66,14 @@ bool StateTracker::Initialize()
return false;
m_dummy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Create a dummy compute texture which can be used in place of a real binding
m_dummy_compute_texture = VKTexture::Create(
TextureConfig(1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, AbstractTextureFlag_ComputeImage),
"");
if (!m_dummy_compute_texture)
return false;
m_dummy_compute_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_IMAGE_LAYOUT_GENERAL);

// Initialize all samplers to point by default
for (size_t i = 0; i < VideoCommon::MAX_PIXEL_SHADER_SAMPLERS; i++)
Expand All @@ -73,6 +83,13 @@ bool StateTracker::Initialize()
m_bindings.samplers[i].sampler = g_object_cache->GetPointSampler();
}

for (size_t i = 0; i < VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS; i++)
{
m_bindings.image_textures[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_bindings.image_textures[i].imageView = m_dummy_compute_texture->GetView();
m_bindings.image_textures[i].sampler = g_object_cache->GetPointSampler();
}

// Default dirty flags include all descriptors
InvalidateCachedState();
return true;
Expand Down Expand Up @@ -217,13 +234,13 @@ void StateTracker::SetTexelBuffer(u32 index, VkBufferView view)
m_dirty_flags |= DIRTY_FLAG_UTILITY_BINDINGS | DIRTY_FLAG_COMPUTE_BINDINGS;
}

void StateTracker::SetImageTexture(VkImageView view)
void StateTracker::SetImageTexture(u32 index, VkImageView view)
{
if (m_bindings.image_texture.imageView == view)
if (m_bindings.image_textures[index].imageView == view)
return;

m_bindings.image_texture.imageView = view;
m_bindings.image_texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_bindings.image_textures[index].imageView = view;
m_bindings.image_textures[index].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_dirty_flags |= DIRTY_FLAG_COMPUTE_BINDINGS;
}

Expand All @@ -238,10 +255,13 @@ void StateTracker::UnbindTexture(VkImageView view)
}
}

if (m_bindings.image_texture.imageView == view)
for (VkDescriptorImageInfo& it : m_bindings.image_textures)
{
m_bindings.image_texture.imageView = m_dummy_texture->GetView();
m_bindings.image_texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (it.imageView == view)
{
it.imageView = m_dummy_compute_texture->GetView();
it.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
}
}

Expand Down Expand Up @@ -667,15 +687,15 @@ void StateTracker::UpdateComputeDescriptorSet()
m_compute_descriptor_set,
1,
0,
NUM_COMPUTE_SHADER_SAMPLERS,
VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
m_bindings.samplers.data(),
nullptr,
nullptr};
dswrites[2] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
m_compute_descriptor_set,
3,
1 + VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS,
0,
NUM_COMPUTE_TEXEL_BUFFERS,
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
Expand All @@ -685,11 +705,11 @@ void StateTracker::UpdateComputeDescriptorSet()
dswrites[3] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
m_compute_descriptor_set,
5,
1 + VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS + NUM_COMPUTE_TEXEL_BUFFERS,
0,
1,
VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
&m_bindings.image_texture,
m_bindings.image_textures.data(),
nullptr,
nullptr};

Expand Down
5 changes: 3 additions & 2 deletions Source/Core/VideoBackends/Vulkan/StateTracker.h
Expand Up @@ -43,7 +43,7 @@ class StateTracker
void SetSampler(u32 index, VkSampler sampler);
void SetSSBO(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range);
void SetTexelBuffer(u32 index, VkBufferView view);
void SetImageTexture(VkImageView view);
void SetImageTexture(u32 index, VkImageView view);

void UnbindTexture(VkImageView view);

Expand Down Expand Up @@ -146,7 +146,7 @@ class StateTracker
std::array<VkBufferView, NUM_COMPUTE_TEXEL_BUFFERS> texel_buffers;
VkDescriptorBufferInfo ssbo;
VkDescriptorBufferInfo gx_uber_vertex_ssbo;
VkDescriptorImageInfo image_texture;
std::array<VkDescriptorImageInfo, VideoCommon::MAX_COMPUTE_SHADER_SAMPLERS> image_textures;
} m_bindings = {};
std::array<VkDescriptorSet, NUM_GX_DESCRIPTOR_SETS> m_gx_descriptor_sets = {};
std::array<VkDescriptorSet, NUM_UTILITY_DESCRIPTOR_SETS> m_utility_descriptor_sets = {};
Expand All @@ -158,6 +158,7 @@ class StateTracker

// uniform buffers
std::unique_ptr<VKTexture> m_dummy_texture;
std::unique_ptr<VKTexture> m_dummy_compute_texture;

VKFramebuffer* m_framebuffer = nullptr;
VkRenderPass m_current_render_pass = VK_NULL_HANDLE;
Expand Down