File: render.c

package info (click to toggle)
wlroots 0.19.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,592 kB
  • sloc: ansic: 75,766; xml: 2,739; sh: 33; makefile: 23
file content (218 lines) | stat: -rw-r--r-- 6,487 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include <assert.h>
#include <drm_fourcc.h>
#include <stdlib.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/allocator.h>
#include <wlr/render/interface.h>
#include <wlr/render/swapchain.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
#include "render/drm_format_set.h"
#include "render/wlr_renderer.h"
#include "render/pixel_format.h"
#include "types/wlr_output.h"

bool wlr_output_init_render(struct wlr_output *output,
		struct wlr_allocator *allocator, struct wlr_renderer *renderer) {
	assert(allocator != NULL && renderer != NULL);

	if (!(output->backend->buffer_caps & allocator->buffer_caps)) {
		wlr_log(WLR_ERROR, "output backend and allocator buffer capabilities "
			"don't match");
		return false;
	} else if (!(renderer->render_buffer_caps & allocator->buffer_caps)) {
		wlr_log(WLR_ERROR, "renderer and allocator buffer capabilities "
			"don't match");
		return false;
	}

	wlr_swapchain_destroy(output->swapchain);
	output->swapchain = NULL;

	wlr_swapchain_destroy(output->cursor_swapchain);
	output->cursor_swapchain = NULL;

	output->allocator = allocator;
	output->renderer = renderer;

	return true;
}

static struct wlr_buffer *output_acquire_empty_buffer(struct wlr_output *output,
		const struct wlr_output_state *state) {
	assert(!(state->committed & WLR_OUTPUT_STATE_BUFFER));

	// wlr_output_configure_primary_swapchain() function will call
	// wlr_output_test_state(), which can call us again. This is dangerous: we
	// risk infinite recursion. However, a buffer will always be supplied in
	// wlr_output_test_state(), which will prevent us from being called.
	if (!wlr_output_configure_primary_swapchain(output, state,
			&output->swapchain)) {
		return NULL;
	}

	struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain);
	if (buffer == NULL) {
		return NULL;
	}

	struct wlr_render_pass *pass =
		wlr_renderer_begin_buffer_pass(output->renderer, buffer, NULL);
	if (pass == NULL) {
		wlr_buffer_unlock(buffer);
		return NULL;
	}

	wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
		.color = { 0, 0, 0, 0 },
		.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
	});

	if (!wlr_render_pass_submit(pass)) {
		wlr_buffer_unlock(buffer);
		return NULL;
	}

	return buffer;
}

// This function may attach a new, empty buffer if necessary.
// If so, the new_back_buffer out parameter will be set to true.
bool output_ensure_buffer(struct wlr_output *output,
		struct wlr_output_state *state, bool *new_buffer) {
	assert(*new_buffer == false);

	// If we already have a buffer, we don't need to allocate a new one
	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
		return true;
	}

	// If the compositor hasn't called wlr_output_init_render(), they will use
	// their own logic to attach buffers
	if (output->renderer == NULL) {
		return true;
	}

	bool enabled = output->enabled;
	if (state->committed & WLR_OUTPUT_STATE_ENABLED) {
		enabled = state->enabled;
	}

	// If we're lighting up an output or changing its mode, make sure to
	// provide a new buffer
	bool needs_new_buffer = false;
	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
		needs_new_buffer = true;
	}
	if (state->committed & WLR_OUTPUT_STATE_MODE) {
		needs_new_buffer = true;
	}
	if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
		needs_new_buffer = true;
	}
	if (state->allow_reconfiguration && output->commit_seq == 0 && enabled) {
		// On first commit, require a new buffer if the compositor called a
		// mode-setting function, even if the mode won't change. This makes it
		// so the swapchain is created now.
		needs_new_buffer = true;
	}
	if (!needs_new_buffer) {
		return true;
	}

	wlr_log(WLR_DEBUG, "Attaching empty buffer to output for modeset");
	struct wlr_buffer *buffer = output_acquire_empty_buffer(output, state);
	if (buffer == NULL) {
		return false;
	}

	*new_buffer = true;
	wlr_output_state_set_buffer(state, buffer);
	wlr_buffer_unlock(buffer);
	return true;
}

void wlr_output_lock_attach_render(struct wlr_output *output, bool lock) {
	if (lock) {
		++output->attach_render_locks;
	} else {
		assert(output->attach_render_locks > 0);
		--output->attach_render_locks;
	}
	wlr_log(WLR_DEBUG, "%s direct scan-out on output '%s' (locks: %d)",
		lock ? "Disabling" : "Enabling", output->name,
		output->attach_render_locks);
}

bool output_pick_format(struct wlr_output *output,
		const struct wlr_drm_format_set *display_formats,
		struct wlr_drm_format *format, uint32_t fmt) {
	struct wlr_renderer *renderer = output->renderer;
	struct wlr_allocator *allocator = output->allocator;
	assert(renderer != NULL && allocator != NULL);

	const struct wlr_drm_format_set *render_formats =
		wlr_renderer_get_render_formats(renderer);
	if (render_formats == NULL) {
		wlr_log(WLR_ERROR, "Failed to get render formats");
		return false;
	}

	const struct wlr_drm_format *render_format =
		wlr_drm_format_set_get(render_formats, fmt);
	if (render_format == NULL) {
		wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%"PRIX32, fmt);
		return false;
	}

	if (display_formats != NULL) {
		const struct wlr_drm_format *display_format =
			wlr_drm_format_set_get(display_formats, fmt);
		if (display_format == NULL) {
			wlr_log(WLR_DEBUG, "Output doesn't support format 0x%"PRIX32, fmt);
			return false;
		}
		if (!wlr_drm_format_intersect(format, display_format, render_format)) {
			wlr_log(WLR_DEBUG, "Failed to intersect display and render "
				"modifiers for format 0x%"PRIX32 " on output %s",
				fmt, output->name);
			return false;
		}
	} else {
		// The output can display any format
		if (!wlr_drm_format_copy(format, render_format)) {
			return false;
		}
	}

	if (format->len == 0) {
		wlr_drm_format_finish(format);
		wlr_log(WLR_DEBUG, "Failed to pick output format");
		return false;
	}

	return true;
}

struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,
		struct wlr_output_state *state, struct wlr_buffer_pass_options *render_options) {
	if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
		return NULL;
	}

	struct wlr_buffer *buffer = wlr_swapchain_acquire(output->swapchain);
	if (buffer == NULL) {
		return NULL;
	}

	struct wlr_renderer *renderer = output->renderer;
	assert(renderer != NULL);
	struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, buffer, render_options);
	if (pass == NULL) {
		return NULL;
	}

	wlr_output_state_set_buffer(state, buffer);
	wlr_buffer_unlock(buffer);
	return pass;
}