diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 78486a1d8..6b8e7f2b9 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -207,7 +207,7 @@ class CRTCBusHandler { // collect some more pixels if output is ongoing if(!is_sync && state.display_enable) { if(!pixel_data_) { - pixel_pointer_ = pixel_data_ = crt_->allocate_write_area(320); + pixel_pointer_ = pixel_data_ = crt_->allocate_write_area(320, 8); } if(pixel_pointer_) { // the CPC shuffles output lines as: diff --git a/Machines/Electron/Video.cpp b/Machines/Electron/Video.cpp index dabac72cd..faa1d410e 100644 --- a/Machines/Electron/Video.cpp +++ b/Machines/Electron/Video.cpp @@ -106,7 +106,7 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) { if(!initial_output_target_ || divider != current_output_divider_) { if(current_output_target_) crt_->output_data((unsigned int)((current_output_target_ - initial_output_target_) * current_output_divider_), current_output_divider_); current_output_divider_ = divider; - initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_); + initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 4); } #define get_pixel() \ diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 19d890ec3..ae26fbc8a 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -221,9 +221,9 @@ class CRT { @param required_length The number of samples to allocate. @returns A pointer to the allocated area if room is available; @c nullptr otherwise. */ - inline uint8_t *allocate_write_area(size_t required_length) { + inline uint8_t *allocate_write_area(size_t required_length, size_t required_alignment = 1) { std::unique_lock output_lock = openGL_output_builder_.get_output_lock(); - return openGL_output_builder_.texture_builder.allocate_write_area(required_length); + return openGL_output_builder_.texture_builder.allocate_write_area(required_length, required_alignment); } /*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state. diff --git a/Outputs/CRT/Internals/TextureBuilder.cpp b/Outputs/CRT/Internals/TextureBuilder.cpp index 945b440b1..9e5d5003f 100644 --- a/Outputs/CRT/Internals/TextureBuilder.cpp +++ b/Outputs/CRT/Internals/TextureBuilder.cpp @@ -60,7 +60,7 @@ inline uint8_t *TextureBuilder::pointer_to_location(uint16_t x, uint16_t y) { return &image_[((y * InputBufferBuilderWidth) + x) * bytes_per_pixel_]; } -uint8_t *TextureBuilder::allocate_write_area(size_t required_length) { +uint8_t *TextureBuilder::allocate_write_area(size_t required_length, size_t required_alignment) { // Keep a flag to indicate whether the buffer was full at allocate_write_area; if it was then // don't return anything now, and decline to act upon follow-up methods. is_full_ may be reset // by asynchronous calls to submit. was_full_ will not be touched by it. @@ -69,8 +69,10 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) { // If there's not enough space on this line, move to the next. If the next is where the current // submission group started, trigger is/was_full_ and return nothing. - if(write_areas_start_x_ + required_length + 2 > InputBufferBuilderWidth) { + size_t alignment_offset = (required_alignment - ((write_areas_start_x_ + 1) % required_alignment)) % required_alignment; + if(write_areas_start_x_ + required_length + 2 + alignment_offset > InputBufferBuilderWidth) { write_areas_start_x_ = 0; + alignment_offset = (required_alignment - 1) % required_alignment; write_areas_start_y_ = (write_areas_start_y_ + 1) % InputBufferBuilderHeight; if(write_areas_start_y_ == first_unsubmitted_y_) { @@ -80,7 +82,7 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) { } // Queue up the latest write area. - write_area_.x = write_areas_start_x_ + 1; + write_area_.x = write_areas_start_x_ + 1 + static_cast(alignment_offset); write_area_.y = write_areas_start_y_; write_area_.length = (uint16_t)required_length; diff --git a/Outputs/CRT/Internals/TextureBuilder.hpp b/Outputs/CRT/Internals/TextureBuilder.hpp index 476e1d04b..f0b211686 100644 --- a/Outputs/CRT/Internals/TextureBuilder.hpp +++ b/Outputs/CRT/Internals/TextureBuilder.hpp @@ -66,10 +66,11 @@ class TextureBuilder { TextureBuilder(size_t bytes_per_pixel, GLenum texture_unit); virtual ~TextureBuilder(); - /// Finds the first available space of at least @c required_length pixels in size. Calls must be paired off - /// with calls to @c reduce_previous_allocation_to. + /// Finds the first available space of at least @c required_length pixels in size which is suitably aligned + /// for writing of @c required_alignment number of pixels at a time. + /// Calls must be paired off with calls to @c reduce_previous_allocation_to. /// @returns a pointer to the allocated space if any was available; @c nullptr otherwise. - uint8_t *allocate_write_area(size_t required_length); + uint8_t *allocate_write_area(size_t required_length, size_t required_alignment = 1); /// Announces that the owner is finished with the region created by the most recent @c allocate_write_area /// and indicates that its actual final size was @c actual_length.