metal: don't bind resources that are already bound

This commit is contained in:
Samuliak 2024-04-10 17:20:24 +02:00
parent 4771cd1602
commit 98c4ff461f
No known key found for this signature in database
4 changed files with 105 additions and 11 deletions

View File

@ -11,12 +11,12 @@ CommandRecorder::CommandRecorder(const Device& device_) : device(device_) {}
CommandRecorder::~CommandRecorder() = default;
void CommandRecorder::BeginOrContinueRenderPass(MTL::RenderPassDescriptor* render_pass) {
if (render_pass != bound_render_pass) {
if (render_pass != render_state.render_pass) {
RequireCommandBuffer();
EndEncoding();
encoder = command_buffer->renderCommandEncoder(render_pass);
encoder_type = EncoderType::Render;
bound_render_pass = render_pass;
render_state.render_pass = render_pass;
}
}
@ -43,7 +43,9 @@ void CommandRecorder::EndEncoding() {
encoder->endEncoding();
//[encoder release];
encoder = nullptr;
bound_render_pass = nullptr;
if (encoder_type == EncoderType::Render) {
render_state = {};
}
}
}

View File

@ -12,6 +12,27 @@ class Device;
enum class EncoderType { Render, Compute, Blit };
constexpr size_t MAX_BUFFERS = 31;
constexpr size_t MAX_TEXTURES = 31;
constexpr size_t MAX_SAMPLERS = 31;
struct RenderState {
MTL::RenderPassDescriptor* render_pass{nullptr};
MTL::RenderPipelineState* pipeline_state{nullptr};
MTL::Buffer* vertex_buffers[MAX_BUFFERS] = {nullptr};
MTL::Buffer* fragment_buffers[MAX_BUFFERS] = {nullptr};
MTL::Buffer* compute_buffers[MAX_BUFFERS] = {nullptr};
MTL::Texture* vertex_textures[MAX_TEXTURES] = {nullptr};
MTL::Texture* fragment_textures[MAX_TEXTURES] = {nullptr};
MTL::Texture* compute_textures[MAX_TEXTURES] = {nullptr};
MTL::SamplerState* vertex_sampler_states[MAX_SAMPLERS] = {nullptr};
MTL::SamplerState* fragment_sampler_states[MAX_SAMPLERS] = {nullptr};
MTL::SamplerState* compute_sampler_states[MAX_SAMPLERS] = {nullptr};
};
// TODO: whenever a render pass gets interrupted by either a compute or blit command and application
// then tries to perform a render command, begin the same render pass, but with all load actions set
// to "load"
@ -61,6 +82,77 @@ public:
return static_cast<MTL::BlitCommandEncoder*>(encoder);
}
// Render commands
inline void SetRenderPipelineState(MTL::RenderPipelineState* pipeline_state) {
if (pipeline_state != render_state.pipeline_state) {
GetRenderCommandEncoder()->setRenderPipelineState(pipeline_state);
render_state.pipeline_state = pipeline_state;
}
}
inline void SetVertexBuffer(MTL::Buffer* buffer, size_t index) {
if (buffer != render_state.vertex_buffers[index]) {
GetRenderCommandEncoder()->setVertexBuffer(buffer, index, 0);
render_state.vertex_buffers[index] = buffer;
}
}
inline void SetFragmentBuffer(MTL::Buffer* buffer, size_t index) {
if (buffer != render_state.fragment_buffers[index]) {
GetRenderCommandEncoder()->setFragmentBuffer(buffer, index, 0);
render_state.fragment_buffers[index] = buffer;
}
}
inline void SetComputeBuffer(MTL::Buffer* buffer, size_t index) {
if (buffer != render_state.compute_buffers[index]) {
GetComputeCommandEncoder()->setBuffer(buffer, index, 0);
render_state.compute_buffers[index] = buffer;
}
}
inline void SetVertexTexture(MTL::Texture* texture, size_t index) {
if (texture != render_state.vertex_textures[index]) {
GetRenderCommandEncoder()->setVertexTexture(texture, index);
render_state.vertex_textures[index] = texture;
}
}
inline void SetFragmentTexture(MTL::Texture* texture, size_t index) {
if (texture != render_state.fragment_textures[index]) {
GetRenderCommandEncoder()->setFragmentTexture(texture, index);
render_state.fragment_textures[index] = texture;
}
}
inline void SetComputeTexture(MTL::Texture* texture, size_t index) {
if (texture != render_state.compute_textures[index]) {
GetComputeCommandEncoder()->setTexture(texture, index);
render_state.compute_textures[index] = texture;
}
}
inline void SetVertexSamplerState(MTL::SamplerState* sampler_state, size_t index) {
if (sampler_state != render_state.vertex_sampler_states[index]) {
GetRenderCommandEncoder()->setVertexSamplerState(sampler_state, index);
render_state.vertex_sampler_states[index] = sampler_state;
}
}
inline void SetFragmentSamplerState(MTL::SamplerState* sampler_state, size_t index) {
if (sampler_state != render_state.fragment_sampler_states[index]) {
GetRenderCommandEncoder()->setFragmentSamplerState(sampler_state, index);
render_state.fragment_sampler_states[index] = sampler_state;
}
}
inline void SetComputeSamplerState(MTL::SamplerState* sampler_state, size_t index) {
if (sampler_state != render_state.compute_sampler_states[index]) {
GetComputeCommandEncoder()->setSamplerState(sampler_state, index);
render_state.compute_sampler_states[index] = sampler_state;
}
}
private:
const Device& device;
@ -71,8 +163,8 @@ private:
EncoderType encoder_type;
// Keep track of last bound render pass
MTL::RenderPassDescriptor* bound_render_pass{nullptr};
// Keep track of bound resources
RenderState render_state{};
void RequireCommandBuffer();
};

View File

@ -120,7 +120,7 @@ void GraphicsPipeline::Configure(bool is_indexed) {
}
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(pipeline_state);
command_recorder.SetRenderPipelineState(pipeline_state);
// Bind resources
@ -131,8 +131,8 @@ void GraphicsPipeline::Configure(bool is_indexed) {
ImageView& image_view{texture_cache.GetImageView(views_it->id)};
Sampler& sampler{texture_cache.GetSampler(*samplers_it)};
command_recorder.GetRenderCommandEncoder()->setFragmentTexture(image_view.GetHandle(), 0);
command_recorder.GetRenderCommandEncoder()->setFragmentSamplerState(sampler.GetHandle(), 0);
command_recorder.SetFragmentTexture(image_view.GetHandle(), 0);
command_recorder.SetFragmentSamplerState(sampler.GetHandle(), 0);
}
void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) {

View File

@ -51,9 +51,9 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
return;
}
MTL::Texture* src_texture = framebuffer->GetHandle()->colorAttachments()->object(0)->texture();
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(blit_pipeline_state);
command_recorder.GetRenderCommandEncoder()->setFragmentTexture(src_texture, 0);
command_recorder.GetRenderCommandEncoder()->setFragmentSamplerState(blit_sampler_state, 0);
command_recorder.SetRenderPipelineState(blit_pipeline_state);
command_recorder.SetFragmentTexture(src_texture, 0);
command_recorder.SetFragmentSamplerState(blit_sampler_state, 0);
// Draw a full screen triangle which will get clipped to a rectangle
command_recorder.GetRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle,