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"
# include "CRTInputBufferBuilder.hpp"
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-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
std : : unique_ptr < CRTInputBufferBuilder > _buffer_builder ;
2016-05-08 20:07:36 +00:00
std : : unique_ptr < std : : mutex > _output_mutex ;
2016-03-09 03:40:23 +00:00
// transient buffers indicating composite data not yet decoded
2016-04-21 00:44:25 +00:00
uint16_t _composite_src_output_y , _cleared_composite_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-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 ( ) ;
inline void set_colour_format ( ColourSpace colour_space , unsigned int colour_cycle_numerator , unsigned int colour_cycle_denominator )
{
2016-05-03 22:45:55 +00:00
_output_mutex - > lock ( ) ;
2016-03-09 03:40:23 +00:00
_colour_space = colour_space ;
_colour_cycle_numerator = colour_cycle_numerator ;
_colour_cycle_denominator = colour_cycle_denominator ;
2016-04-24 23:16:23 +00:00
set_colour_space_uniforms ( ) ;
2016-05-03 22:45:55 +00:00
_output_mutex - > unlock ( ) ;
2016-03-09 03:40:23 +00:00
}
inline void set_visible_area ( Rect visible_area )
{
_visible_area = visible_area ;
}
2016-04-10 19:58:43 +00:00
inline uint8_t * get_next_source_run ( )
2016-03-09 03:40:23 +00:00
{
2016-05-05 23:52:05 +00:00
if ( _source_buffer_data_pointer = = _drawn_source_buffer_data_pointer + SourceVertexBufferDataSize ) return nullptr ;
2016-04-14 02:20:13 +00:00
_output_mutex - > lock ( ) ;
2016-05-08 23:42:33 +00:00
return & _source_buffer_data . get ( ) [ _source_buffer_data_pointer % SourceVertexBufferDataSize ] ;
2016-03-09 03:40:23 +00:00
}
2016-04-10 19:58:43 +00:00
inline void complete_source_run ( )
2016-03-09 03:40:23 +00:00
{
2016-04-20 02:38:11 +00:00
_source_buffer_data_pointer + = 2 * SourceVertexSize ;
2016-04-14 02:20:13 +00:00
_output_mutex - > unlock ( ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-07 22:37:18 +00:00
inline bool composite_output_run_has_room_for_vertices ( GLsizei vertices_to_write )
{
2016-05-09 00:30:59 +00:00
return _output_buffer_data_pointer < = _drawn_output_buffer_data_pointer + OutputVertexBufferDataSize - vertices_to_write * OutputVertexSize ;
2016-05-07 22:37:18 +00:00
}
2016-03-09 03:40:23 +00:00
inline uint8_t * get_next_output_run ( )
{
2016-05-05 23:52:05 +00:00
if ( _output_buffer_data_pointer = = _drawn_output_buffer_data_pointer + OutputVertexBufferDataSize ) return nullptr ;
2016-04-10 19:58:43 +00:00
_output_mutex - > lock ( ) ;
2016-05-08 23:42:33 +00:00
return & _output_buffer_data . get ( ) [ _output_buffer_data_pointer % OutputVertexBufferDataSize ] ;
2016-03-09 03:40:23 +00:00
}
2016-04-21 01:05:32 +00:00
inline void complete_output_run ( GLsizei vertices_written )
2016-03-09 03:40:23 +00:00
{
2016-04-27 01:41:39 +00:00
_output_buffer_data_pointer + = vertices_written * OutputVertexSize ;
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 ;
}
2016-05-07 22:37:18 +00:00
inline bool composite_output_buffer_has_room_for_vertices ( GLsizei vertices_to_write )
2016-05-05 23:52:05 +00:00
{
2016-05-07 22:37:18 +00:00
return _composite_src_output_y < = _cleared_composite_output_y + IntermediateBufferHeight - vertices_to_write * OutputVertexSize ;
2016-05-05 23:52:05 +00:00
}
2016-03-09 03:40:23 +00:00
inline uint16_t get_composite_output_y ( )
{
2016-04-21 00:44:25 +00:00
return _composite_src_output_y % IntermediateBufferHeight ;
2016-03-09 03:40:23 +00:00
}
2016-05-07 22:37:18 +00:00
inline bool composite_output_buffer_is_full ( )
{
return _composite_src_output_y = = _cleared_composite_output_y + IntermediateBufferHeight ;
}
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
{
_buffer_builder - > allocate_write_area ( required_length ) ;
2016-05-05 01:27:10 +00:00
return _buffer_builder - > get_write_target ( ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-04 11:39:45 +00:00
inline bool reduce_previous_allocation_to ( size_t actual_length )
2016-03-09 03:40:23 +00:00
{
2016-05-05 01:27:10 +00:00
return _buffer_builder - > reduce_previous_allocation_to ( actual_length ) ;
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-05-04 00:56:47 +00:00
return _buffer_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-05-04 00:56:47 +00:00
return _buffer_builder - > get_last_write_y_position ( ) ;
2016-03-09 03:40:23 +00:00
}
2016-05-07 22:37:18 +00:00
inline void release_source_buffer_write_pointer ( )
{
_buffer_builder - > release_write_pointer ( ) ;
}
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-05-08 23:42:33 +00:00
std : : unique_ptr < uint8_t > _source_buffer_data ;
2016-04-21 01:05:32 +00:00
GLsizei _source_buffer_data_pointer ;
GLsizei _drawn_source_buffer_data_pointer ;
2016-04-27 01:41:39 +00:00
2016-05-08 23:42:33 +00:00
std : : unique_ptr < uint8_t > _output_buffer_data ;
2016-04-27 01:41:39 +00:00
GLsizei _output_buffer_data_pointer ;
GLsizei _drawn_output_buffer_data_pointer ;
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 */