void QueueLengthPolicy::update_policy(int queue_length)
{
if (queue_length < 0) { // Starvation.
- if (safe_queue_length < 5) {
+ if (been_at_safe_point_since_last_starvation && safe_queue_length < 5) {
++safe_queue_length;
fprintf(stderr, "Card %u: Starvation, increasing safe limit to %u frames\n",
card_index, safe_queue_length);
}
frames_with_at_least_one = 0;
+ been_at_safe_point_since_last_starvation = false;
return;
}
if (queue_length > 0) {
- if (++frames_with_at_least_one >= 50) {
+ if (queue_length >= int(safe_queue_length)) {
+ been_at_safe_point_since_last_starvation = true;
+ }
+ if (++frames_with_at_least_one >= 50 && safe_queue_length > 0) {
--safe_queue_length;
fprintf(stderr, "Card %u: Spare frames for more than 50 frames, reducing safe limit to %u frames\n",
card_index, safe_queue_length);
movit_texel_subpixel_precision /= 2.0;
resource_pool.reset(new ResourcePool);
- theme.reset(new Theme("theme.lua", resource_pool.get(), num_cards));
+ theme.reset(new Theme(global_flags.theme_filename.c_str(), resource_pool.get(), num_cards));
for (unsigned i = 0; i < NUM_OUTPUTS; ++i) {
output_channel[i].parent = this;
}
locut.init(FILTER_HPF, 2);
+ // If --flat-audio is given, turn off everything that messes with the sound,
+ // except the final makeup gain.
+ if (global_flags.flat_audio) {
+ set_locut_enabled(false);
+ set_limiter_enabled(false);
+ set_compressor_enabled(false);
+ }
+
// hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise,
// and there's a limit to how important the peak meter is.
peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0);
new_frame.frame = RefCountedFrame(FrameAllocator::Frame());
new_frame.length = frame_length;
new_frame.interlaced = false;
- new_frame.ready_fence = nullptr;
new_frame.dropped_frames = dropped_frames;
card->new_frames.push(move(new_frame));
card->new_frames_changed.notify_all();
GLuint pbo = userdata->pbo;
check_error();
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
- check_error();
- glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
check_error();
+ size_t field_y_start = y_offset + video_format.width * field_start_line;
+ size_t field_cbcr_start = cbcr_offset + cbcr_width * field_start_line * sizeof(uint16_t);
+
+ if (global_flags.flush_pbos) {
+ glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, field_y_start, video_format.width * video_format.height);
+ check_error();
+ glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, field_cbcr_start, cbcr_width * video_format.height * sizeof(uint16_t));
+ check_error();
+ }
+
glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]);
check_error();
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, video_format.height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(cbcr_offset + cbcr_width * field_start_line * sizeof(uint16_t)));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, video_format.height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_cbcr_start));
check_error();
glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]);
check_error();
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_format.width, video_format.height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(y_offset + video_format.width * field_start_line));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_format.width, video_format.height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_y_start));
check_error();
glBindTexture(GL_TEXTURE_2D, 0);
check_error();
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
check_error();
- GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);
+ RefCountedGLsync fence(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);
+ check_error();
+ assert(fence.get() != nullptr);
+ glFlush(); // Make sure the main thread doesn't have to wait until we push out enough frames to make a new command buffer.
check_error();
- assert(fence != nullptr);
if (field == 1) {
// Don't upload the second field as fast as we can; wait until
// The new texture might still be uploaded,
// tell the GPU to wait until it's there.
if (new_frame->ready_fence) {
- glWaitSync(new_frame->ready_fence, /*flags=*/0, GL_TIMEOUT_IGNORED);
+ glWaitSync(new_frame->ready_fence.get(), /*flags=*/0, GL_TIMEOUT_IGNORED);
check_error();
- glDeleteSync(new_frame->ready_fence);
+ new_frame->ready_fence.reset();
check_error();
}
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- RefCountedGLsync fence(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);
- check_error();
-
const int64_t av_delay = TIMEBASE / 10; // Corresponds to the fixed delay in resampling_queue.h. TODO: Make less hard-coded.
- h264_encoder->end_frame(fence, pts_int + av_delay, theme_main_chain.input_frames);
+ RefCountedGLsync fence = h264_encoder->end_frame(pts_int + av_delay, theme_main_chain.input_frames);
// The live frame just shows the RGBA texture we just rendered.
// It owns rgba_tex now.