Skip to content

Commit 634a781

Browse files
committed
output-layout: replace output mirroring implementation
The new mirroring implementation is much less efficient, however, it works at least ...
1 parent 835a7bf commit 634a781

File tree

4 files changed

+107
-114
lines changed

4 files changed

+107
-114
lines changed

src/core/opengl-priv.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ void init();
1111
/** Destroy the default GL program and resources */
1212
void fini();
1313
/** Indicate we have started repainting the given output */
14-
void bind_output(wf::output_t *output, uint32_t fb);
14+
void bind_output(uint32_t fb);
1515
/** Indicate the output frame has been finished */
16-
void unbind_output(wf::output_t *output);
16+
void unbind_output();
1717
}
1818

1919
#endif /* end of include guard: WF_OPENGL_PRIV_HPP */

src/core/opengl.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,16 @@ void fini()
115115

116116
namespace
117117
{
118-
wf::output_t *current_output = NULL;
119-
uint32_t current_output_fb = 0;
118+
uint32_t current_output_fb = 0;
120119
}
121120

122-
void bind_output(wf::output_t *output, uint32_t fb)
121+
void bind_output(uint32_t fb)
123122
{
124-
current_output = output;
125123
current_output_fb = fb;
126124
}
127125

128-
void unbind_output(wf::output_t *output)
126+
void unbind_output()
129127
{
130-
current_output = NULL;
131128
current_output_fb = 0;
132129
}
133130

src/core/output-layout.cpp

Lines changed: 98 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "opengl-priv.hpp"
12
#include "wayfire/output.hpp"
23
#include "wayfire/core.hpp"
34
#include "wayfire/output-layout.hpp"
@@ -249,6 +250,100 @@ inline bool is_shutting_down()
249250
return wf::get_core().get_current_state() == compositor_state_t::SHUTDOWN;
250251
}
251252

253+
class output_cloner_t
254+
{
255+
wf::wl_listener_wrapper source_commit;
256+
wf::wl_listener_wrapper destination_frame;
257+
wf::framebuffer_base_t content;
258+
259+
wlr_output *source;
260+
wlr_output *destination;
261+
262+
public:
263+
output_cloner_t(wlr_output *source, wlr_output *destination)
264+
{
265+
this->source = source;
266+
this->destination = destination;
267+
wlr_output_lock_software_cursors(source, true);
268+
wlr_output_schedule_frame(destination);
269+
270+
source_commit.set_callback([=] (void *data)
271+
{
272+
auto ev = (wlr_output_event_commit*)data;
273+
if (!(ev->committed & WLR_OUTPUT_STATE_BUFFER))
274+
{
275+
// Something else than the output contents changed, nothing to do yet
276+
return;
277+
}
278+
279+
int w = ev->buffer->width;
280+
int h = ev->buffer->height;
281+
282+
OpenGL::render_begin();
283+
content.allocate(w, h);
284+
285+
// Bind buffer
286+
auto renderer = get_core().renderer;
287+
wlr_renderer_begin_with_buffer(renderer, ev->buffer);
288+
289+
// Store a copy for ourselves
290+
GL_CALL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, content.fb));
291+
GL_CALL(glBlitFramebuffer(0, 0, w, h,
292+
0, 0, w, h,
293+
GL_COLOR_BUFFER_BIT, GL_LINEAR));
294+
295+
wlr_renderer_end(renderer);
296+
OpenGL::render_end();
297+
298+
wlr_output_damage_whole(destination);
299+
wlr_output_schedule_frame(destination);
300+
});
301+
302+
destination_frame.set_callback([=] (void *data)
303+
{
304+
auto renderer = get_core().renderer;
305+
wlr_output_attach_render(destination, NULL);
306+
wlr_renderer_begin(renderer, destination->width, destination->height);
307+
308+
int w = content.viewport_width;
309+
int h = content.viewport_height;
310+
if ((w > 0) && (h > 0))
311+
{
312+
int current_fb;
313+
GL_CALL(glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fb));
314+
OpenGL::bind_output(current_fb);
315+
316+
OpenGL::render_begin();
317+
GL_CALL(glBindFramebuffer(GL_READ_FRAMEBUFFER, content.fb));
318+
GL_CALL(glBlitFramebuffer(0, 0, w, h,
319+
0, 0, destination->width, destination->height,
320+
GL_COLOR_BUFFER_BIT, GL_LINEAR));
321+
322+
OpenGL::render_end();
323+
}
324+
325+
wlr_renderer_end(renderer);
326+
wlr_output_commit(destination);
327+
});
328+
329+
source_commit.connect(&source->events.commit);
330+
destination_frame.connect(&destination->events.frame);
331+
}
332+
333+
~output_cloner_t()
334+
{
335+
wlr_output_lock_software_cursors(source, false);
336+
OpenGL::render_begin();
337+
content.release();
338+
OpenGL::render_end();
339+
}
340+
341+
output_cloner_t(const output_cloner_t&) = delete;
342+
output_cloner_t(output_cloner_t&&) = delete;
343+
output_cloner_t& operator =(const output_cloner_t&) = delete;
344+
output_cloner_t& operator =(output_cloner_t&&) = delete;
345+
};
346+
252347
/** Represents a single output in the output layout */
253348
struct output_layout_output_t
254349
{
@@ -589,64 +684,6 @@ struct output_layout_output_t
589684
wlr_output_commit(handle);
590685
}
591686

