| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -590,8 +590,12 @@ std::unique_ptr<GPUPipeline> OpenGLDevice::CreatePipeline(const GPUPipeline::Gra
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                         config.blend, primitives[static_cast<u8>(config.primitive)]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE static void ApplyRasterizationState(const GPUPipeline::RasterizationState& rs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyRasterizationState(GPUPipeline::RasterizationState rs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_rasterization_state == rs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Only one thing, no need to check.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (rs.cull_mode == GPUPipeline::CullMode::None)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glDisable(GL_CULL_FACE);
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -601,9 +605,11 @@ ALWAYS_INLINE static void ApplyRasterizationState(const GPUPipeline::Rasterizati
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glEnable(GL_CULL_FACE);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glCullFace((rs.cull_mode == GPUPipeline::CullMode::Front) ? GL_FRONT : GL_BACK);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  m_last_rasterization_state = rs;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE static void ApplyDepthState(const GPUPipeline::DepthState& ds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyDepthState(GPUPipeline::DepthState ds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  static constexpr std::array<GLenum, static_cast<u32>(GPUPipeline::DepthFunc::MaxCount)> func_mapping = {{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    GL_NEVER,   // Never
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -615,13 +621,19 @@ ALWAYS_INLINE static void ApplyDepthState(const GPUPipeline::DepthState& ds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    GL_EQUAL,   // Equal
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_depth_state == ds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  (ds.depth_test != GPUPipeline::DepthFunc::Always || ds.depth_write) ? glEnable(GL_DEPTH_TEST) :
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                                        glDisable(GL_DEPTH_TEST);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  glDepthFunc(func_mapping[static_cast<u8>(ds.depth_test.GetValue())]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  glDepthMask(ds.depth_write);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_depth_state.depth_write != ds.depth_write)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glDepthMask(ds.depth_write);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  m_last_depth_state = ds;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE static void ApplyBlendState(const GPUPipeline::BlendState& bs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ALWAYS_INLINE_RELEASE void OpenGLDevice::ApplyBlendState(GPUPipeline::BlendState bs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  static constexpr std::array<GLenum, static_cast<u32>(GPUPipeline::BlendFunc::MaxCount)> blend_mapping = {{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    GL_ZERO,                     // Zero
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -649,24 +661,44 @@ ALWAYS_INLINE static void ApplyBlendState(const GPUPipeline::BlendState& bs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // TODO: driver bugs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // TODO: rdoc and look for redundant calls
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  bs.enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (bs == m_last_blend_state)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (bs.enable != m_last_blend_state.enable)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bs.enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (bs.enable)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glBlendFuncSeparate(blend_mapping[static_cast<u8>(bs.src_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glBlendEquationSeparate(op_mapping[static_cast<u8>(bs.blend_op.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (bs.blend_factors != m_last_blend_state.blend_factors)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      glBlendFuncSeparate(blend_mapping[static_cast<u8>(bs.src_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (bs.blend_ops != m_last_blend_state.blend_ops)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      glBlendEquationSeparate(op_mapping[static_cast<u8>(bs.blend_op.GetValue())],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                              op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO: cache this to avoid calls?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glBlendColor(bs.GetConstantRed(), bs.GetConstantGreen(), bs.GetConstantBlue(), bs.GetConstantAlpha());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (bs.constant != m_last_blend_state.constant)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      glBlendColor(bs.GetConstantRed(), bs.GetConstantGreen(), bs.GetConstantBlue(), bs.GetConstantAlpha());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Keep old values for blend options to potentially avoid calls when re-enabling.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bs.blend_factors.SetValue(m_last_blend_state.blend_factors);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bs.blend_ops.SetValue(m_last_blend_state.blend_ops);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bs.constant.SetValue(m_last_blend_state.constant);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  glColorMask(bs.write_r, bs.write_g, bs.write_b, bs.write_a);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (bs.write_mask != m_last_blend_state.write_mask)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    glColorMask(bs.write_r, bs.write_g, bs.write_b, bs.write_a);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  m_last_blend_state = bs;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void OpenGLDevice::SetPipeline(GPUPipeline* pipeline)
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -677,21 +709,10 @@ void OpenGLDevice::SetPipeline(GPUPipeline* pipeline)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  OpenGLPipeline* const P = static_cast<OpenGLPipeline*>(pipeline);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  m_current_pipeline = P;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_rasterization_state != P->GetRasterizationState())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    m_last_rasterization_state = P->GetRasterizationState();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ApplyRasterizationState(m_last_rasterization_state);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_depth_state != P->GetDepthState())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    m_last_depth_state = P->GetDepthState();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ApplyDepthState(m_last_depth_state);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_blend_state != P->GetBlendState())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    m_last_blend_state = P->GetBlendState();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ApplyBlendState(m_last_blend_state);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ApplyRasterizationState(P->GetRasterizationState());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ApplyDepthState(P->GetDepthState());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ApplyBlendState(P->GetBlendState());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (m_last_vao != P->GetVAO())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    m_last_vao = P->GetVAO();
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |