mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-22 12:55:58 +01:00
render/gles2: implement timer API
This commit is contained in:
parent
9e8947e4d5
commit
45ca284eee
4 changed files with 150 additions and 3 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
#include <wlr/render/gles2.h>
|
#include <wlr/render/gles2.h>
|
||||||
#include <wlr/render/interface.h>
|
#include <wlr/render/interface.h>
|
||||||
|
@ -14,6 +15,11 @@
|
||||||
#include <wlr/util/addon.h>
|
#include <wlr/util/addon.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
// mesa ships old GL headers that don't include this type, so for distros that use headers from
|
||||||
|
// mesa we need to def it ourselves until they update.
|
||||||
|
// https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23144
|
||||||
|
typedef void (GL_APIENTRYP PFNGLGETINTEGER64VEXTPROC) (GLenum pname, GLint64 *data);
|
||||||
|
|
||||||
struct wlr_gles2_pixel_format {
|
struct wlr_gles2_pixel_format {
|
||||||
uint32_t drm_format;
|
uint32_t drm_format;
|
||||||
// optional field, if empty then internalformat = format
|
// optional field, if empty then internalformat = format
|
||||||
|
@ -47,6 +53,7 @@ struct wlr_gles2_renderer {
|
||||||
bool EXT_texture_type_2_10_10_10_REV;
|
bool EXT_texture_type_2_10_10_10_REV;
|
||||||
bool OES_texture_half_float_linear;
|
bool OES_texture_half_float_linear;
|
||||||
bool EXT_texture_norm16;
|
bool EXT_texture_norm16;
|
||||||
|
bool EXT_disjoint_timer_query;
|
||||||
} exts;
|
} exts;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -57,6 +64,12 @@ struct wlr_gles2_renderer {
|
||||||
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
|
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
|
||||||
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
|
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
|
||||||
PFNGLGETGRAPHICSRESETSTATUSKHRPROC glGetGraphicsResetStatusKHR;
|
PFNGLGETGRAPHICSRESETSTATUSKHRPROC glGetGraphicsResetStatusKHR;
|
||||||
|
PFNGLGENQUERIESEXTPROC glGenQueriesEXT;
|
||||||
|
PFNGLDELETEQUERIESEXTPROC glDeleteQueriesEXT;
|
||||||
|
PFNGLQUERYCOUNTEREXTPROC glQueryCounterEXT;
|
||||||
|
PFNGLGETQUERYOBJECTIVEXTPROC glGetQueryObjectivEXT;
|
||||||
|
PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64vEXT;
|
||||||
|
PFNGLGETINTEGER64VEXTPROC glGetInteger64vEXT;
|
||||||
} procs;
|
} procs;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -78,6 +91,15 @@ struct wlr_gles2_renderer {
|
||||||
uint32_t viewport_width, viewport_height;
|
uint32_t viewport_width, viewport_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_gles2_render_timer {
|
||||||
|
struct wlr_render_timer base;
|
||||||
|
struct wlr_gles2_renderer *renderer;
|
||||||
|
struct timespec cpu_start;
|
||||||
|
struct timespec cpu_end;
|
||||||
|
GLuint id;
|
||||||
|
GLint64 gl_cpu_end;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_gles2_buffer {
|
struct wlr_gles2_buffer {
|
||||||
struct wlr_buffer *buffer;
|
struct wlr_buffer *buffer;
|
||||||
struct wlr_gles2_renderer *renderer;
|
struct wlr_gles2_renderer *renderer;
|
||||||
|
@ -116,6 +138,7 @@ struct wlr_gles2_render_pass {
|
||||||
struct wlr_render_pass base;
|
struct wlr_render_pass base;
|
||||||
struct wlr_gles2_buffer *buffer;
|
struct wlr_gles2_buffer *buffer;
|
||||||
float projection_matrix[9];
|
float projection_matrix[9];
|
||||||
|
struct wlr_gles2_render_timer *timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
|
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
|
||||||
|
@ -128,6 +151,8 @@ const uint32_t *get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer,
|
||||||
|
|
||||||
struct wlr_gles2_renderer *gles2_get_renderer(
|
struct wlr_gles2_renderer *gles2_get_renderer(
|
||||||
struct wlr_renderer *wlr_renderer);
|
struct wlr_renderer *wlr_renderer);
|
||||||
|
struct wlr_gles2_render_timer *gles2_get_render_timer(
|
||||||
|
struct wlr_render_timer *timer);
|
||||||
struct wlr_gles2_texture *gles2_get_texture(
|
struct wlr_gles2_texture *gles2_get_texture(
|
||||||
struct wlr_texture *wlr_texture);
|
struct wlr_texture *wlr_texture);
|
||||||
|
|
||||||
|
@ -140,6 +165,7 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
|
||||||
#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__)
|
#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__)
|
||||||
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
|
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
|
||||||
|
|
||||||
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer);
|
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
|
||||||
|
struct wlr_gles2_render_timer *timer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct wlr_gles2_texture_attribs {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer);
|
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer);
|
||||||
|
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer);
|
||||||
bool wlr_texture_is_gles2(struct wlr_texture *texture);
|
bool wlr_texture_is_gles2(struct wlr_texture *texture);
|
||||||
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
|
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
|
||||||
struct wlr_gles2_texture_attribs *attribs);
|
struct wlr_gles2_texture_attribs *attribs);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
#define _POSIX_C_SOURCE 199309L
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
#include <time.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include "render/gles2.h"
|
#include "render/gles2.h"
|
||||||
#include "types/wlr_matrix.h"
|
#include "types/wlr_matrix.h"
|
||||||
|
@ -18,6 +20,19 @@ static struct wlr_gles2_render_pass *get_render_pass(struct wlr_render_pass *wlr
|
||||||
static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||||
struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass);
|
struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass);
|
||||||
struct wlr_gles2_renderer *renderer = pass->buffer->renderer;
|
struct wlr_gles2_renderer *renderer = pass->buffer->renderer;
|
||||||
|
struct wlr_gles2_render_timer *timer = pass->timer;
|
||||||
|
|
||||||
|
if (timer) {
|
||||||
|
// clear disjoint flag
|
||||||
|
GLint64 disjoint;
|
||||||
|
renderer->procs.glGetInteger64vEXT(GL_GPU_DISJOINT_EXT, &disjoint);
|
||||||
|
// set up the query
|
||||||
|
renderer->procs.glQueryCounterEXT(timer->id, GL_TIMESTAMP_EXT);
|
||||||
|
// get end-of-CPU-work time in GL time domain
|
||||||
|
renderer->procs.glGetInteger64vEXT(GL_TIMESTAMP_EXT, &timer->gl_cpu_end);
|
||||||
|
// get end-of-CPU-work time in CPU time domain
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &timer->cpu_end);
|
||||||
|
}
|
||||||
push_gles2_debug(renderer);
|
push_gles2_debug(renderer);
|
||||||
glFlush();
|
glFlush();
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
@ -219,7 +234,8 @@ static const char *reset_status_str(GLenum status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer) {
|
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
|
||||||
|
struct wlr_gles2_render_timer *timer) {
|
||||||
struct wlr_gles2_renderer *renderer = buffer->renderer;
|
struct wlr_gles2_renderer *renderer = buffer->renderer;
|
||||||
struct wlr_buffer *wlr_buffer = buffer->buffer;
|
struct wlr_buffer *wlr_buffer = buffer->buffer;
|
||||||
|
|
||||||
|
@ -240,6 +256,7 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b
|
||||||
wlr_render_pass_init(&pass->base, &render_pass_impl);
|
wlr_render_pass_init(&pass->base, &render_pass_impl);
|
||||||
wlr_buffer_lock(wlr_buffer);
|
wlr_buffer_lock(wlr_buffer);
|
||||||
pass->buffer = buffer;
|
pass->buffer = buffer;
|
||||||
|
pass->timer = timer;
|
||||||
|
|
||||||
matrix_projection(pass->projection_matrix, wlr_buffer->width, wlr_buffer->height,
|
matrix_projection(pass->projection_matrix, wlr_buffer->width, wlr_buffer->height,
|
||||||
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#define _POSIX_C_SOURCE 199309L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <GLES2/gl2.h>
|
#include <GLES2/gl2.h>
|
||||||
|
@ -5,6 +6,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wayland-server-protocol.h>
|
#include <wayland-server-protocol.h>
|
||||||
#include <wayland-util.h>
|
#include <wayland-util.h>
|
||||||
|
@ -18,6 +20,7 @@
|
||||||
#include "render/gles2.h"
|
#include "render/gles2.h"
|
||||||
#include "render/pixel_format.h"
|
#include "render/pixel_format.h"
|
||||||
#include "types/wlr_matrix.h"
|
#include "types/wlr_matrix.h"
|
||||||
|
#include "util/time.h"
|
||||||
|
|
||||||
#include "common_vert_src.h"
|
#include "common_vert_src.h"
|
||||||
#include "quad_frag_src.h"
|
#include "quad_frag_src.h"
|
||||||
|
@ -33,6 +36,7 @@ static const GLfloat verts[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct wlr_renderer_impl renderer_impl;
|
static const struct wlr_renderer_impl renderer_impl;
|
||||||
|
static const struct wlr_render_timer_impl render_timer_impl;
|
||||||
|
|
||||||
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer) {
|
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer) {
|
||||||
return wlr_renderer->impl == &renderer_impl;
|
return wlr_renderer->impl == &renderer_impl;
|
||||||
|
@ -52,6 +56,16 @@ static struct wlr_gles2_renderer *gles2_get_renderer_in_context(
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer) {
|
||||||
|
return timer->impl == &render_timer_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gles2_render_timer *gles2_get_render_timer(struct wlr_render_timer *wlr_timer) {
|
||||||
|
assert(wlr_render_timer_is_gles2(wlr_timer));
|
||||||
|
struct wlr_gles2_render_timer *timer = wl_container_of(wlr_timer, timer, base);
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
static void destroy_buffer(struct wlr_gles2_buffer *buffer) {
|
static void destroy_buffer(struct wlr_gles2_buffer *buffer) {
|
||||||
wl_list_remove(&buffer->link);
|
wl_list_remove(&buffer->link);
|
||||||
wlr_addon_finish(&buffer->addon);
|
wlr_addon_finish(&buffer->addon);
|
||||||
|
@ -543,18 +557,91 @@ static struct wlr_render_pass *gles2_begin_buffer_pass(struct wlr_renderer *wlr_
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_gles2_render_timer *timer = gles2_get_render_timer(options->timer);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &timer->cpu_start);
|
||||||
|
|
||||||
struct wlr_gles2_buffer *buffer = get_or_create_buffer(renderer, wlr_buffer);
|
struct wlr_gles2_buffer *buffer = get_or_create_buffer(renderer, wlr_buffer);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_gles2_render_pass *pass = begin_gles2_buffer_pass(buffer);
|
struct wlr_gles2_render_pass *pass = begin_gles2_buffer_pass(buffer, timer);
|
||||||
if (!pass) {
|
if (!pass) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &pass->base;
|
return &pass->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wlr_render_timer *gles2_render_timer_create(struct wlr_renderer *wlr_renderer) {
|
||||||
|
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
|
||||||
|
if (!renderer->exts.EXT_disjoint_timer_query) {
|
||||||
|
wlr_log(WLR_ERROR, "can't create timer, EXT_disjoint_timer_query not available");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gles2_render_timer *timer = calloc(1, sizeof(struct wlr_gles2_render_timer));
|
||||||
|
if (!timer) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
timer->base.impl = &render_timer_impl;
|
||||||
|
timer->renderer = renderer;
|
||||||
|
|
||||||
|
struct wlr_egl_context prev_ctx;
|
||||||
|
wlr_egl_save_context(&prev_ctx);
|
||||||
|
wlr_egl_make_current(renderer->egl);
|
||||||
|
renderer->procs.glGenQueriesEXT(1, &timer->id);
|
||||||
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
|
||||||
|
return (struct wlr_render_timer *)timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gles2_get_render_time(struct wlr_render_timer *wlr_timer) {
|
||||||
|
struct wlr_gles2_render_timer *timer = gles2_get_render_timer(wlr_timer);
|
||||||
|
struct wlr_gles2_renderer *renderer = timer->renderer;
|
||||||
|
|
||||||
|
struct wlr_egl_context prev_ctx;
|
||||||
|
wlr_egl_save_context(&prev_ctx);
|
||||||
|
wlr_egl_make_current(renderer->egl);
|
||||||
|
|
||||||
|
GLint64 disjoint;
|
||||||
|
renderer->procs.glGetInteger64vEXT(GL_GPU_DISJOINT_EXT, &disjoint);
|
||||||
|
if (disjoint) {
|
||||||
|
wlr_log(WLR_ERROR, "a disjoint operation occurred and the render timer is invalid");
|
||||||
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint available;
|
||||||
|
renderer->procs.glGetQueryObjectivEXT(timer->id,
|
||||||
|
GL_QUERY_RESULT_AVAILABLE_EXT, &available);
|
||||||
|
if (!available) {
|
||||||
|
wlr_log(WLR_ERROR, "timer was read too early, gpu isn't done!");
|
||||||
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint64 gl_render_end;
|
||||||
|
renderer->procs.glGetQueryObjectui64vEXT(timer->id, GL_QUERY_RESULT_EXT,
|
||||||
|
&gl_render_end);
|
||||||
|
|
||||||
|
int64_t cpu_nsec_total = timespec_to_nsec(&timer->cpu_end) - timespec_to_nsec(&timer->cpu_start);
|
||||||
|
|
||||||
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
return gl_render_end - timer->gl_cpu_end + cpu_nsec_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gles2_render_timer_destroy(struct wlr_render_timer *wlr_timer) {
|
||||||
|
struct wlr_gles2_render_timer *timer = (struct wlr_gles2_render_timer *)wlr_timer;
|
||||||
|
struct wlr_gles2_renderer *renderer = timer->renderer;
|
||||||
|
|
||||||
|
struct wlr_egl_context prev_ctx;
|
||||||
|
wlr_egl_save_context(&prev_ctx);
|
||||||
|
wlr_egl_make_current(renderer->egl);
|
||||||
|
renderer->procs.glDeleteQueriesEXT(1, &timer->id);
|
||||||
|
wlr_egl_restore_context(&prev_ctx);
|
||||||
|
free(timer);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct wlr_renderer_impl renderer_impl = {
|
static const struct wlr_renderer_impl renderer_impl = {
|
||||||
.destroy = gles2_destroy,
|
.destroy = gles2_destroy,
|
||||||
.bind_buffer = gles2_bind_buffer,
|
.bind_buffer = gles2_bind_buffer,
|
||||||
|
@ -573,6 +660,12 @@ static const struct wlr_renderer_impl renderer_impl = {
|
||||||
.get_render_buffer_caps = gles2_get_render_buffer_caps,
|
.get_render_buffer_caps = gles2_get_render_buffer_caps,
|
||||||
.texture_from_buffer = gles2_texture_from_buffer,
|
.texture_from_buffer = gles2_texture_from_buffer,
|
||||||
.begin_buffer_pass = gles2_begin_buffer_pass,
|
.begin_buffer_pass = gles2_begin_buffer_pass,
|
||||||
|
.render_timer_create = gles2_render_timer_create,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wlr_render_timer_impl render_timer_impl = {
|
||||||
|
.get_duration_ns = gles2_get_render_time,
|
||||||
|
.destroy = gles2_render_timer_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
|
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
|
||||||
|
@ -812,6 +905,16 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_gl_ext(exts_str, "GL_EXT_disjoint_timer_query")) {
|
||||||
|
renderer->exts.EXT_disjoint_timer_query = true;
|
||||||
|
load_gl_proc(&renderer->procs.glGenQueriesEXT, "glGenQueriesEXT");
|
||||||
|
load_gl_proc(&renderer->procs.glDeleteQueriesEXT, "glDeleteQueriesEXT");
|
||||||
|
load_gl_proc(&renderer->procs.glQueryCounterEXT, "glQueryCounterEXT");
|
||||||
|
load_gl_proc(&renderer->procs.glGetQueryObjectivEXT, "glGetQueryObjectivEXT");
|
||||||
|
load_gl_proc(&renderer->procs.glGetQueryObjectui64vEXT, "glGetQueryObjectui64vEXT");
|
||||||
|
load_gl_proc(&renderer->procs.glGetInteger64vEXT, "glGetInteger64vEXT");
|
||||||
|
}
|
||||||
|
|
||||||
if (renderer->exts.KHR_debug) {
|
if (renderer->exts.KHR_debug) {
|
||||||
glEnable(GL_DEBUG_OUTPUT_KHR);
|
glEnable(GL_DEBUG_OUTPUT_KHR);
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
|
||||||
|
|
Loading…
Reference in a new issue