592-
/* Mirroring implementation */
593-
wl_listener_wrapper on_mirrored_frame;
594-
wl_listener_wrapper on_frame;
595-
wlr_output *locked_cursors_on = NULL;
596-
597-
/** Render the output using texture as source */
598-
void render_output(wlr_texture *texture)
599-
{
600-
auto renderer = get_core().renderer;
601-
wlr_output_attach_render(handle, NULL);
602-
wlr_renderer_begin(renderer, handle->width, handle->height);
603-
604-
wf::texture_t tex{texture};
605-
OpenGL::render_transformed_texture(tex, {-1, -1, 2, 2});
606-
607-
wlr_renderer_end(renderer);
608-
wlr_output_commit(handle);
609-
}
610-
611-
/* Load output contents and render them */
612-
wlr_buffer *source_back_buffer = NULL;
613-
614-
void handle_frame()
615-
{
616-
auto wo = get_core().output_layout->find_output(
617-
current_state.mirror_from);
618-
if (!wo)
619-
{
620-
LOGE("Cannot find mirrored output ", current_state.mirror_from,
621-
" for output ", handle->name);
622-
623-
return;
624-
}
625-
626-
wlr_dmabuf_attributes attributes;
627-
if (source_back_buffer == NULL)
628-
{
629-
LOGE("Got empty buffer on ", wo->handle->name);
630-
return;
631-
}
632-
633-
if (!wlr_buffer_get_dmabuf(source_back_buffer, &attributes))
634-
{
635-
LOGE("Failed reading mirrored output contents from ", wo->handle->name);
636-
637-
return;
638-
}
639-
640-
/* We export the output to mirror from to a dmabuf, then create
641-
* a texture from this and use it to render "our" output */
642-
auto texture = wlr_texture_from_dmabuf(
643-
get_core().renderer, &attributes);
644-
render_output(texture);
645-
646-
wlr_texture_destroy(texture);
647-
wlr_dmabuf_attributes_finish(&attributes);
648-
}
649-
650687
void set_enabled(bool enabled)
651688
{
652689
wlr_output_enable(handle, enabled);
@@ -656,6 +693,7 @@ struct output_layout_output_t
656693
}
657694
}
658695

696+
std::unique_ptr<output_cloner_t> cloner;
659697
void setup_mirror()
660698
{
661699
/* Check if we can mirror */
@@ -686,55 +724,12 @@ struct output_layout_output_t
686724
return;
687725
}
688726

689-
/* Force software cursors on the mirrored from output.
690-
* This ensures that they will be copied when reading pixels
691-
* from the main plane */
692-
wlr_output_lock_software_cursors(wo->handle, true);
693-
locked_cursors_on = wo->handle;
694-
695-
wlr_output_schedule_frame(handle);
696-
on_mirrored_frame.set_callback([=] (void *data)
697-
{
698-
auto ev = (wlr_output_event_commit*)data;
699-
700-
if (ev->buffer)
701-
{
702-
if (source_back_buffer)
703-
{
704-
wlr_buffer_unlock(source_back_buffer);
705-
}
706-
707-
source_back_buffer = ev->buffer;
708-
wlr_buffer_lock(ev->buffer);
709-
}
710-
711-
/* The mirrored output was repainted, schedule repaint
712-
* for us as well */
713-
wlr_output_damage_whole(handle);
714-
wlr_output_schedule_frame(handle);
715-
});
716-
on_mirrored_frame.connect(&wo->handle->events.commit);
717-
718-
on_frame.set_callback([=] (void*) { handle_frame(); });
719-
on_frame.connect(&handle->events.frame);
727+
cloner = std::make_unique<output_cloner_t>(wo->handle, this->handle);
720728
}
721729

722730
void teardown_mirror()
723731
{
724-
if (locked_cursors_on)
725-
{
726-
wlr_output_lock_software_cursors(locked_cursors_on, false);
727-
locked_cursors_on = NULL;
728-
}
729-
730-
if (source_back_buffer)
731-
{
732-
wlr_buffer_unlock(source_back_buffer);
733-
source_back_buffer = NULL;
734-
}
735-
736-
on_mirrored_frame.disconnect();
737-
on_frame.disconnect();
732+
cloner.reset();
738733
}
739734

740735
wf::dimensions_t get_effective_size()

src/output/render-manager.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ class wf::render_manager::impl
793793
*/
794794
void bind_output(uint32_t fb)
795795
{
796-
OpenGL::bind_output(output, fb);
796+
OpenGL::bind_output(fb);
797797

798798
/* Make sure the default buffer has enough size */
799799
postprocessing->allocate(output->handle->width, output->handle->height);
@@ -845,7 +845,8 @@ class wf::render_manager::impl
845845
!output_inhibit_counter &&
846846
!renderer &&
847847
effects->can_scanout() &&
848-
postprocessing->can_scanout();
848+
postprocessing->can_scanout() &&
849+
output->handle->software_cursor_locks == 0;
849850

850851
if (!can_scanout)
851852
{
@@ -1041,7 +1042,7 @@ class wf::render_manager::impl
10411042
OpenGL::render_end();
10421043

10431044
/* Part 6: finalize frame: swap buffers, send frame_done, etc */
1044-
OpenGL::unbind_output(output);
1045+
OpenGL::unbind_output();
10451046
output_damage->swap_buffers(swap_damage);
10461047
swap_damage.clear();
10471048
post_paint();

0 commit comments

Comments
 (0)