2016-02-14 01:52:23 +00: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-09 03:40:23 +00:00
# include "../CRTTypes.hpp"
2016-03-19 21:07:05 +00:00
# include "CRTConstants.hpp"
2016-03-09 03:40:23 +00:00
# include "OpenGL.hpp"
# include "TextureTarget.hpp"
# include "Shader.hpp"
2016-11-16 04:31:32 +00:00
# include "InputTextureBuilder.hpp"
2016-03-09 03:40:23 +00:00
2016-04-28 02:29:54 +00:00
# include "Shaders/OutputShader.hpp"
2016-04-29 01:45:44 +00:00
# include "Shaders/IntermediateShader.hpp"
2016-04-28 02:29:54 +00:00
2016-03-09 03:40:23 +00:00
# include <mutex>
2016-11-16 02:34:54 +00:00
# include <vector>
2016-03-09 03:40:23 +00:00
2016-03-09 01:49:07 +00:00
namespace Outputs {
namespace CRT {
2016-03-09 03:40:23 +00:00
class OpenGLOutputBuilder {
private :
// colour information
ColourSpace _colour_space ;
unsigned int _colour_cycle_numerator ;
unsigned int _colour_cycle_denominator ;
OutputDevice _output_device ;
// timing information to allow reasoning about input information
2016-05-03 01:05:58 +00:00
unsigned int _input_frequency ;
2016-03-09 03:40:23 +00:00
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 ;
// The user-supplied visible area
Rect _visible_area ;
// Other things the caller may have provided.
char * _composite_shader ;
char * _rgb_shader ;
// Methods used by the OpenGL code
2016-05-03 01:05:58 +00:00
void prepare_output_shader ( ) ;
void prepare_rgb_input_shaders ( ) ;
void prepare_composite_input_shaders ( ) ;
2016-04-22 00:21:34 +00:00
2016-03-09 03:40:23 +00:00
void prepare_output_vertex_array ( ) ;
2016-04-17 20:17:23 +00:00
void prepare_source_vertex_array ( ) ;
2016-03-09 03:40:23 +00:00
// the run and input data buffers
2016-11-16 04:31:32 +00:00
std : : unique_ptr < InputTextureBuilder > _texture_builder ;
2016-05-08 20:07:36 +00:00
std : : unique_ptr < std : : mutex > _output_mutex ;
2016-06-03 02:29:09 +00:00
std : : unique_ptr < std : : mutex > _draw_mutex ;
2016-03-09 03:40:23 +00:00
// transient buffers indicating composite data not yet decoded
2016-11-16 03:10:34 +00:00
GLsizei _composite_src_output_y ;
2016-03-09 03:40:23 +00:00
2016-05-03 01:05:58 +00:00
std : : unique_ptr < OpenGL : : OutputShader > output_shader_program ;
2016-05-03 11:46:40 +00:00
std : : unique_ptr < OpenGL : : IntermediateShader > composite_input_shader_program , composite_separation_filter_program , composite_y_filter_shader_program , composite_chrominance_filter_shader_program ;
2016-05-03 01:05:58 +00:00
std : : unique_ptr < OpenGL : : IntermediateShader > rgb_input_shader_program , rgb_filter_shader_program ;
2016-03-09 03:40:23 +00:00
2016-05-03 11:46:40 +00:00
std : : unique_ptr < OpenGL : : TextureTarget > compositeTexture ; // receives raw composite levels
std : : unique_ptr < OpenGL : : TextureTarget > separatedTexture ; // receives unfiltered Y in the R channel plus unfiltered but demodulated chrominance in G and B
std : : unique_ptr < OpenGL : : TextureTarget > filteredYTexture ; // receives filtered Y in the R channel plus unfiltered chrominance in G and B
std : : unique_ptr < OpenGL : : TextureTarget > filteredTexture ; // receives filtered YIQ or YUV
std : : unique_ptr < OpenGL : : TextureTarget > framebuffer ; // the current pixel output
2016-05-06 01:21:27 +00:00
GLuint output_array_buffer , output_vertex_array ;
2016-04-17 21:17:59 +00:00
GLuint source_array_buffer , source_vertex_array ;
2016-03-09 03:40:23 +00:00
2016-04-29 02:04:47 +00:00
unsigned int _last_output_width , _last_output_height ;
2016-03-09 03:40:23 +00:00
GLuint textureName , shadowMaskTextureName ;
GLuint defaultFramebuffer ;
2016-04-24 22:58:31 +00:00
void set_timing_uniforms ( ) ;
2016-04-24 23:16:23 +00:00
void set_colour_space_uniforms ( ) ;
2016-04-17 22:08:05 +00:00
2016-05-12 02:11:01 +00:00
void establish_OpenGL_state ( ) ;
void reset_all_OpenGL_state ( ) ;
2016-03-09 03:40:23 +00:00
public :
2016-03-19 21:37:55 +00:00
OpenGLOutputBuilder ( unsigned int buffer_depth ) ;
2016-03-09 03:40:23 +00:00
~ OpenGLOutputBuilder ( ) ;
2016-11-16 02:34:54 +00:00
inline uint8_t * get_next_source_run ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:49:18 +00:00
_line_buffer . data . resize ( _line_buffer . pointer + SourceVertexSize ) ;
return & _line_buffer . data [ _line_buffer . pointer ] ;
2016-03-09 03:40:23 +00:00
}
2016-11-16 02:34:54 +00:00
inline void complete_source_run ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:49:18 +00:00
_line_buffer . pointer + = SourceVertexSize ;
2016-03-09 03:40:23 +00:00
}
2016-11-16 03:34:05 +00:00
inline uint8_t * get_buffered_source_runs ( size_t & size )
{
size = _line_buffer . pointer ;
return _line_buffer . data . data ( ) ;
}
2016-11-16 02:34:54 +00:00
inline uint8_t * get_next_output_run ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:34:54 +00:00
if ( _output_buffer . pointer = = OutputVertexBufferDataSize ) return nullptr ;
return & _output_buffer . data [ _output_buffer . pointer ] ;
2016-03-09 03:40:23 +00:00
}
2016-11-16 02:34:54 +00:00
inline void complete_output_run ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:49:18 +00:00
size_t line_buffer_size = _line_buffer . data . size ( ) ;
if ( _source_buffer . pointer + line_buffer_size < SourceVertexBufferDataSize )
{
_output_buffer . pointer + = OutputVertexSize ;
memcpy ( & _source_buffer . data [ _source_buffer . pointer ] , _line_buffer . data . data ( ) , _line_buffer . data . size ( ) ) ;
_source_buffer . pointer + = _line_buffer . data . size ( ) ;
_line_buffer . data . resize ( 0 ) ;
_line_buffer . pointer = 0 ;
}
2016-03-09 03:40:23 +00:00
}
2016-11-16 02:34:54 +00:00
inline void set_colour_format ( ColourSpace colour_space , unsigned int colour_cycle_numerator , unsigned int colour_cycle_denominator )
2016-05-07 22:37:18 +00:00
{
2016-11-16 02:34:54 +00:00
_output_mutex - > lock ( ) ;
_colour_space = colour_space ;
_colour_cycle_numerator = colour_cycle_numerator ;
_colour_cycle_denominator = colour_cycle_denominator ;
set_colour_space_uniforms ( ) ;
_output_mutex - > unlock ( ) ;
2016-05-07 22:37:18 +00:00
}
2016-11-16 02:34:54 +00:00
inline void set_visible_area ( Rect visible_area )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:34:54 +00:00
_visible_area = visible_area ;
2016-03-09 03:40:23 +00:00
}
2016-11-16 02:34:54 +00:00
inline bool composite_output_run_has_room_for_vertex ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 02:34:54 +00:00
return _output_buffer . pointer < OutputVertexBufferDataSize ;
2016-05-09 10:58:26 +00:00
}
inline void lock_output ( )
{
_output_mutex - > lock ( ) ;
}
inline void unlock_output ( )
{
2016-04-10 19:58:43 +00:00
_output_mutex - > unlock ( ) ;
2016-03-09 03:40:23 +00:00
}
inline OutputDevice get_output_device ( )
{
return _output_device ;
}
inline uint16_t get_composite_output_y ( )
{
2016-11-16 03:34:05 +00:00
return ( uint16_t ) _composite_src_output_y ;
2016-03-09 03:40:23 +00:00
}
2016-05-07 22:37:18 +00:00
inline bool composite_output_buffer_is_full ( )
{
2016-11-16 03:10:34 +00:00
return _composite_src_output_y = = IntermediateBufferHeight ;
2016-05-07 22:37:18 +00:00
}
2016-03-09 03:40:23 +00:00
inline void increment_composite_output_y ( )
{
2016-05-07 22:37:18 +00:00
if ( ! composite_output_buffer_is_full ( ) )
_composite_src_output_y + + ;
2016-03-09 03:40:23 +00:00
}
2016-03-19 21:37:55 +00:00
inline uint8_t * allocate_write_area ( size_t required_length )
2016-03-09 03:40:23 +00:00
{
2016-11-16 05:15:50 +00:00
return _texture_builder - > allocate_write_area ( required_length ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-09 11:02:12 +00:00
inline void reduce_previous_allocation_to ( size_t actual_length )
2016-03-09 03:40:23 +00:00
{
2016-11-16 04:31:32 +00:00
_texture_builder - > reduce_previous_allocation_to ( actual_length ) ;
2016-05-09 11:02:12 +00:00
}
inline bool input_buffer_is_full ( )
{
2016-11-16 04:31:32 +00:00
return _texture_builder - > is_full ( ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-04 00:56:47 +00:00
inline uint16_t get_last_write_x_posititon ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 04:31:32 +00:00
return _texture_builder - > get_last_write_x_position ( ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-04 00:56:47 +00:00
inline uint16_t get_last_write_y_posititon ( )
2016-03-09 03:40:23 +00:00
{
2016-11-16 04:31:32 +00:00
return _texture_builder - > get_last_write_y_position ( ) ;
2016-03-09 03:40:23 +00: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 ) ;
void set_composite_sampling_function ( const char * shader ) ;
void set_rgb_sampling_function ( const char * shader ) ;
void set_output_device ( OutputDevice output_device ) ;
2016-05-03 01:05:58 +00: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-17 02:29:22 +00:00
2016-11-16 02:34:54 +00:00
struct Buffer {
std : : vector < uint8_t > data ;
size_t pointer ;
Buffer ( ) : pointer ( 0 ) { }
} _line_buffer , _source_buffer , _output_buffer ;
2016-05-08 23:42:33 +00:00
GLsync _fence ;
2016-03-09 03:40:23 +00:00
} ;
2016-03-09 01:49:07 +00:00
}
}
2016-02-14 04:50:18 +00:00
2016-02-14 01:52:23 +00:00
# endif /* CRTOpenGL_h */