Implement various improvements to egl renderer

* 12to11.c (MakeColormap): Delete function.
(XLMain): Stop making colormap here.
* compositor.h (ImmediateRelease): New flag.
(struct _BufferFuncs): New field can_release_now.
(struct _State): New flag `BufferAlreadyReleased'.
* egl.c (struct _CompositeProgram): New field `invert_y'.
(EglCompileCompositeProgram): Get new uniform index.
(Composite): Apply InvertY.
(egl_render_funcs): Set ImmediateRelease flag.
(BufferFromDmaBuf): Set InvertY flag if set.
(UpdateTexture, UpdateShmBufferIncrementally): Set CanRelease
flag on SHM buffers.
(UpdateBuffer): Don't update if damage is empty.
(CanReleaseNow): New function.
(egl_buffer_funcs): Add CanReleaseNow.
* picture_renderer.c (MakeCheckWindow): New function.
(FindSupportedModifiers): Use a more similar window to look for
modifiers.
(CanReleaseNow): New function.
(picture_buffer_funcs): Add CanReleaseNow.
* renderer.c (RenderCanReleaseNow): New wrapper function.
(InstallRenderer): Create colormaps here, so the buffer init
function can get it.
* shaders.txt (Composite Rectangle Fragment Shader RGBA)
(Composite Rectangle Fragment Shader RGBX)
(Composite Rectangle Fragment Shader External): New uniform
`invert_y'.
(main): Use it.
* subcompositor.c (SubcompositorUpdate): Always update attached
buffer from damage, even if damage is empty.
* surface.c (TryEarlyRelease): New function.
(InternalCommit): Call it.  Also, do not call role
release_buffer hook if ImmediateRelease is specified by the
renderer.
(SavePendingState): Likewise, release buffers immediately if
possible.
This commit is contained in:
oldosfan 2022-09-24 01:53:15 +00:00
parent 1ab2633f35
commit 459de34ca7
8 changed files with 198 additions and 34 deletions

View file

@ -28,14 +28,6 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
/* Globals. */
Compositor compositor;
static Colormap
MakeColormap (void)
{
return XCreateColormap (compositor.display,
DefaultRootWindow (compositor.display),
compositor.visual, AllocNone);
}
static void
DetermineServerTime (void)
{
@ -112,10 +104,6 @@ XLMain (int argc, char **argv)
up. */
InitRenderers ();
/* Set up the colormap. Initializing renderers should also cause
the visual to be set. */
compositor.colormap = MakeColormap ();
XLInitRROutputs ();
XLInitCompositor ();
XLInitSurfaces ();

View file

@ -187,7 +187,9 @@ enum
{
/* The render target always preserves previously drawn contents;
IOW, target_age always returns 0. */
NeverAges = 1,
NeverAges = 1,
/* Buffers attached can always be immediately released. */
ImmediateRelease = 1 << 2,
};
struct _RenderFuncs
@ -319,6 +321,10 @@ struct _BufferFuncs
be performed on the buffer. */
void (*update_buffer_for_damage) (RenderBuffer, pixman_region32_t *);
/* Return whether or not the buffer contents can be released early,
by being copied to an offscreen buffer. */
Bool (*can_release_now) (RenderBuffer);
/* Called during renderer initialization. */
void (*init_buffer_funcs) (void);
};
@ -358,6 +364,7 @@ extern Bool RenderValidateShmParams (uint32_t, uint32_t, uint32_t, int32_t,
extern void RenderFreeShmBuffer (RenderBuffer);
extern void RenderFreeDmabufBuffer (RenderBuffer);
extern void RenderUpdateBufferForDamage (RenderBuffer, pixman_region32_t *);
extern Bool RenderCanReleaseNow (RenderBuffer);
/* Defined in run.c. */
@ -614,6 +621,10 @@ enum
PendingFrameCallbacks = (1 << 6),
PendingBufferScale = (1 << 7),
PendingAttachments = (1 << 8),
/* Flags here are stored in `pending' of the current state for
space reasons. */
BufferAlreadyReleased = (1 << 19),
};
struct _FrameCallback
@ -642,7 +653,8 @@ struct _State
/* The currently attached buffer. */
ExtBuffer *buffer;
/* What part of this state has been changed. */
/* What part of this state has been changed, and some more
flags. */
int pending;
/* The scale of this buffer. */

47
egl.c
View file

