forked from 12to11/12to11
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:
parent
1ab2633f35
commit
459de34ca7
8 changed files with 198 additions and 34 deletions
12
12to11.c
12
12to11.c
|
@ -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 ();
|
||||
|
|
14
compositor.h
14
compositor.h
|
@ -188,6 +188,8 @@ enum
|
|||
/* The render target always preserves previously drawn contents;
|
||||
IOW, target_age always returns 0. */
|
||||
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
47
egl.c
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
12
renderer.c
12
renderer.c
|
@ -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
|
||||
|
|
32
shaders.txt
32
shaders.txt
|
@ -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);
|
||||
}
|
||||
//==
|
||||
|
|
|
@ -1913,16 +1913,20 @@ SubcompositorUpdate (Subcompositor *subcompositor)
|
|||
-list->view->abs_y);
|
||||
}
|
||||
|
||||
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. */
|
||||
/* 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))
|
||||
{
|
||||
/* Translate the region into the subcompositor
|
||||
coordinate space. */
|
||||
pixman_region32_translate (&list->view->damage,
|
||||
|
|
53
surface.c
53
surface.c
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue