2016-02-13 20:52:23 -05:00
//
// CRTOpenGL.hpp
// Clock Signal
//
// Created by Thomas Harte on 13/02/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
# ifndef CRTOpenGL_h
# define CRTOpenGL_h
2016-03-08 22:40:23 -05:00
# include "../CRTTypes.hpp"
2016-03-19 17:07:05 -04:00
# include "CRTConstants.hpp"
2016-03-08 22:40:23 -05:00
# include "OpenGL.hpp"
# include "TextureTarget.hpp"
2017-11-08 22:36:41 -05:00
# include "Shaders/Shader.hpp"
2016-11-17 12:26:04 +08:00
# include "ArrayBuilder.hpp"
2016-11-16 22:57:17 +08:00
# include "TextureBuilder.hpp"
2016-03-08 22:40:23 -05:00
2016-04-27 22:29:54 -04:00
# include "Shaders/OutputShader.hpp"
2016-04-28 21:45:44 -04:00
# include "Shaders/IntermediateShader.hpp"
2016-04-27 22:29:54 -04:00
2016-03-08 22:40:23 -05:00
# include <mutex>
2016-11-16 10:34:54 +08:00
# include <vector>
2016-03-08 22:40:23 -05:00
2016-03-08 20:49:07 -05:00
namespace Outputs {
namespace CRT {
2016-03-08 22:40:23 -05:00
class OpenGLOutputBuilder {
private :
// colour information
2016-11-21 12:14:52 +08:00
ColourSpace colour_space_ ;
unsigned int colour_cycle_numerator_ ;
unsigned int colour_cycle_denominator_ ;
OutputDevice output_device_ ;
2017-08-10 15:17:08 -04:00
float gamma_ ;
2016-03-08 22:40:23 -05:00
// timing information to allow reasoning about input information
2016-11-21 12:14:52 +08:00
unsigned int input_frequency_ ;
unsigned int cycles_per_line_ ;
unsigned int height_of_display_ ;
unsigned int horizontal_scan_period_ ;
unsigned int vertical_scan_period_ ;
unsigned int vertical_period_divider_ ;
2016-03-08 22:40:23 -05:00
// The user-supplied visible area
2016-11-21 12:14:52 +08:00
Rect visible_area_ ;
2016-03-08 22:40:23 -05:00
// Other things the caller may have provided.
2017-02-20 10:35:33 -05:00
std : : string composite_shader_ ;
std : : string rgb_shader_ ;
2017-11-12 19:29:22 -05:00
GLint target_framebuffer_ = 0 ;
2016-03-08 22:40:23 -05:00
// Methods used by the OpenGL code
2016-05-02 21:05:58 -04:00
void prepare_output_shader ( ) ;
void prepare_rgb_input_shaders ( ) ;
void prepare_composite_input_shaders ( ) ;
2016-04-21 20:21:34 -04:00
2016-03-08 22:40:23 -05:00
void prepare_output_vertex_array ( ) ;
2016-04-17 16:17:23 -04:00
void prepare_source_vertex_array ( ) ;
2016-03-08 22:40:23 -05:00
// the run and input data buffers
2016-11-21 12:14:52 +08:00
std : : mutex output_mutex_ ;
std : : mutex draw_mutex_ ;
2016-03-08 22:40:23 -05:00
// transient buffers indicating composite data not yet decoded
2016-11-21 12:14:52 +08:00
GLsizei composite_src_output_y_ ;
2016-03-08 22:40:23 -05:00
2016-11-21 12:14:52 +08:00
std : : unique_ptr < OpenGL : : OutputShader > output_shader_program_ ;
2016-03-08 22:40:23 -05:00
2017-01-08 11:13:20 -05:00
std : : unique_ptr < OpenGL : : IntermediateShader > composite_input_shader_program_ ;
std : : unique_ptr < OpenGL : : IntermediateShader > composite_separation_filter_program_ ;
std : : unique_ptr < OpenGL : : IntermediateShader > composite_chrominance_filter_shader_program_ ;
std : : unique_ptr < OpenGL : : IntermediateShader > rgb_input_shader_program_ ;
std : : unique_ptr < OpenGL : : IntermediateShader > rgb_filter_shader_program_ ;
std : : unique_ptr < OpenGL : : TextureTarget > composite_texture_ ; // receives raw composite levels
std : : unique_ptr < OpenGL : : TextureTarget > separated_texture_ ; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B
std : : unique_ptr < OpenGL : : TextureTarget > filtered_texture_ ; // receives filtered YIQ or YUV
std : : unique_ptr < OpenGL : : TextureTarget > work_texture_ ; // used for all intermediate rendering if texture fences are supported
2016-05-03 07:46:40 -04:00
2016-11-21 12:14:52 +08:00
std : : unique_ptr < OpenGL : : TextureTarget > framebuffer_ ; // the current pixel output
2016-05-03 07:46:40 -04:00
2016-11-21 12:14:52 +08:00
GLuint output_vertex_array_ ;
GLuint source_vertex_array_ ;
2016-03-08 22:40:23 -05:00
2016-11-21 12:14:52 +08:00
unsigned int last_output_width_ , last_output_height_ ;
2016-03-08 22:40:23 -05:00
2016-04-24 18:58:31 -04:00
void set_timing_uniforms ( ) ;
2016-04-24 19:16:23 -04:00
void set_colour_space_uniforms ( ) ;
2017-08-10 15:17:08 -04:00
void set_gamma ( ) ;
2016-04-17 18:08:05 -04:00
2016-05-11 22:11:01 -04:00
void establish_OpenGL_state ( ) ;
void reset_all_OpenGL_state ( ) ;
2016-11-21 12:14:52 +08:00
GLsync fence_ ;
2017-01-24 20:48:54 -05:00
float get_composite_output_width ( ) const ;
void set_output_shader_width ( ) ;
2017-01-25 21:25:03 -05:00
bool get_is_television_output ( ) ;
2016-11-21 12:14:52 +08:00
2016-03-08 22:40:23 -05:00
public :
2016-12-06 18:48:30 -05:00
// These two are protected by output_mutex_.
2016-11-17 12:26:04 +08:00
TextureBuilder texture_builder ;
ArrayBuilder array_builder ;
2016-03-08 22:40:23 -05:00
2017-11-11 15:28:40 -05:00
OpenGLOutputBuilder ( std : : size_t bytes_per_pixel ) ;
2016-11-17 12:26:04 +08:00
~ OpenGLOutputBuilder ( ) ;
2016-03-08 22:40:23 -05:00
2017-03-26 14:34:47 -04:00
inline void set_colour_format ( ColourSpace colour_space , unsigned int colour_cycle_numerator , unsigned int colour_cycle_denominator ) {
2016-12-06 18:48:30 -05:00
std : : lock_guard < std : : mutex > output_guard ( output_mutex_ ) ;
2016-11-21 12:14:52 +08:00
colour_space_ = colour_space ;
colour_cycle_numerator_ = colour_cycle_numerator ;
colour_cycle_denominator_ = colour_cycle_denominator ;
2016-11-16 10:34:54 +08:00
set_colour_space_uniforms ( ) ;
2016-05-07 18:37:18 -04:00
}
2017-03-26 14:34:47 -04:00
inline void set_visible_area ( Rect visible_area ) {
2016-11-21 12:14:52 +08:00
visible_area_ = visible_area ;
2016-03-08 22:40:23 -05:00
}
2017-08-10 15:17:08 -04:00
inline void set_gamma ( float gamma ) {
gamma_ = gamma ;
set_gamma ( ) ;
}
2017-03-26 14:34:47 -04:00
inline std : : unique_lock < std : : mutex > get_output_lock ( ) {
2016-12-06 18:48:30 -05:00
return std : : unique_lock < std : : mutex > ( output_mutex_ ) ;
2016-03-08 22:40:23 -05:00
}
2017-03-26 14:34:47 -04:00
inline OutputDevice get_output_device ( ) {
2016-11-21 12:14:52 +08:00
return output_device_ ;
2016-03-08 22:40:23 -05:00
}
2017-03-26 14:34:47 -04:00
inline uint16_t get_composite_output_y ( ) {
2017-10-21 21:50:53 -04:00
return static_cast < uint16_t > ( composite_src_output_y_ ) ;
2016-03-08 22:40:23 -05:00
}
2017-03-26 14:34:47 -04:00
inline bool composite_output_buffer_is_full ( ) {
2016-11-21 12:14:52 +08:00
return composite_src_output_y_ = = IntermediateBufferHeight ;
2016-05-07 18:37:18 -04:00
}
2017-03-26 14:34:47 -04:00
inline void increment_composite_output_y ( ) {
2016-05-07 18:37:18 -04:00
if ( ! composite_output_buffer_is_full ( ) )
2016-11-21 12:14:52 +08:00
composite_src_output_y_ + + ;
2016-03-08 22:40:23 -05:00
}
2017-11-12 19:29:22 -05:00
void set_target_framebuffer ( GLint target_framebuffer ) ;
2016-03-08 22:40:23 -05:00
void draw_frame ( unsigned int output_width , unsigned int output_height , bool only_if_dirty ) ;
void set_openGL_context_will_change ( bool should_delete_resources ) ;
2017-02-20 10:35:33 -05:00
void set_composite_sampling_function ( const std : : string & shader ) ;
void set_rgb_sampling_function ( const std : : string & shader ) ;
2016-03-08 22:40:23 -05:00
void set_output_device ( OutputDevice output_device ) ;
2016-05-02 21:05:58 -04:00
void set_timing ( unsigned int input_frequency , unsigned int cycles_per_line , unsigned int height_of_display , unsigned int horizontal_scan_period , unsigned int vertical_scan_period , unsigned int vertical_period_divider ) ;
2016-03-08 22:40:23 -05:00
} ;
2016-03-08 20:49:07 -05:00
}
}
2016-02-13 23:50:18 -05:00
2016-02-13 20:52:23 -05:00
# endif /* CRTOpenGL_h */