Skip to content
Commits on Source (5)
......@@ -183,6 +183,8 @@ headless_output_disable_gl(struct headless_output *output)
weston_gl_borders_fini(&output->gl.borders, &output->base);
weston_renderbuffer_unref(output->renderbuffer);
output->renderbuffer = NULL;
renderer->gl->output_destroy(&output->base);
if (output->frame) {
......@@ -252,10 +254,7 @@ headless_output_enable_gl(struct headless_output *output)
struct headless_backend *b = output->backend;
const struct weston_renderer *renderer = b->compositor->renderer;
const struct weston_mode *mode = output->base.current_mode;
struct gl_renderer_pbuffer_options options = {
.formats = b->formats,
.formats_count = b->formats_count,
};
struct gl_renderer_fbo_options options = { 0 };
if (b->decorate) {
/*
......@@ -283,7 +282,7 @@ headless_output_enable_gl(struct headless_output *output)
options.fb_size.height = mode->height;
}
if (renderer->gl->output_pbuffer_create(&output->base, &options) < 0) {
if (renderer->gl->output_fbo_create(&output->base, &options) < 0) {
weston_log("failed to create gl renderer output state\n");
if (output->frame) {
frame_destroy(output->frame);
......@@ -292,7 +291,19 @@ headless_output_enable_gl(struct headless_output *output)
return -1;
}
output->renderbuffer =
renderer->gl->create_fbo(&output->base, b->formats[0],
options.fb_size.width,
options.fb_size.height);
if (!output->renderbuffer)
goto err_renderbuffer;
return 0;
err_renderbuffer:
renderer->gl->output_destroy(&output->base);
return -1;
}
static int
......@@ -556,7 +567,6 @@ headless_backend_create(struct weston_compositor *compositor,
const struct gl_renderer_display_options options = {
.egl_platform = EGL_PLATFORM_SURFACELESS_MESA,
.egl_native_display = NULL,
.egl_surface_type = EGL_PBUFFER_BIT,
.formats = b->formats,
.formats_count = b->formats_count,
};
......
......@@ -50,10 +50,12 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#define GL_INTERNALFORMAT(fmt) .gl_internalformat = (fmt)
#define GL_FORMAT(fmt) .gl_format = (fmt)
#define GL_TYPE(type) .gl_type = (type)
#define SAMPLER_TYPE(type) .sampler_type = (type)
#else
#define GL_INTERNALFORMAT(fmt) .gl_internalformat = 0
#define GL_FORMAT(fmt) .gl_format = 0
#define GL_TYPE(type) .gl_type = 0
#define SAMPLER_TYPE(type) .sampler_type = 0
......@@ -237,6 +239,7 @@ static const struct pixel_format_info pixel_format_table[] = {
BITS_RGBA_FIXED(8, 8, 8, 0),
.addfb_legacy_depth = 24,
.bpp = 32,
GL_INTERNALFORMAT(GL_RGB8),
GL_FORMAT(GL_BGRA_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
#if __BYTE_ORDER == __LITTLE_ENDIAN
......@@ -251,6 +254,7 @@ static const struct pixel_format_info pixel_format_table[] = {
.opaque_substitute = DRM_FORMAT_XRGB8888,
.addfb_legacy_depth = 32,
.bpp = 32,
GL_INTERNALFORMAT(GL_RGBA8),
GL_FORMAT(GL_BGRA_EXT),
GL_TYPE(GL_UNSIGNED_BYTE),
#if __BYTE_ORDER == __LITTLE_ENDIAN
......@@ -331,6 +335,7 @@ static const struct pixel_format_info pixel_format_table[] = {
BITS_RGBA_FIXED(10, 10, 10, 0),
.addfb_legacy_depth = 30,
.bpp = 32,
GL_INTERNALFORMAT(GL_RGB10_A2),
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(x2r10g10b10),
#endif
......@@ -340,6 +345,7 @@ static const struct pixel_format_info pixel_format_table[] = {
BITS_RGBA_FIXED(10, 10, 10, 2),
.bpp = 32,
.opaque_substitute = DRM_FORMAT_XRGB2101010,
GL_INTERNALFORMAT(GL_RGB10_A2),
#if __BYTE_ORDER == __LITTLE_ENDIAN
PIXMAN_FMT(a2r10g10b10),
#endif
......
......@@ -62,6 +62,9 @@ struct pixel_format_info {
* opaque. */
uint32_t sampler_type;
/** GL internal format; to be used when creating FBO renderbuffers */
int gl_internalformat;
/** GL format, if data can be natively/directly uploaded. Note that
* whilst DRM formats are little-endian unless explicitly specified,
* (i.e. DRM_FORMAT_ARGB8888 is stored BGRA as sequential bytes in
......
......@@ -177,7 +177,9 @@ struct gl_renderer {
bool has_texture_type_2_10_10_10_rev;
bool has_gl_texture_rg;
bool has_texture_norm16;
bool has_texture_storage;
bool has_pack_reverse;
bool has_rgb8_rgba8;
struct gl_shader *current_shader;
struct gl_shader *fallback_shader;
......
......@@ -93,6 +93,9 @@ struct gl_fbo_texture {
struct gl_renderbuffer {
struct weston_renderbuffer base;
enum gl_border_status border_damage;
/* The fbo value zero represents the default surface framebuffer. */
GLuint fbo;
GLuint rb;
struct wl_list link;
int age;
};
......@@ -104,7 +107,6 @@ struct gl_output_state {
EGLSurface egl_surface;
struct gl_border_image borders[4];
enum gl_border_status border_status;
bool swap_behavior_is_preserved;
struct weston_matrix output_matrix;
......@@ -718,12 +720,19 @@ gl_fbo_texture_fini(struct gl_fbo_texture *fbotex)
fbotex->tex = 0;
}
static inline struct gl_renderbuffer *
to_gl_renderbuffer(struct weston_renderbuffer *renderbuffer)
{
return container_of(renderbuffer, struct gl_renderbuffer, base);
}
static void
gl_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer)
{
struct gl_renderbuffer *rb;
struct gl_renderbuffer *rb = to_gl_renderbuffer(renderbuffer);
rb = container_of(renderbuffer, struct gl_renderbuffer, base);
glDeleteFramebuffers(1, &rb->fbo);
glDeleteRenderbuffers(1, &rb->rb);
pixman_region32_fini(&rb->base.damage);
free(rb);
}
......@@ -736,6 +745,8 @@ gl_renderer_create_dummy_renderbuffer(struct weston_output *output)
renderbuffer = xzalloc(sizeof(*renderbuffer));
renderbuffer->fbo = 0;
pixman_region32_init(&renderbuffer->base.damage);
pixman_region32_copy(&renderbuffer->base.damage, &output->region);
renderbuffer->border_damage = BORDER_ALL_DIRTY;
......@@ -750,6 +761,66 @@ gl_renderer_create_dummy_renderbuffer(struct weston_output *output)
return renderbuffer;
}
static struct weston_renderbuffer *
gl_renderer_create_fbo(struct weston_output *output,
const struct pixel_format_info *format,
int width, int height)
{
struct gl_renderer *gr = get_renderer(output->compositor);
struct gl_output_state *go = get_output_state(output);
struct gl_renderbuffer *renderbuffer;
int fb_status;
switch (format->gl_internalformat) {
case GL_RGB8:
case GL_RGBA8:
if (!gr->has_rgb8_rgba8)
return NULL;
break;
case GL_RGB10_A2:
if (!gr->has_texture_type_2_10_10_10_rev ||
!gr->has_texture_storage)
return NULL;
break;
default:
return NULL;
}
renderbuffer = xzalloc(sizeof(*renderbuffer));
glGenFramebuffers(1, &renderbuffer->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, renderbuffer->fbo);
glGenRenderbuffers(1, &renderbuffer->rb);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer->rb);
glRenderbufferStorage(GL_RENDERBUFFER, format->gl_internalformat,
width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, renderbuffer->rb);
fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &renderbuffer->fbo);
glDeleteRenderbuffers(1, &renderbuffer->rb);
free(renderbuffer);
return NULL;
}
pixman_region32_init(&renderbuffer->base.damage);
/*
* One reference is kept on the renderbuffer_list,
* the other is returned to the calling backend.
*/
renderbuffer->base.refcount = 2;
renderbuffer->base.destroy = gl_renderer_renderbuffer_destroy;
wl_list_insert(&go->renderbuffer_list, &renderbuffer->link);
return &renderbuffer->base;
}
static bool
gl_renderer_do_capture(struct gl_renderer *gr, struct weston_buffer *into,
const struct weston_geometry *rect)
......@@ -1585,15 +1656,14 @@ output_get_buffer_age(struct weston_output *output)
EGLint buffer_age = 0;
EGLBoolean ret;
if (gr->has_egl_buffer_age || gr->has_egl_partial_update) {
if ((gr->has_egl_buffer_age || gr->has_egl_partial_update) &&
go->egl_surface != EGL_NO_SURFACE) {
ret = eglQuerySurface(gr->egl_display, go->egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age);
if (ret == EGL_FALSE) {
weston_log("buffer age query failed.\n");
gl_renderer_print_egl_error_state();
}
} else if (go->swap_behavior_is_preserved) {
buffer_age = 1;
}
return buffer_age;
......@@ -1804,7 +1874,6 @@ gl_renderer_repaint_output(struct weston_output *output,
struct gl_output_state *go = get_output_state(output);
struct weston_compositor *compositor = output->compositor;
struct gl_renderer *gr = get_renderer(compositor);
EGLBoolean ret;
static int errored;
struct weston_paint_node *pnode;
const int32_t area_inv_y =
......@@ -1826,7 +1895,10 @@ gl_renderer_repaint_output(struct weston_output *output,
rb->border_damage |= go->border_status;
}
rb = output_get_dummy_renderbuffer(output);
if (renderbuffer)
rb = to_gl_renderbuffer(renderbuffer);
else
rb = output_get_dummy_renderbuffer(output);
/* Clear the used_in_output_repaint flag, so that we can properly track
* which surfaces were used in this output repaint. */
......@@ -1855,7 +1927,7 @@ gl_renderer_repaint_output(struct weston_output *output,
glBindFramebuffer(GL_FRAMEBUFFER, go->shadow.fbo);
glViewport(0, 0, go->area.width, go->area.height);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, rb->fbo);
glViewport(go->area.x, area_inv_y,
go->area.width, go->area.height);
}
......@@ -1896,7 +1968,7 @@ gl_renderer_repaint_output(struct weston_output *output,
else
repaint_views(output, output_damage);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, rb->fbo);
glViewport(go->area.x, area_inv_y,
go->area.width, go->area.height);
blit_shadow_to_output(output, &rb->base.damage);
......@@ -1918,27 +1990,33 @@ gl_renderer_repaint_output(struct weston_output *output,
gr->destroy_sync(gr->egl_display, go->render_sync);
go->render_sync = create_render_sync(gr);
if (gr->swap_buffers_with_damage && !gr->fan_debug) {
int n_egl_rects;
EGLint *egl_rects;
if (go->egl_surface != EGL_NO_SURFACE) {
EGLBoolean ret;
if (gr->swap_buffers_with_damage && !gr->fan_debug) {
int n_egl_rects;
EGLint *egl_rects;
/* For swap_buffers_with_damage, we need to pass the region
* which has changed since the previous SwapBuffers on this
* surface - this is output_damage. */
pixman_region_to_egl_y_invert(output, output_damage,
&egl_rects, &n_egl_rects);
ret = gr->swap_buffers_with_damage(gr->egl_display,
go->egl_surface,
egl_rects, n_egl_rects);
free(egl_rects);
} else {
ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
}
/* For swap_buffers_with_damage, we need to pass the region
* which has changed since the previous SwapBuffers on this
* surface - this is output_damage. */
pixman_region_to_egl_y_invert(output, output_damage,
&egl_rects, &n_egl_rects);
ret = gr->swap_buffers_with_damage(gr->egl_display,
go->egl_surface,
egl_rects, n_egl_rects);
free(egl_rects);
if (ret == EGL_FALSE && !errored) {
errored = 1;
weston_log("Failed in eglSwapBuffers.\n");
gl_renderer_print_egl_error_state();
}
} else {
ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
}
if (ret == EGL_FALSE && !errored) {
errored = 1;
weston_log("Failed in eglSwapBuffers.\n");
gl_renderer_print_egl_error_state();
glFlush();
}
pixman_region32_clear(&rb->base.damage);
......@@ -3620,7 +3698,7 @@ gl_renderer_output_window_create(struct weston_output *output,
struct weston_compositor *ec = output->compositor;
struct gl_renderer *gr = get_renderer(ec);
EGLSurface egl_surface = EGL_NO_SURFACE;
int ret = 0;
int ret;
egl_surface = gl_renderer_create_window_surface(gr,
options->window_for_legacy,
......@@ -3641,58 +3719,11 @@ gl_renderer_output_window_create(struct weston_output *output,
}
static int
gl_renderer_output_pbuffer_create(struct weston_output *output,
const struct gl_renderer_pbuffer_options *options)
gl_renderer_output_fbo_create(struct weston_output *output,
const struct gl_renderer_fbo_options *options)
{
struct gl_renderer *gr = get_renderer(output->compositor);
struct gl_output_state *go;
EGLConfig pbuffer_config;
EGLSurface egl_surface;
EGLint value = 0;
int ret;
EGLint pbuffer_attribs[] = {
EGL_WIDTH, options->fb_size.width,
EGL_HEIGHT, options->fb_size.height,
EGL_NONE
};
pbuffer_config = gl_renderer_get_egl_config(gr, EGL_PBUFFER_BIT,
options->formats,
options->formats_count);
if (pbuffer_config == EGL_NO_CONFIG_KHR) {
weston_log("failed to choose EGL config for PbufferSurface\n");
return -1;
}
log_egl_config_info(gr->egl_display, pbuffer_config);
egl_surface = eglCreatePbufferSurface(gr->egl_display, pbuffer_config,
pbuffer_attribs);
if (egl_surface == EGL_NO_SURFACE) {
weston_log("failed to create egl surface\n");
gl_renderer_print_egl_error_state();
return -1;
}
eglSurfaceAttrib(gr->egl_display, egl_surface,
EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
if (!eglQuerySurface(gr->egl_display, egl_surface,
EGL_SWAP_BEHAVIOR, &value) ||
value != EGL_BUFFER_PRESERVED) {
weston_log("Error: pbuffer surface does not support EGL_BUFFER_PRESERVED, got 0x%x."
" Continuing anyway.\n", value);
}
ret = gl_renderer_output_create(output, egl_surface,
return gl_renderer_output_create(output, EGL_NO_SURFACE,
&options->fb_size, &options->area);
if (ret < 0) {
eglDestroySurface(gr->egl_display, egl_surface);
} else {
go = get_output_state(output);
go->swap_behavior_is_preserved = true;
}
return ret;
}
static void
......@@ -4161,6 +4192,10 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
if (weston_check_egl_extension(extensions, "GL_EXT_texture_norm16"))
gr->has_texture_norm16 = true;
if (gr->gl_version >= gr_gl_version(3, 0) ||
weston_check_egl_extension(extensions, "GL_EXT_texture_storage"))
gr->has_texture_storage = true;
if (weston_check_egl_extension(extensions, "GL_ANGLE_pack_reverse_row_order"))
gr->has_pack_reverse = true;
......@@ -4171,6 +4206,10 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
if (weston_check_egl_extension(extensions, "GL_OES_EGL_image_external"))
gr->has_egl_image_external = true;
if (gr->gl_version >= gr_gl_version(3, 0) ||
weston_check_egl_extension(extensions, "GL_OES_rgb8_rgba8"))
gr->has_rgb8_rgba8 = true;
if (gr->gl_version >= gr_gl_version(3, 0) &&
weston_check_egl_extension(extensions, "GL_OES_texture_float_linear") &&
weston_check_egl_extension(extensions, "GL_EXT_color_buffer_half_float") &&
......@@ -4258,8 +4297,9 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
.display_create = gl_renderer_display_create,
.output_window_create = gl_renderer_output_window_create,
.output_pbuffer_create = gl_renderer_output_pbuffer_create,
.output_fbo_create = gl_renderer_output_fbo_create,
.output_destroy = gl_renderer_output_destroy,
.output_set_border = gl_renderer_output_set_border,
.create_fence_fd = gl_renderer_create_fence_fd,
.create_fbo = gl_renderer_create_fbo,
};
......@@ -94,15 +94,11 @@ struct gl_renderer_output_options {
unsigned formats_count;
};
struct gl_renderer_pbuffer_options {
struct gl_renderer_fbo_options {
/** Size of the framebuffer in pixels, including borders */
struct weston_size fb_size;
/** Area inside the framebuffer in pixels for composited content */
struct weston_geometry area;
/** Array of pixel formats acceptable for the pbuffer */
const struct pixel_format_info **formats;
/** The \c formats array length */
unsigned formats_count;
};
struct gl_renderer_interface {
......@@ -165,25 +161,18 @@ struct gl_renderer_interface {
const struct gl_renderer_output_options *options);
/**
* Attach GL-renderer to the output with internal pixel storage
* Attach GL-renderer to the output with a frame buffer object
*
* \param output The output to create a rendering surface for.
* \param options The options struct describing the pbuffer
* \param output The output to prepare for FBO rendering.
* \param options The options struct describing the render geometry
* \return 0 on success, -1 on failure.
*
* This function creates the renderer data structures needed to repaint
* the output. The repaint results will be kept internal and can only
* be accessed through e.g. screen capture.
*
* The first format in formats that matches any EGLConfig
* determines which EGLConfig is chosen. See \c display_create about
* how the matching works and the possible limitations.
*
* This function should be used only if \c display_create was called
* with \c EGL_PBUFFER_BIT in \c egl_surface_type.
* the output. The repaint results will be stored in FBO renderbuffers
* passed to \c repaint_output.
*/
int (*output_pbuffer_create)(struct weston_output *output,
const struct gl_renderer_pbuffer_options *options);
int (*output_fbo_create)(struct weston_output *output,
const struct gl_renderer_fbo_options *options);
void (*output_destroy)(struct weston_output *output);
......@@ -225,4 +214,20 @@ struct gl_renderer_interface {
* EGL_ANDROID_native_fence_sync extension.
*/
int (*create_fence_fd)(struct weston_output *output);
/**
* Create an FBO renderbuffer that repaint_output can render to
*
* \param output The output to create an FBO renderbuffer for.
* \param format The renderbuffer pixel format.
* \param width The renderbuffer width.
* \param height The renderbuffer height.
* \return 0 on success, -1 on failure.
*
* This function creates an FBO renderbuffer that can be passed to \c
* repaint_output.
*/
struct weston_renderbuffer *(*create_fbo)(struct weston_output *output,
const struct pixel_format_info *format,
int width, int height);
};