@ -33,6 +33,8 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include "linux-dmabuf-unstable-v1.h"
/* These are flags for the DrmFormats. */
enum
@ -108,7 +110,9 @@ struct _FormatInfo
enum
{
IsTextureGenerated = 1,
HasAlpha = 2,
HasAlpha = (1 << 2),
CanRelease = (1 << 3),
InvertY = (1 << 4),
};
struct _EglBuffer
@ -180,6 +184,9 @@ struct _CompositeProgram
/* The index of the scale uniform. */
GLuint scale;
/* The index of the invert_y uniform. */
GLuint invert_y;
};
/* All known SHM formats. */
@ -714,6 +721,8 @@ EglCompileCompositeProgram (CompositeProgram *program,
"texture");
program->scale = glGetUniformLocation (program->program,
"scale");
program->invert_y = glGetUniformLocation (program->program,
"invert_y");
/* Now delete the shaders. */
glDeleteShader (vertex);
@ -1210,6 +1219,7 @@ Composite (RenderBuffer buffer, RenderTarget target,
glUniform1i (program->texture, 0);
glUniform1f (program->scale, egl_buffer->scale);
glUniform1i (program->invert_y, egl_buffer->flags & InvertY);
glVertexAttribPointer (program->position, 2, GL_FLOAT,
GL_FALSE, 0, verts);
glVertexAttribPointer (program->texcoord, 2, GL_FLOAT,
@ -1282,7 +1292,7 @@ static RenderFuncs egl_render_funcs =
.reset_transform = ResetTransform,
.finish_render = FinishRender,
.target_age = TargetAge,
.flags = 0,
.flags = ImmediateRelease,
};
static DrmFormat *
@ -1384,6 +1394,11 @@ BufferFromDmaBuf (DmaBufAttributes *attributes, Bool *error)
&& attributes->modifier != DRM_FORMAT_MOD_INVALID)
goto error;
/* Set invert_y based on flags. */
if (attributes->flags
& ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
buffer->flags |= InvertY;
/* Otherwise, import the buffer now. */
attribs[i++] = EGL_WIDTH;
attribs[i++] = attributes->width;
@ -1836,6 +1851,10 @@ UpdateTexture (EglBuffer *buffer)
/* Unset the row length. */
glPixelStorei (GL_UNPACK_ROW_LENGTH_EXT, 0);
/* The buffer's been copied to the texture. It can now be
released. */
buffer->flags |= CanRelease;
}
/* Bind the target to nothing. */
@ -1909,6 +1928,10 @@ UpdateShmBufferIncrementally (EglBuffer *buffer, pixman_region32_t *damage)
/* Unbind from the texturing target. */
glBindTexture (target, 0);
/* The buffer's been copied to the texture. It can now be
released. */
buffer->flags |= CanRelease;
}
static void
@ -1949,7 +1972,7 @@ UpdateBuffer (RenderBuffer buffer, pixman_region32_t *damage)
if (egl_buffer->u.type == ShmBuffer)
UpdateTexture (egl_buffer);
}
else
else if (pixman_region32_not_empty (damage))
{
switch (egl_buffer->u.type)
{
@ -1990,6 +2013,23 @@ UpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage)
UpdateBuffer (buffer, damage);
}
static Bool
CanReleaseNow (RenderBuffer buffer)
{
EglBuffer *egl_buffer;
Bool rc;
egl_buffer = buffer.pointer;
/* Return if texture contents were copied. */
rc = (egl_buffer->flags & CanRelease) != 0;
/* Clear that flag now. */
egl_buffer->flags &= ~CanRelease;
return rc;
}
static BufferFuncs egl_buffer_funcs =
{
.get_drm_formats = GetDrmFormats,
@ -2002,6 +2042,7 @@ static BufferFuncs egl_buffer_funcs =
.free_shm_buffer = FreeShmBuffer,
.free_dmabuf_buffer = FreeDmabufBuffer,
.update_buffer_for_damage = UpdateBufferForDamage,
.can_release_now = CanReleaseNow,
.init_buffer_funcs = InitBufferFuncs,
};

View file

@ -418,17 +418,41 @@ FindSupportedFormats (void)
return supported;
}
static Window
MakeCheckWindow (void)
{
XSetWindowAttributes attrs;
unsigned long flags;
/* Make an override-redirect window to use as the icon surface. */
flags = (CWColormap | CWBorderPixel | CWEventMask
| CWOverrideRedirect);
attrs.colormap = compositor.colormap;
attrs.border_pixel = border_pixel;
attrs.event_mask = (ExposureMask | StructureNotifyMask);
attrs.override_redirect = 1;
return XCreateWindow (compositor.display,
DefaultRootWindow (compositor.display),
0, 0, 1, 1, 0, compositor.n_planes,
InputOutput, compositor.visual, flags,
&attrs);
}
static void
FindSupportedModifiers (int *pair_count_return)
{
Window root_window;
Window check_window;
xcb_dri3_get_supported_modifiers_cookie_t *cookies;
xcb_dri3_get_supported_modifiers_reply_t *reply;
int i, length, pair_count;
uint64_t *mods;
cookies = alloca (sizeof *cookies * ArrayElements (all_formats));
root_window = DefaultRootWindow (compositor.display);
/* Create a temporary window similar to ones surfaces will use to
determine which modifiers are supported. */
check_window = MakeCheckWindow ();
pair_count = 0;
for (i = 0; i < ArrayElements (all_formats); ++i)
@ -437,7 +461,7 @@ FindSupportedModifiers (int *pair_count_return)
{
cookies[i]
= xcb_dri3_get_supported_modifiers (compositor.conn,
root_window, all_formats[i].depth,
check_window, all_formats[i].depth,
all_formats[i].bits_per_pixel);
/* pair_count is the number of format-modifier pairs that
@ -447,6 +471,9 @@ FindSupportedModifiers (int *pair_count_return)
}
}
/* Delete the temporary window used to query for modifiers. */
XDestroyWindow (compositor.display, check_window);
for (i = 0; i < ArrayElements (all_formats); ++i)
{
if (!all_formats[i].format)
@ -1042,6 +1069,12 @@ InitBufferFuncs (void)
free (reply);
}
static Bool
CanReleaseNow (RenderBuffer buffer)
{
return False;
}
static BufferFuncs picture_buffer_funcs =
{
.get_drm_formats = GetDrmFormats,
@ -1053,6 +1086,7 @@ static BufferFuncs picture_buffer_funcs =
.validate_shm_params = ValidateShmParams,
.free_shm_buffer = FreeShmBuffer,
.free_dmabuf_buffer = FreeDmabufBuffer,
.can_release_now = CanReleaseNow,
.init_buffer_funcs = InitBufferFuncs,
};

View file

@ -233,6 +233,12 @@ RenderUpdateBufferForDamage (RenderBuffer buffer, pixman_region32_t *damage)
buffer_funcs.update_buffer_for_damage (buffer, damage);
}
Bool
RenderCanReleaseNow (RenderBuffer buffer)
{
return buffer_funcs.can_release_now (buffer);
}
void
RegisterStaticRenderer (const char *name,
RenderFuncs *render_funcs,
@ -261,6 +267,12 @@ InstallRenderer (Renderer *renderer)
/* If this returns false, then the renderer cannot be used. */
return False;
/* Next, initialize the colormap before init_buffer_funcs. */
compositor.colormap
= XCreateColormap (compositor.display,
DefaultRootWindow (compositor.display),
compositor.visual, AllocNone);
buffer_funcs.init_buffer_funcs ();
/* Finally, set the flags. The idea is that init_render_funcs

View file

@ -23,7 +23,7 @@ main (void)
void
main (void)
{
gl_FragColor = vec4 (0.0, 0.0, 0.0, 1.0);
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);
}
//==
@ -44,12 +44,20 @@ main (void)
precision mediump float;
uniform sampler2D texture;
uniform float scale;
uniform bool invert_y;
varying vec2 v_texcoord;
void
main (void)
{
gl_FragColor = texture2D (texture, v_texcoord / scale);
vec2 texcoord;
texcoord = v_texcoord / scale;
if (invert_y)
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
gl_FragColor = texture2D (texture, texcoord);
}
//==
@ -57,13 +65,21 @@ main (void)
precision mediump float;
uniform sampler2D texture;
uniform float scale;
uniform bool invert_y;
varying vec2 v_texcoord;
void
main (void)
{
vec2 texcoord;
texcoord = v_texcoord / scale;
if (invert_y)
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
gl_FragColor = vec4 (texture2D (texture,
v_texcoord / scale).rgb,
texcoord).rgb,
1.0);
}
//==
@ -74,11 +90,19 @@ main (void)
precision mediump float;
uniform samplerExternalOES texture;
uniform float scale;
uniform bool invert_y;
varying vec2 v_texcoord;
void
main (void)
{
gl_FragColor = texture2D (texture, v_texcoord / scale);
vec2 texcoord;
texcoord = v_texcoord / scale;
if (invert_y)
texcoord = vec2 (texcoord.x, 1.0 - texcoord.y);
gl_FragColor = texture2D (texture, texcoord);
}
//==

View file

@ -1913,16 +1913,20 @@ SubcompositorUpdate (Subcompositor *subcompositor)
-list->view->abs_y);
}
/* Update the attached buffer from the damage. This is only
required on some backends, where we have to upload data
from a shared memory buffer to the graphics hardware.
The update is performed even when there is no damage,
because the initial data might need to be uploaded.
However, the function does not perform partial updates
when the damage region is empty. */
buffer = XLRenderBufferFromBuffer (view->buffer);
RenderUpdateBufferForDamage (buffer, &list->view->damage);
if (pixman_region32_not_empty (&list->view->damage))
{
/* Update the attached buffer from the damage. This is
only required on some backends, where we have to
upload data from a shared memory buffer to the
graphics hardware. */
buffer = XLRenderBufferFromBuffer (view->buffer);
RenderUpdateBufferForDamage (buffer, &list->view->damage);
/* Translate the region into the subcompositor
coordinate space. */
pixman_region32_translate (&list->view->damage,

View file

@ -653,7 +653,7 @@ SavePendingState (Surface *surface)
&& (surface->cached_state.buffer
!= surface->current_state.buffer))
{
if (surface->role)
if (surface->role && !(renderer_flags & ImmediateRelease))
surface->role->funcs.release_buffer (surface, surface->role,
surface->cached_state.buffer);
else
@ -720,6 +720,41 @@ SavePendingState (Surface *surface)
surface->pending_state.pending = PendingNone;
}
static void
TryEarlyRelease (Surface *surface)
{
ExtBuffer *buffer;
RenderBuffer render_buffer;
/* The rendering backend may have copied the contents of, i.e., a
shared memory buffer to a backing texture. In that case buffers
can be released immediately after commit. Programs such as GTK
also rely on the compositor performing such an optimization, or
else they will constantly create new buffers to back their back
buffer contents. */
buffer = surface->current_state.buffer;
if (!buffer)
return;
/* Get the render buffer. */
render_buffer = XLRenderBufferFromBuffer (buffer);
/* Don't release immediately if not okay. */
if (!RenderCanReleaseNow (render_buffer))
return;
/* Release the buffer now. */
if (surface->role && !(renderer_flags & ImmediateRelease))
surface->role->funcs.release_buffer (surface, surface->role, buffer);
else
XLReleaseBuffer (buffer);
/* Set the flag saying that the buffer has been released. */
surface->current_state.pending |= BufferAlreadyReleased;
}
static void
InternalCommit (Surface *surface, State *pending)
{
@ -728,15 +763,22 @@ InternalCommit (Surface *surface, State *pending)
if (pending->pending & PendingBuffer)
{
if ((surface->current_state.buffer != pending->buffer)
/* The buffer may already released if its contents were
copied, i.e. uploaded to a texture, during updates. */
&& !(surface->current_state.pending & BufferAlreadyReleased)
&& surface->current_state.buffer)
{
if (surface->role)
if (surface->role && !(renderer_flags & ImmediateRelease))
surface->role->funcs.release_buffer (surface, surface->role,
surface->current_state.buffer);
else
XLReleaseBuffer (surface->current_state.buffer);
}
/* Clear this flag now, since the attached buffer has
changed. */
surface->current_state.pending &= ~BufferAlreadyReleased;
if (pending->buffer)
{
AttachBuffer (&surface->current_state,
@ -812,6 +854,8 @@ InternalCommit (Surface *surface, State *pending)
}
}
/* Run commit callbacks. This tells synchronous subsurfaces to
update. */
RunCommitCallbacks (surface);
if (surface->subsurfaces)
@ -829,6 +873,11 @@ InternalCommit (Surface *surface, State *pending)
surface->role->funcs.commit (surface, surface->role);
pending->pending = PendingNone;
/* Release the attached buffer if possible. The role may have
called SubcompositorUpdate, leading to the buffer contents being
copied. */
TryEarlyRelease (surface);
}
static void