]> git.sesse.net Git - nageru/blobdiff - mixer.cpp
Make sure our uploaded RGBA textures can deal with being asked for linear gamma.
[nageru] / mixer.cpp
index 0c00d148144eae9583d65b8e06d32a5fe14f8c71..385ca237d94364e48d834271fe2eabf82072c2c1 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -81,10 +81,18 @@ void insert_new_frame(RefCountedFrame frame, unsigned field_num, bool interlaced
 void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned field, unsigned width, unsigned height, unsigned v210_width)
 {
        bool first;
-       if (global_flags.ten_bit_input) {
+       switch (userdata->pixel_format) {
+       case bmusb::PixelFormat_10BitYCbCr:
                first = userdata->tex_v210[field] == 0 || userdata->tex_444[field] == 0;
-       } else {
+               break;
+       case bmusb::PixelFormat_8BitYCbCr:
                first = userdata->tex_y[field] == 0 || userdata->tex_cbcr[field] == 0;
+               break;
+       case bmusb::PixelFormat_8BitRGBA:
+               first = userdata->tex_rgba[field] == 0;
+               break;
+       default:
+               assert(false);
        }
 
        if (first ||
@@ -93,12 +101,14 @@ void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned f
                // We changed resolution since last use of this texture, so we need to create
                // a new object. Note that this each card has its own PBOFrameAllocator,
                // we don't need to worry about these flip-flopping between resolutions.
-               if (global_flags.ten_bit_input) {
+               switch (userdata->pixel_format) {
+               case bmusb::PixelFormat_10BitYCbCr:
                        glBindTexture(GL_TEXTURE_2D, userdata->tex_444[field]);
                        check_error();
                        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, nullptr);
                        check_error();
-               } else {
+                       break;
+               case bmusb::PixelFormat_8BitYCbCr: {
                        size_t cbcr_width = width / 2;
 
                        glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]);
@@ -109,6 +119,18 @@ void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned f
                        check_error();
                        glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
                        check_error();
+                       break;
+               }
+               case bmusb::PixelFormat_8BitRGBA:
+                       glBindTexture(GL_TEXTURE_2D, userdata->tex_rgba[field]);
+                       check_error();
+                       if (global_flags.can_disable_srgb_decoder) {  // See the comments in tweaked_inputs.h.
+                               glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+                       } else {
+                               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+                       }
+                       check_error();
+                       break;
                }
                userdata->last_width[field] = width;
                userdata->last_height[field] = height;
@@ -188,6 +210,9 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
        CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF));
        check_error();
 
+       // This nearly always should be true.
+       global_flags.can_disable_srgb_decoder = epoxy_has_gl_extension("GL_EXT_texture_sRGB_decode");
+
        // Since we allow non-bouncing 4:2:2 YCbCrInputs, effective subpixel precision
        // will be halved when sampling them, and we need to compensate here.
        movit_texel_subpixel_precision /= 2.0;
@@ -361,9 +386,12 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, bool
        if (card->output.get() != output) {
                card->output.reset(output);
        }
+
+       bmusb::PixelFormat pixel_format = global_flags.ten_bit_input ? PixelFormat_10BitYCbCr : PixelFormat_8BitYCbCr;
+
        card->capture->set_frame_callback(bind(&Mixer::bm_frame, this, card_index, _1, _2, _3, _4, _5, _6, _7));
        if (card->frame_allocator == nullptr) {
-               card->frame_allocator.reset(new PBOFrameAllocator(8 << 20, global_flags.width, global_flags.height));  // 8 MB.
+               card->frame_allocator.reset(new PBOFrameAllocator(pixel_format, 8 << 20, global_flags.width, global_flags.height));  // 8 MB.
        }
        card->capture->set_video_frame_allocator(card->frame_allocator.get());
        if (card->surface == nullptr) {
@@ -371,7 +399,7 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, bool
        }
        while (!card->new_frames.empty()) card->new_frames.pop_front();
        card->last_timecode = -1;
-       card->capture->set_pixel_format(global_flags.ten_bit_input ? PixelFormat_10BitYCbCr : PixelFormat_8BitYCbCr);
+       card->capture->set_pixel_format(pixel_format);
        card->capture->configure_card();
 
        // NOTE: start_bm_capture() happens in thread_func().
@@ -588,24 +616,36 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                                field_start_line = video_format.extra_lines_top;
                        }
 
-                       // For 8-bit input, v210_width will be nonsensical but not used.
+                       // For anything not FRAME_FORMAT_YCBCR_10BIT, v210_width will be nonsensical but not used.
                        size_t v210_width = video_format.stride / sizeof(uint32_t);
                        ensure_texture_resolution(userdata, field, video_format.width, video_format.height, v210_width);
 
                        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, userdata->pbo);
                        check_error();
 
-                       if (global_flags.ten_bit_input) {
+                       switch (userdata->pixel_format) {
+                       case bmusb::PixelFormat_10BitYCbCr: {
                                size_t field_start = video_offset + video_format.stride * field_start_line;
                                upload_texture(userdata->tex_v210[field], v210_width, video_format.height, video_format.stride, interlaced_stride, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, field_start);
                                v210_converter->convert(userdata->tex_v210[field], userdata->tex_444[field], video_format.width, video_format.height);
-                       } else {
+                               break;
+                       }
+                       case bmusb::PixelFormat_8BitYCbCr: {
                                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);
 
                                // Make up our own strides, since we are interleaving.
                                upload_texture(userdata->tex_y[field], video_format.width, video_format.height, video_format.width, interlaced_stride, GL_RED, GL_UNSIGNED_BYTE, field_y_start);
                                upload_texture(userdata->tex_cbcr[field], cbcr_width, video_format.height, cbcr_width * sizeof(uint16_t), interlaced_stride, GL_RG, GL_UNSIGNED_BYTE, field_cbcr_start);
+                               break;
+                       }
+                       case bmusb::PixelFormat_8BitRGBA: {
+                               size_t field_start = video_offset + video_format.stride * field_start_line;
+                               upload_texture(userdata->tex_rgba[field], video_format.width, video_format.height, video_format.stride, interlaced_stride, GL_RGBA, GL_UNSIGNED_BYTE, field_start);
+                               break;
+                       }
+                       default:
+                               assert(false);
                        }
 
                        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -854,10 +894,12 @@ void Mixer::trim_queue(CaptureCard *card, unsigned card_index)
                ++dropped_frames;
        }
 
+#if 0
        if (dropped_frames > 0) {
                fprintf(stderr, "Card %u dropped %u frame(s) to keep latency down.\n",
                        card_index, dropped_frames);
        }
+#endif
 }